v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
code-stub-assembler.h
Go to the documentation of this file.
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_CODEGEN_CODE_STUB_ASSEMBLER_H_
6#define V8_CODEGEN_CODE_STUB_ASSEMBLER_H_
7
8#include <functional>
9#include <optional>
10
11#include "src/base/macros.h"
14#include "src/codegen/tnode.h"
15#include "src/common/globals.h"
21#include "src/objects/bigint.h"
22#include "src/objects/cell.h"
26#include "src/objects/foreign.h"
28#include "src/objects/hole.h"
33#include "src/objects/objects.h"
34#include "src/objects/oddball.h"
36#include "src/objects/smi.h"
37#include "src/objects/string.h"
40#include "src/objects/tagged.h"
42#include "src/roots/roots.h"
43#include "torque-generated/exported-macros-assembler.h"
44
45#if V8_ENABLE_WEBASSEMBLY
47#endif // V8_ENABLE_WEBASSEMBLY
48
49namespace v8 {
50namespace internal {
51
53
54class CallInterfaceDescriptor;
55class CodeStubArguments;
56class CodeStubAssembler;
57class StatsCounter;
58class StubCache;
59
61
62// Provides JavaScript-specific "macro-assembler" functionality on top of the
63// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
64// it's possible to add JavaScript-specific useful CodeAssembler "macros"
65// without modifying files in the compiler directory (and requiring a review
66// from a compiler directory OWNER).
69 public TorqueGeneratedExportedMacrosAssembler {
70 public:
72
73 template <typename T>
74 using LazyNode = std::function<TNode<T>()>;
75
77
78 enum class AllocationFlag : uint8_t {
79 kNone = 0,
81 kPretenured = 1 << 1
82 };
83
89
91
92 TNode<UintPtrT> ArrayBufferMaxByteLength();
93
94 TNode<IntPtrT> ParameterToIntPtr(TNode<Smi> value) { return SmiUntag(value); }
97 return Signed(value);
98 }
100 return TaggedIndexToIntPtr(value);
101 }
102
104
105 TNode<Smi> ParameterToTagged(TNode<IntPtrT> value) { return SmiTag(value); }
106
107 template <typename TIndex>
109
110 bool ToParameterConstant(TNode<Smi> node, intptr_t* out) {
111 if (TryToIntPtrConstant(node, out)) {
112 return true;
113 }
114 return false;
115 }
116
117 bool ToParameterConstant(TNode<IntPtrT> node, intptr_t* out) {
118 intptr_t constant;
119 if (TryToIntPtrConstant(node, &constant)) {
120 *out = constant;
121 return true;
122 }
123 return false;
124 }
125
126#if defined(BINT_IS_SMI)
127 TNode<Smi> BIntToSmi(TNode<BInt> source) { return source; }
128 TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) {
129 return SmiToIntPtr(source);
130 }
131 TNode<BInt> SmiToBInt(TNode<Smi> source) { return source; }
132 TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) {
133 return SmiFromIntPtr(source);
134 }
135#elif defined(BINT_IS_INTPTR)
136 TNode<Smi> BIntToSmi(TNode<BInt> source) { return SmiFromIntPtr(source); }
137 TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) { return source; }
138 TNode<BInt> SmiToBInt(TNode<Smi> source) { return SmiToIntPtr(source); }
139 TNode<BInt> IntPtrToBInt(TNode<IntPtrT> source) { return source; }
140#else
141#error Unknown architecture.
142#endif
143
144 TNode<IntPtrT> TaggedIndexToIntPtr(TNode<TaggedIndex> value);
145 TNode<TaggedIndex> IntPtrToTaggedIndex(TNode<IntPtrT> value);
146 // TODO(v8:10047): Get rid of these conversions eventually.
147 TNode<Smi> TaggedIndexToSmi(TNode<TaggedIndex> value);
148 TNode<TaggedIndex> SmiToTaggedIndex(TNode<Smi> value);
149
150 // Pointer compression specific. Ensures that the upper 32 bits of a Smi
151 // contain the sign of a lower 32 bits so that the Smi can be directly used
152 // as an index in element offset computation.
153 TNode<Smi> NormalizeSmiIndex(TNode<Smi> smi_index);
154
156 GotoIf(TaggedIsNotSmi(value), fail);
157 return UncheckedCast<Smi>(value);
158 }
159
161 GotoIfNot(TaggedIsPositiveSmi(value), fail);
162 return UncheckedCast<Smi>(value);
163 }
164
165 TNode<String> TaggedToDirectString(TNode<Object> value, Label* fail);
166
168 GotoIf(TaggedIsSmi(value), fail);
169 return UncheckedCast<HeapObject>(value);
170 }
171
173 return UncheckedCast<Uint16T>(Int32Constant(t));
174 }
175
177 Label* fail) {
178 GotoIfNot(IsJSDataView(heap_object), fail);
179 return CAST(heap_object);
180 }
181
183 Label* fail) {
184 GotoIfNot(IsJSProxy(heap_object), fail);
185 return CAST(heap_object);
186 }
187
189 TNode<HeapObject> heap_object, Label* fail) {
190 GotoIfNot(IsJSStringIterator(heap_object), fail);
191 return CAST(heap_object);
192 }
193
195 Label* fail) {
196 GotoIfNot(IsCallable(heap_object), fail);
197 return CAST(heap_object);
198 }
199
201 GotoIfNot(IsString(heap_object), fail);
202 return CAST(heap_object);
203 }
204
206 Label* fail) {
207 GotoIfNot(IsConstructor(heap_object), fail);
208 return CAST(heap_object);
209 }
210
212 TNode<HeapObject> heap_object, Label* fail) {
213 GotoIfNot(IsJSFunctionWithPrototypeSlot(heap_object), fail);
214 return CAST(heap_object);
215 }
216
217 template <typename T>
219 return lazy();
220 }
221
222#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
223 TNode<Smi> OpName(TNode<Smi> a, TNode<Smi> b) { return SmiOpName(a, b); } \
224 TNode<IntPtrT> OpName(TNode<IntPtrT> a, TNode<IntPtrT> b) { \
225 return IntPtrOpName(a, b); \
226 } \
227 TNode<UintPtrT> OpName(TNode<UintPtrT> a, TNode<UintPtrT> b) { \
228 return Unsigned(IntPtrOpName(Signed(a), Signed(b))); \
229 } \
230 TNode<RawPtrT> OpName(TNode<RawPtrT> a, TNode<RawPtrT> b) { \
231 return ReinterpretCast<RawPtrT>(IntPtrOpName( \
232 ReinterpretCast<IntPtrT>(a), ReinterpretCast<IntPtrT>(b))); \
233 }
234 // TODO(v8:9708): Define BInt operations once all uses are ported.
235 PARAMETER_BINOP(IntPtrOrSmiAdd, IntPtrAdd, SmiAdd)
236 PARAMETER_BINOP(IntPtrOrSmiSub, IntPtrSub, SmiSub)
237#undef PARAMETER_BINOP
238
239#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
240 TNode<BoolT> OpName(TNode<Smi> a, TNode<Smi> b) { return SmiOpName(a, b); } \
241 TNode<BoolT> OpName(TNode<IntPtrT> a, TNode<IntPtrT> b) { \
242 return IntPtrOpName(a, b); \
243 } \
244 /* IntPtrXXX comparisons shouldn't be used with unsigned types, use */ \
245 /* UintPtrXXX operations explicitly instead. */ \
246 TNode<BoolT> OpName(TNode<UintPtrT> a, TNode<UintPtrT> b) { UNREACHABLE(); } \
247 TNode<BoolT> OpName(TNode<RawPtrT> a, TNode<RawPtrT> b) { UNREACHABLE(); }
248 // TODO(v8:9708): Define BInt operations once all uses are ported.
249 PARAMETER_BINOP(IntPtrOrSmiEqual, WordEqual, SmiEqual)
250 PARAMETER_BINOP(IntPtrOrSmiNotEqual, WordNotEqual, SmiNotEqual)
251 PARAMETER_BINOP(IntPtrOrSmiLessThan, IntPtrLessThan, SmiLessThan)
252 PARAMETER_BINOP(IntPtrOrSmiLessThanOrEqual, IntPtrLessThanOrEqual,
253 SmiLessThanOrEqual)
254 PARAMETER_BINOP(IntPtrOrSmiGreaterThan, IntPtrGreaterThan, SmiGreaterThan)
255#undef PARAMETER_BINOP
256
257#define PARAMETER_BINOP(OpName, UintPtrOpName, SmiOpName) \
258 TNode<BoolT> OpName(TNode<Smi> a, TNode<Smi> b) { return SmiOpName(a, b); } \
259 TNode<BoolT> OpName(TNode<IntPtrT> a, TNode<IntPtrT> b) { \
260 return UintPtrOpName(Unsigned(a), Unsigned(b)); \
261 } \
262 TNode<BoolT> OpName(TNode<UintPtrT> a, TNode<UintPtrT> b) { \
263 return UintPtrOpName(a, b); \
264 } \
265 TNode<BoolT> OpName(TNode<RawPtrT> a, TNode<RawPtrT> b) { \
266 return UintPtrOpName(a, b); \
267 }
268 // TODO(v8:9708): Define BInt operations once all uses are ported.
269 PARAMETER_BINOP(UintPtrOrSmiEqual, WordEqual, SmiEqual)
270 PARAMETER_BINOP(UintPtrOrSmiNotEqual, WordNotEqual, SmiNotEqual)
271 PARAMETER_BINOP(UintPtrOrSmiLessThan, UintPtrLessThan, SmiBelow)
272 PARAMETER_BINOP(UintPtrOrSmiLessThanOrEqual, UintPtrLessThanOrEqual,
273 SmiBelowOrEqual)
274 PARAMETER_BINOP(UintPtrOrSmiGreaterThan, UintPtrGreaterThan, SmiAbove)
275 PARAMETER_BINOP(UintPtrOrSmiGreaterThanOrEqual, UintPtrGreaterThanOrEqual,
276 SmiAboveOrEqual)
277#undef PARAMETER_BINOP
278
279 uintptr_t ConstexprUintPtrShl(uintptr_t a, int32_t b) { return a << b; }
280 uintptr_t ConstexprUintPtrShr(uintptr_t a, int32_t b) { return a >> b; }
281 intptr_t ConstexprIntPtrAdd(intptr_t a, intptr_t b) { return a + b; }
282 uintptr_t ConstexprUintPtrAdd(uintptr_t a, uintptr_t b) { return a + b; }
283 intptr_t ConstexprWordNot(intptr_t a) { return ~a; }
284 uintptr_t ConstexprWordNot(uintptr_t a) { return ~a; }
285
288 return Word32Equal(ReinterpretCast<Word32T>(a),
289 ReinterpretCast<Word32T>(b));
290 } else {
291 return WordEqual(ReinterpretCast<WordT>(a), ReinterpretCast<WordT>(b));
292 }
293 }
294
296 return Word32BinaryNot(TaggedEqual(a, b));
297 }
298
299 TNode<Smi> NoContextConstant();
300
302 // This node makes the graph platform-specific. To make sure that the graph
303 // structure is still platform independent, UniqueIntPtrConstants are used
304 // here.
305#if V8_TARGET_ARCH_ARM64
306 return UniqueIntPtrConstant(16);
307#else
308 return UniqueIntPtrConstant(kSystemPointerSize);
309#endif
310 }
311
312#define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \
313 TNode<RemoveTagged< \
314 decltype(std::declval<ReadOnlyRoots>().rootAccessorName())>::type> \
315 name##Constant();
317#undef HEAP_CONSTANT_ACCESSOR
318
319#define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \
320 TNode<RemoveTagged<decltype(std::declval<Heap>().rootAccessorName())>::type> \
321 name##Constant();
323#undef HEAP_CONSTANT_ACCESSOR
324
325#define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \
326 TNode<BoolT> Is##name(TNode<Object> value); \
327 TNode<BoolT> IsNot##name(TNode<Object> value);
329#undef HEAP_CONSTANT_TEST
330
331 TNode<BInt> BIntConstant(int value);
332
333 template <typename TIndex>
335
336 bool TryGetIntPtrOrSmiConstantValue(TNode<Smi> maybe_constant, int* value);
337 bool TryGetIntPtrOrSmiConstantValue(TNode<IntPtrT> maybe_constant,
338 int* value);
339
340 TNode<IntPtrT> PopulationCountFallback(TNode<UintPtrT> value);
341 TNode<Int64T> PopulationCount64(TNode<Word64T> value);
342 TNode<Int32T> PopulationCount32(TNode<Word32T> value);
343 TNode<Int64T> CountTrailingZeros64(TNode<Word64T> value);
344 TNode<Int32T> CountTrailingZeros32(TNode<Word32T> value);
345 TNode<Int64T> CountLeadingZeros64(TNode<Word64T> value);
346 TNode<Int32T> CountLeadingZeros32(TNode<Word32T> value);
347
348 // Round the 32bits payload of the provided word up to the next power of two.
349 TNode<IntPtrT> IntPtrRoundUpToPowerOfTwo32(TNode<IntPtrT> value);
350 // Select the maximum of the two provided IntPtr values.
351 TNode<IntPtrT> IntPtrMax(TNode<IntPtrT> left, TNode<IntPtrT> right);
352 // Select the minimum of the two provided IntPtr values.
353 TNode<IntPtrT> IntPtrMin(TNode<IntPtrT> left, TNode<IntPtrT> right);
354 TNode<UintPtrT> UintPtrMin(TNode<UintPtrT> left, TNode<UintPtrT> right);
355
356 // Float64 operations.
357 TNode<BoolT> Float64AlmostEqual(TNode<Float64T> x, TNode<Float64T> y,
358 double max_relative_error = 0.0000001);
359 TNode<Float64T> Float64Ceil(TNode<Float64T> x);
360 TNode<Float64T> Float64Floor(TNode<Float64T> x);
361 TNode<Float64T> Float64Round(TNode<Float64T> x);
362 TNode<Float64T> Float64RoundToEven(TNode<Float64T> x);
363 TNode<Float64T> Float64Trunc(TNode<Float64T> x);
364 // Select the minimum of the two provided Number values.
365 TNode<Number> NumberMax(TNode<Number> left, TNode<Number> right);
366 // Select the minimum of the two provided Number values.
367 TNode<Number> NumberMin(TNode<Number> left, TNode<Number> right);
368
369 // Returns true iff the given value fits into smi range and is >= 0.
370 TNode<BoolT> IsValidPositiveSmi(TNode<IntPtrT> value);
371
372 // Tag an IntPtr as a Smi value.
373 TNode<Smi> SmiTag(TNode<IntPtrT> value);
374 // Untag a Smi value as an IntPtr.
375 TNode<IntPtrT> SmiUntag(TNode<Smi> value);
376 // Untag a positive Smi value as an IntPtr, it's slightly better than
377 // SmiUntag() because it doesn't have to do sign extension.
378 TNode<IntPtrT> PositiveSmiUntag(TNode<Smi> value);
379
380 // Smi conversions.
381 TNode<Float64T> SmiToFloat64(TNode<Smi> value);
382 TNode<Smi> SmiFromIntPtr(TNode<IntPtrT> value) { return SmiTag(value); }
383 TNode<Smi> SmiFromInt32(TNode<Int32T> value);
384 TNode<Smi> SmiFromUint32(TNode<Uint32T> value);
385 TNode<IntPtrT> SmiToIntPtr(TNode<Smi> value) { return SmiUntag(value); }
386 TNode<Int32T> SmiToInt32(TNode<Smi> value);
387 TNode<Uint32T> PositiveSmiToUint32(TNode<Smi> value);
388
389 // Smi operations.
390#define SMI_ARITHMETIC_BINOP(SmiOpName, IntPtrOpName, Int32OpName) \
391 TNode<Smi> SmiOpName(TNode<Smi> a, TNode<Smi> b) { \
392 if (SmiValuesAre32Bits()) { \
393 return BitcastWordToTaggedSigned( \
394 IntPtrOpName(BitcastTaggedToWordForTagAndSmiBits(a), \
395 BitcastTaggedToWordForTagAndSmiBits(b))); \
396 } else { \
397 DCHECK(SmiValuesAre31Bits()); \
398 return BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Int32OpName( \
399 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), \
400 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(b))))); \
401 } \
402 }
403 SMI_ARITHMETIC_BINOP(SmiAdd, IntPtrAdd, Int32Add)
404 SMI_ARITHMETIC_BINOP(SmiSub, IntPtrSub, Int32Sub)
405 SMI_ARITHMETIC_BINOP(SmiAnd, WordAnd, Word32And)
406 SMI_ARITHMETIC_BINOP(SmiOr, WordOr, Word32Or)
407 SMI_ARITHMETIC_BINOP(SmiXor, WordXor, Word32Xor)
408#undef SMI_ARITHMETIC_BINOP
409
410 TNode<IntPtrT> TryIntPtrAdd(TNode<IntPtrT> a, TNode<IntPtrT> b,
411 Label* if_overflow);
412 TNode<IntPtrT> TryIntPtrSub(TNode<IntPtrT> a, TNode<IntPtrT> b,
413 Label* if_overflow);
414 TNode<IntPtrT> TryIntPtrMul(TNode<IntPtrT> a, TNode<IntPtrT> b,
415 Label* if_overflow);
416 TNode<IntPtrT> TryIntPtrDiv(TNode<IntPtrT> a, TNode<IntPtrT> b,
417 Label* if_div_zero);
418 TNode<IntPtrT> TryIntPtrMod(TNode<IntPtrT> a, TNode<IntPtrT> b,
419 Label* if_div_zero);
420 TNode<Int32T> TryInt32Mul(TNode<Int32T> a, TNode<Int32T> b,
421 Label* if_overflow);
422 TNode<Smi> TrySmiAdd(TNode<Smi> a, TNode<Smi> b, Label* if_overflow);
423 TNode<Smi> TrySmiSub(TNode<Smi> a, TNode<Smi> b, Label* if_overflow);
424 TNode<Smi> TrySmiAbs(TNode<Smi> a, Label* if_overflow);
425
427 if (SmiValuesAre32Bits()) {
428 return BitcastWordToTaggedSigned(
429 WordShl(BitcastTaggedToWordForTagAndSmiBits(a), shift));
430 } else {
432 return BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Word32Shl(
433 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)),
434 Int32Constant(shift))));
435 }
436 }
437
439 TNode<Smi> result = UnsignedSmiShl(a, shift);
440 // Smi shift have different result to int32 shift when the inputs are not
441 // strictly limited. The CSA_DCHECK is to ensure valid inputs.
443 this, TaggedEqual(result, BitwiseOp(SmiToInt32(a), Int32Constant(shift),
444 Operation::kShiftLeft)));
445 return result;
446 }
447
450 if (kTaggedSize == kInt64Size) {
451 result = BitcastWordToTaggedSigned(
452 WordAnd(WordShr(BitcastTaggedToWordForTagAndSmiBits(a), shift),
453 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1))));
454 } else {
455 // For pointer compressed Smis, we want to make sure that we truncate to
456 // int32 before shifting, to avoid the values of the top 32-bits from
457 // leaking into the sign bit of the smi.
458 result = BitcastWordToTaggedSigned(WordAnd(
459 ChangeInt32ToIntPtr(Word32Shr(
460 TruncateWordToInt32(BitcastTaggedToWordForTagAndSmiBits(a)),
461 shift)),
462 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1))));
463 }
464 // Smi shift have different result to int32 shift when the inputs are not
465 // strictly limited. The CSA_DCHECK is to ensure valid inputs.
467 this, TaggedEqual(result, BitwiseOp(SmiToInt32(a), Int32Constant(shift),
468 Operation::kShiftRightLogical)));
469 return result;
470 }
471
473 // The number of shift bits is |shift % 64| for 64-bits value and |shift %
474 // 32| for 32-bits value. The DCHECK is to ensure valid inputs.
475 DCHECK_LT(shift, 32);
476 if (kTaggedSize == kInt64Size) {
477 return BitcastWordToTaggedSigned(
478 WordAnd(WordSar(BitcastTaggedToWordForTagAndSmiBits(a), shift),
479 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1))));
480 } else {
481 // For pointer compressed Smis, we want to make sure that we truncate to
482 // int32 before shifting, to avoid the values of the top 32-bits from
483 // changing the sign bit of the smi.
484 return BitcastWordToTaggedSigned(WordAnd(
485 ChangeInt32ToIntPtr(Word32Sar(
486 TruncateWordToInt32(BitcastTaggedToWordForTagAndSmiBits(a)),
487 shift)),
488 BitcastTaggedToWordForTagAndSmiBits(SmiConstant(-1))));
489 }
490 }
491
492 TNode<Smi> WordOrSmiShr(TNode<Smi> a, int shift) { return SmiShr(a, shift); }
493
495 return WordShr(a, shift);
496 }
497
498#define SMI_COMPARISON_OP(SmiOpName, IntPtrOpName, Int32OpName) \
499 TNode<BoolT> SmiOpName(TNode<Smi> a, TNode<Smi> b) { \
500 if (kTaggedSize == kInt64Size) { \
501 return IntPtrOpName(BitcastTaggedToWordForTagAndSmiBits(a), \
502 BitcastTaggedToWordForTagAndSmiBits(b)); \
503 } else { \
504 DCHECK_EQ(kTaggedSize, kInt32Size); \
505 DCHECK(SmiValuesAre31Bits()); \
506 return Int32OpName( \
507 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(a)), \
508 TruncateIntPtrToInt32(BitcastTaggedToWordForTagAndSmiBits(b))); \
509 } \
510 }
511 SMI_COMPARISON_OP(SmiEqual, WordEqual, Word32Equal)
512 SMI_COMPARISON_OP(SmiNotEqual, WordNotEqual, Word32NotEqual)
513 SMI_COMPARISON_OP(SmiAbove, UintPtrGreaterThan, Uint32GreaterThan)
514 SMI_COMPARISON_OP(SmiAboveOrEqual, UintPtrGreaterThanOrEqual,
515 Uint32GreaterThanOrEqual)
516 SMI_COMPARISON_OP(SmiBelow, UintPtrLessThan, Uint32LessThan)
517 SMI_COMPARISON_OP(SmiBelowOrEqual, UintPtrLessThanOrEqual,
518 Uint32LessThanOrEqual)
519 SMI_COMPARISON_OP(SmiLessThan, IntPtrLessThan, Int32LessThan)
520 SMI_COMPARISON_OP(SmiLessThanOrEqual, IntPtrLessThanOrEqual,
521 Int32LessThanOrEqual)
522 SMI_COMPARISON_OP(SmiGreaterThan, IntPtrGreaterThan, Int32GreaterThan)
523 SMI_COMPARISON_OP(SmiGreaterThanOrEqual, IntPtrGreaterThanOrEqual,
524 Int32GreaterThanOrEqual)
525#undef SMI_COMPARISON_OP
526 TNode<Smi> SmiMax(TNode<Smi> a, TNode<Smi> b);
527 TNode<Smi> SmiMin(TNode<Smi> a, TNode<Smi> b);
528 // Computes a % b for Smi inputs a and b; result is not necessarily a Smi.
530 // Computes a * b for Smi inputs a and b; result is not necessarily a Smi.
532 // Tries to compute dividend / divisor for Smi inputs; branching to bailout
533 // if the division needs to be performed as a floating point operation.
534 TNode<Smi> TrySmiDiv(TNode<Smi> dividend, TNode<Smi> divisor, Label* bailout);
535
536 // Compares two Smis a and b as if they were converted to strings and then
537 // compared lexicographically. Returns:
538 // -1 iff x < y.
539 // 0 iff x == y.
540 // 1 iff x > y.
541 TNode<Smi> SmiLexicographicCompare(TNode<Smi> x, TNode<Smi> y);
542
543 // Returns Smi::zero() if no CoverageInfo exists.
544 TNode<Object> GetCoverageInfo(TNode<SharedFunctionInfo> sfi);
545
546#ifdef BINT_IS_SMI
547#define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName) \
548 TNode<BoolT> BIntOpName(TNode<BInt> a, TNode<BInt> b) { \
549 return SmiOpName(a, b); \
550 }
551#else
552#define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName) \
553 TNode<BoolT> BIntOpName(TNode<BInt> a, TNode<BInt> b) { \
554 return IntPtrOpName(a, b); \
555 }
556#endif
557 BINT_COMPARISON_OP(BIntEqual, SmiEqual, WordEqual)
558 BINT_COMPARISON_OP(BIntNotEqual, SmiNotEqual, WordNotEqual)
559 BINT_COMPARISON_OP(BIntAbove, SmiAbove, UintPtrGreaterThan)
560 BINT_COMPARISON_OP(BIntAboveOrEqual, SmiAboveOrEqual,
561 UintPtrGreaterThanOrEqual)
562 BINT_COMPARISON_OP(BIntBelow, SmiBelow, UintPtrLessThan)
563 BINT_COMPARISON_OP(BIntLessThan, SmiLessThan, IntPtrLessThan)
564 BINT_COMPARISON_OP(BIntLessThanOrEqual, SmiLessThanOrEqual,
565 IntPtrLessThanOrEqual)
566 BINT_COMPARISON_OP(BIntGreaterThan, SmiGreaterThan, IntPtrGreaterThan)
567 BINT_COMPARISON_OP(BIntGreaterThanOrEqual, SmiGreaterThanOrEqual,
568 IntPtrGreaterThanOrEqual)
569#undef BINT_COMPARISON_OP
570
571 // Smi | HeapNumber operations.
572 TNode<Number> NumberInc(TNode<Number> value);
573 TNode<Number> NumberDec(TNode<Number> value);
576 void GotoIfNotNumber(TNode<Object> value, Label* is_not_number);
577 void GotoIfNumber(TNode<Object> value, Label* is_number);
579
580 // BigInt operations.
581 void GotoIfLargeBigInt(TNode<BigInt> bigint, Label* true_label);
582
583 TNode<Word32T> NormalizeShift32OperandIfNecessary(TNode<Word32T> right32);
584 TNode<Number> BitwiseOp(TNode<Word32T> left32, TNode<Word32T> right32,
585 Operation bitwise_op);
586 TNode<Number> BitwiseSmiOp(TNode<Smi> left32, TNode<Smi> right32,
587 Operation bitwise_op);
588
589 // Align the value to kObjectAlignment8GbHeap if V8_COMPRESS_POINTERS_8GB is
590 // defined.
591 TNode<IntPtrT> AlignToAllocationAlignment(TNode<IntPtrT> value);
592
593 // Allocate an object of the given size.
594 TNode<HeapObject> AllocateInNewSpace(
595 TNode<IntPtrT> size, AllocationFlags flags = AllocationFlag::kNone);
596 TNode<HeapObject> AllocateInNewSpace(
597 int size, AllocationFlags flags = AllocationFlag::kNone);
598 TNode<HeapObject> Allocate(TNode<IntPtrT> size,
599 AllocationFlags flags = AllocationFlag::kNone);
600
601 TNode<HeapObject> Allocate(int size,
602 AllocationFlags flags = AllocationFlag::kNone);
603
604 TNode<BoolT> IsRegularHeapObjectSize(TNode<IntPtrT> size);
605
606 using BranchGenerator = std::function<void(Label*, Label*)>;
607 template <typename T>
608 using NodeGenerator = std::function<TNode<T>()>;
609 using ExtraNode = std::pair<TNode<Object>, const char*>;
610
611 void Dcheck(const BranchGenerator& branch, const char* message,
612 const char* file, int line,
613 std::initializer_list<ExtraNode> extra_nodes = {},
614 const SourceLocation& loc = SourceLocation::Current());
615 void Dcheck(const NodeGenerator<BoolT>& condition_body, const char* message,
616 const char* file, int line,
617 std::initializer_list<ExtraNode> extra_nodes = {},
618 const SourceLocation& loc = SourceLocation::Current());
619 void Dcheck(TNode<Word32T> condition_node, const char* message,
620 const char* file, int line,
621 std::initializer_list<ExtraNode> extra_nodes = {},
622 const SourceLocation& loc = SourceLocation::Current());
623 void Check(const BranchGenerator& branch, const char* message,
624 const char* file, int line,
625 std::initializer_list<ExtraNode> extra_nodes = {},
626 const SourceLocation& loc = SourceLocation::Current());
627 void Check(const NodeGenerator<BoolT>& condition_body, const char* message,
628 const char* file, int line,
629 std::initializer_list<ExtraNode> extra_nodes = {},
630 const SourceLocation& loc = SourceLocation::Current());
631 void Check(TNode<Word32T> condition_node, const char* message,
632 const char* file, int line,
633 std::initializer_list<ExtraNode> extra_nodes = {},
634 const SourceLocation& loc = SourceLocation::Current());
635 void FailAssert(const char* message,
636 const std::vector<FileAndLine>& files_and_lines,
637 std::initializer_list<ExtraNode> extra_nodes = {},
638 const SourceLocation& loc = SourceLocation::Current());
639
640 void FastCheck(TNode<BoolT> condition);
641
642 TNode<RawPtrT> LoadCodeInstructionStart(TNode<Code> code,
643 CodeEntrypointTag tag);
644 TNode<BoolT> IsMarkedForDeoptimization(TNode<Code> code);
645
646 void DCheckReceiver(ConvertReceiverMode mode, TNode<JSAny> receiver);
647
648 // The following Call wrappers call an object according to the semantics that
649 // one finds in the ECMAScript spec, operating on a Callable (e.g. a
650 // JSFunction or proxy) rather than an InstructionStream object.
651 template <typename TCallable, class... TArgs>
652 inline TNode<JSAny> Call(TNode<Context> context, TNode<TCallable> callable,
653 ConvertReceiverMode mode, TNode<JSAny> receiver,
654 TArgs... args);
655 template <typename TCallable, class... TArgs>
656 inline TNode<JSAny> Call(TNode<Context> context, TNode<TCallable> callable,
657 TNode<JSReceiver> receiver, TArgs... args);
658 template <typename TCallable, class... TArgs>
659 inline TNode<JSAny> Call(TNode<Context> context, TNode<TCallable> callable,
660 TNode<JSAny> receiver, TArgs... args);
661 template <class... TArgs>
662 inline TNode<JSAny> CallFunction(TNode<Context> context,
663 TNode<JSFunction> callable,
664 ConvertReceiverMode mode,
665 TNode<JSAny> receiver, TArgs... args);
666 template <class... TArgs>
667 inline TNode<JSAny> CallFunction(TNode<Context> context,
668 TNode<JSFunction> callable,
669 TNode<JSReceiver> receiver, TArgs... args);
670 template <class... TArgs>
671 inline TNode<JSAny> CallFunction(TNode<Context> context,
672 TNode<JSFunction> callable,
673 TNode<JSAny> receiver, TArgs... args);
674
676 TNode<Int32T> argc, TNode<Object> data,
678
680 TNode<Int32T> argc, TNode<Object> data,
682 TNode<Object> value);
683
684 TNode<Object> CallRuntimeNewArray(TNode<Context> context,
687 TNode<Object> allocation_site);
688
689 void TailCallRuntimeNewArray(TNode<Context> context, TNode<JSAny> receiver,
691 TNode<Object> allocation_site);
692
693 template <class... TArgs>
695 TNode<JSReceiver> target,
697 TArgs... args) {
698 return CAST(ConstructJS(Builtin::kConstruct, context, target, new_target,
700 }
701 template <class... TArgs>
704 return ConstructWithTarget(context, new_target, new_target, args...);
705 }
706
707 template <typename T>
709 const NodeGenerator<T>& false_body,
710 BranchHint branch_hint = BranchHint::kNone) {
711 TVARIABLE(T, value);
712 Label vtrue(this), vfalse(this), end(this);
713 Branch(condition, &vtrue, &vfalse, branch_hint);
714
715 BIND(&vtrue);
716 {
717 value = true_body();
718 Goto(&end);
719 }
720 BIND(&vfalse);
721 {
722 value = false_body();
723 Goto(&end);
724 }
725
726 BIND(&end);
727 return value.value();
728 }
729
730 template <class A>
732 TNode<A> false_value) {
733 return Select<A>(
734 condition, [=] { return true_value; }, [=] { return false_value; });
735 }
736
737 TNode<Int32T> SelectInt32Constant(TNode<BoolT> condition, int true_value,
738 int false_value);
739 TNode<IntPtrT> SelectIntPtrConstant(TNode<BoolT> condition, int true_value,
740 int false_value);
741 TNode<Boolean> SelectBooleanConstant(TNode<BoolT> condition);
742 TNode<Smi> SelectSmiConstant(TNode<BoolT> condition, Tagged<Smi> true_value,
743 Tagged<Smi> false_value);
745 Tagged<Smi> false_value) {
746 return SelectSmiConstant(condition, Smi::FromInt(true_value), false_value);
747 }
749 int false_value) {
750 return SelectSmiConstant(condition, true_value, Smi::FromInt(false_value));
751 }
753 int false_value) {
754 return SelectSmiConstant(condition, Smi::FromInt(true_value),
755 Smi::FromInt(false_value));
756 }
757
759 DCHECK_EQ(strlen(single_char), 1);
760 DCHECK_LE(single_char[0], String::kMaxOneByteCharCode);
761 return HeapConstantNoHole(
762 isolate()->factory()->LookupSingleCharacterStringFromCode(
763 single_char[0]));
764 }
765
767 TNode<Float16RawBitsT> TruncateFloat64ToFloat16(TNode<Float64T> value);
768
769 TNode<Int32T> TruncateWordToInt32(TNode<WordT> value);
770 TNode<Int32T> TruncateIntPtrToInt32(TNode<IntPtrT> value);
771 TNode<Word32T> TruncateWord64ToWord32(TNode<Word64T> value);
772
773 // Check a value for smi-ness
774 TNode<BoolT> TaggedIsSmi(TNode<MaybeObject> a);
775 TNode<BoolT> TaggedIsNotSmi(TNode<MaybeObject> a);
776
777 // Check that the value is a non-negative smi.
778 TNode<BoolT> TaggedIsPositiveSmi(TNode<Object> a);
779 // Check that a word has a word-aligned address.
780 TNode<BoolT> WordIsAligned(TNode<WordT> word, size_t alignment);
781 TNode<BoolT> WordIsPowerOfTwo(TNode<IntPtrT> value);
782
783 // Check if lower_limit <= value <= higher_limit.
784 template <typename U>
785 TNode<BoolT> IsInRange(TNode<Word32T> value, U lower_limit, U higher_limit) {
786 DCHECK_LE(lower_limit, higher_limit);
787 static_assert(sizeof(U) <= kInt32Size);
788 if (lower_limit == 0) {
789 return Uint32LessThanOrEqual(value, Int32Constant(higher_limit));
790 }
791 return Uint32LessThanOrEqual(Int32Sub(value, Int32Constant(lower_limit)),
792 Int32Constant(higher_limit - lower_limit));
793 }
794
796 TNode<UintPtrT> higher_limit) {
797 CSA_DCHECK(this, UintPtrLessThanOrEqual(lower_limit, higher_limit));
798 return UintPtrLessThanOrEqual(UintPtrSub(value, lower_limit),
799 UintPtrSub(higher_limit, lower_limit));
800 }
801
802 TNode<BoolT> IsInRange(TNode<WordT> value, intptr_t lower_limit,
803 intptr_t higher_limit) {
804 DCHECK_LE(lower_limit, higher_limit);
805 if (lower_limit == 0) {
806 return UintPtrLessThanOrEqual(value, IntPtrConstant(higher_limit));
807 }
808 return UintPtrLessThanOrEqual(IntPtrSub(value, IntPtrConstant(lower_limit)),
809 IntPtrConstant(higher_limit - lower_limit));
810 }
811
812#if DEBUG
813 void Bind(Label* label, AssemblerDebugInfo debug_info);
814#endif // DEBUG
815 void Bind(Label* label);
816
817 template <class... T>
819 TNode<T>*... phis) {
820 CodeAssembler::Bind(label, phis...);
821 }
822
824 Label* if_false) {
825 Branch(SmiEqual(a, b), if_true, if_false);
826 }
827
829 Label* if_false) {
830 Branch(SmiLessThan(a, b), if_true, if_false);
831 }
832
834 Label* if_false) {
835 Branch(SmiLessThanOrEqual(a, b), if_true, if_false);
836 }
837
839 Label* if_false) {
840 Branch(Float64Equal(value, value), if_false, if_true);
841 }
842
843 // Branches to {if_true} if ToBoolean applied to {value} yields true,
844 // otherwise goes to {if_false}.
845 void BranchIfToBooleanIsTrue(TNode<Object> value, Label* if_true,
846 Label* if_false);
847
848 // Branches to {if_false} if ToBoolean applied to {value} yields false,
849 // otherwise goes to {if_true}.
851 Label* if_true) {
852 BranchIfToBooleanIsTrue(value, if_true, if_false);
853 }
854
855 void BranchIfJSReceiver(TNode<Object> object, Label* if_true,
856 Label* if_false);
857
858 // Branches to {if_true} when --force-slow-path flag has been passed.
859 // It's used for testing to ensure that slow path implementation behave
860 // equivalent to corresponding fast paths (where applicable).
861 //
862 // Works only with V8_ENABLE_FORCE_SLOW_PATH compile time flag. Nop otherwise.
863 void GotoIfForceSlowPath(Label* if_true);
864
865 //
866 // Sandboxed pointer related functionality.
867 //
868
869 // Load a sandboxed pointer value from an object.
871 int offset) {
872 return LoadSandboxedPointerFromObject(object, IntPtrConstant(offset));
873 }
874
875 TNode<RawPtrT> LoadSandboxedPointerFromObject(TNode<HeapObject> object,
877
878 // Stored a sandboxed pointer value to an object.
880 TNode<RawPtrT> pointer) {
881 StoreSandboxedPointerToObject(object, IntPtrConstant(offset), pointer);
882 }
883
884 void StoreSandboxedPointerToObject(TNode<HeapObject> object,
886 TNode<RawPtrT> pointer);
887
888 TNode<RawPtrT> EmptyBackingStoreBufferConstant();
889
890 //
891 // Bounded size related functionality.
892 //
893
894 // Load a bounded size value from an object.
896 int offset) {
897 return LoadBoundedSizeFromObject(object, IntPtrConstant(offset));
898 }
899
900 TNode<UintPtrT> LoadBoundedSizeFromObject(TNode<HeapObject> object,
902
903 // Stored a bounded size value to an object.
905 TNode<UintPtrT> value) {
906 StoreBoundedSizeToObject(object, IntPtrConstant(offset), value);
907 }
908
909 void StoreBoundedSizeToObject(TNode<HeapObject> object, TNode<IntPtrT> offset,
910 TNode<UintPtrT> value);
911 //
912 // ExternalPointerT-related functionality.
913 //
914
916
917 // Load an external pointer value from an object.
919 TNode<HeapObject> object, int offset, ExternalPointerTagRange tag_range) {
920 return LoadExternalPointerFromObject(object, IntPtrConstant(offset),
921 tag_range);
922 }
923
924 TNode<RawPtrT> LoadExternalPointerFromObject(
926 ExternalPointerTagRange tag_range);
927
928 // Store external object pointer to object.
930 TNode<RawPtrT> pointer,
931 ExternalPointerTag tag) {
932 StoreExternalPointerToObject(object, IntPtrConstant(offset), pointer, tag);
933 }
934
935 void StoreExternalPointerToObject(TNode<HeapObject> object,
937 TNode<RawPtrT> pointer,
939
940 // Load a trusted pointer field.
941 // When the sandbox is enabled, these are indirect pointers using the trusted
942 // pointer table. Otherwise they are regular tagged fields.
943 TNode<TrustedObject> LoadTrustedPointerFromObject(TNode<HeapObject> object,
944 int offset,
946
947 // Load a code pointer field.
948 // These are special versions of trusted pointers that, when the sandbox is
949 // enabled, reference code objects through the code pointer table.
950 TNode<Code> LoadCodePointerFromObject(TNode<HeapObject> object, int offset);
951
952#ifdef V8_ENABLE_SANDBOX
953 // Load an indirect pointer field.
954 TNode<TrustedObject> LoadIndirectPointerFromObject(TNode<HeapObject> object,
955 int offset,
957
958 // Determines whether the given indirect pointer handle is a trusted pointer
959 // handle or a code pointer handle.
960 TNode<BoolT> IsTrustedPointerHandle(TNode<IndirectPointerHandleT> handle);
961
962 // Retrieve the heap object referenced by the given indirect pointer handle,
963 // which can either be a trusted pointer handle or a code pointer handle.
964 TNode<TrustedObject> ResolveIndirectPointerHandle(
966
967 // Retrieve the Code object referenced by the given trusted pointer handle.
968 TNode<Code> ResolveCodePointerHandle(TNode<IndirectPointerHandleT> handle);
969
970 // Retrieve the heap object referenced by the given trusted pointer handle.
971 TNode<TrustedObject> ResolveTrustedPointerHandle(
973
974 // Helper function to compute the offset into the code pointer table from a
975 // code pointer handle.
976 TNode<UintPtrT> ComputeCodePointerTableEntryOffset(
978
979 // Load the pointer to a Code's entrypoint via code pointer.
980 // Only available when the sandbox is enabled as it requires the code pointer
981 // table.
982 TNode<RawPtrT> LoadCodeEntrypointViaCodePointerField(TNode<HeapObject> object,
983 int offset,
984 CodeEntrypointTag tag) {
985 return LoadCodeEntrypointViaCodePointerField(object, IntPtrConstant(offset),
986 tag);
987 }
988 TNode<RawPtrT> LoadCodeEntrypointViaCodePointerField(TNode<HeapObject> object,
989 TNode<IntPtrT> offset,
990 CodeEntrypointTag tag);
991 TNode<RawPtrT> LoadCodeEntryFromIndirectPointerHandle(
992 TNode<IndirectPointerHandleT> handle, CodeEntrypointTag tag);
993
994 // Load the value of Code pointer table corresponding to
995 // IsolateGroup::current()->code_pointer_table_.
996 // Only available when the sandbox is enabled.
997 TNode<RawPtrT> LoadCodePointerTableBase();
998
999#endif
1000
1001 TNode<JSDispatchHandleT> InvalidDispatchHandleConstant();
1002
1005 return CAST(LoadProtectedPointerFromObject(
1006 object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag))));
1007 }
1009 int offset) {
1010 return CAST(LoadProtectedPointerFromObject(
1011 object, IntPtrConstant(offset - kHeapObjectTag)));
1012 }
1013
1015 ExternalPointerTag tag) {
1016 return LoadExternalPointerFromObject(object, Foreign::kForeignAddressOffset,
1017 tag);
1018 }
1019
1022 return LoadExternalPointerFromObject(
1023 object, FunctionTemplateInfo::kMaybeRedirectedCallbackOffset,
1025 }
1026
1028 return LoadExternalPointerFromObject(object,
1029 offsetof(ExternalString, resource_),
1031 }
1032
1034 TNode<ExternalString> object) {
1035 // This is only valid for ExternalStrings where the resource data
1036 // pointer is cached (i.e. no uncached external strings).
1037 CSA_DCHECK(this, Word32NotEqual(
1038 Word32And(LoadInstanceType(object),
1039 Int32Constant(kUncachedExternalStringMask)),
1040 Int32Constant(kUncachedExternalStringTag)));
1041 return LoadExternalPointerFromObject(
1042 object, offsetof(ExternalString, resource_data_),
1044 }
1045
1047 return ReinterpretCast<RawPtr<Uint64T>>(
1048 ExternalConstant(ExternalReference::address_of_log10_offset_table()));
1049 }
1050
1051#if V8_ENABLE_WEBASSEMBLY
1052 // Returns WasmTrustedInstanceData|Smi.
1053 TNode<Object> LoadInstanceDataFromWasmImportData(
1054 TNode<WasmImportData> import_data) {
1055 return LoadProtectedPointerField(
1056 import_data, WasmImportData::kProtectedInstanceDataOffset);
1057 }
1058
1059 // Returns WasmImportData or WasmTrustedInstanceData.
1060 TNode<Union<WasmImportData, WasmTrustedInstanceData>>
1061 LoadImplicitArgFromWasmInternalFunction(TNode<WasmInternalFunction> object) {
1062 TNode<Object> obj = LoadProtectedPointerField(
1063 object, WasmInternalFunction::kProtectedImplicitArgOffset);
1064 CSA_DCHECK(this, TaggedIsNotSmi(obj));
1065 TNode<HeapObject> implicit_arg = CAST(obj);
1066 CSA_DCHECK(
1067 this,
1068 Word32Or(HasInstanceType(implicit_arg, WASM_TRUSTED_INSTANCE_DATA_TYPE),
1069 HasInstanceType(implicit_arg, WASM_IMPORT_DATA_TYPE)));
1070 return CAST(implicit_arg);
1071 }
1072
1073 TNode<WasmInternalFunction> LoadWasmInternalFunctionFromFuncRef(
1074 TNode<WasmFuncRef> func_ref) {
1075 return CAST(LoadTrustedPointerFromObject(
1076 func_ref, WasmFuncRef::kTrustedInternalOffset,
1077 kWasmInternalFunctionIndirectPointerTag));
1078 }
1079
1080 TNode<WasmInternalFunction> LoadWasmInternalFunctionFromFunctionData(
1081 TNode<WasmFunctionData> data) {
1082 return CAST(LoadProtectedPointerField(
1083 data, WasmFunctionData::kProtectedInternalOffset));
1084 }
1085
1086 TNode<WasmTrustedInstanceData>
1087 LoadWasmTrustedInstanceDataFromWasmExportedFunctionData(
1088 TNode<WasmExportedFunctionData> data) {
1089 return CAST(LoadProtectedPointerField(
1090 data, WasmExportedFunctionData::kProtectedInstanceDataOffset));
1091 }
1092
1093 // Dynamically allocates a buffer of size `size` in C++ on the cppgc heap.
1094 TNode<RawPtrT> AllocateBuffer(TNode<IntPtrT> size);
1095#endif // V8_ENABLE_WEBASSEMBLY
1096
1098 TNode<JSTypedArray> holder) {
1099 return LoadSandboxedPointerFromObject(holder,
1100 JSTypedArray::kExternalPointerOffset);
1101 }
1102
1104 TNode<RawPtrT> value) {
1105 StoreSandboxedPointerToObject(holder, JSTypedArray::kExternalPointerOffset,
1106 value);
1107 }
1108
1111 auto zero_constant =
1112#ifdef V8_COMPRESS_POINTERS
1113 Int32Constant(0);
1114#else // !V8_COMPRESS_POINTERS
1115 IntPtrConstant(0);
1116#endif // !V8_COMPRESS_POINTERS
1117 StoreObjectFieldNoWriteBarrier(
1118 holder, JSAPIObjectWithEmbedderSlots::kCppHeapWrappableOffset,
1119 zero_constant);
1120 }
1121
1122 // Load value from current parent frame by given offset in bytes.
1123 TNode<Object> LoadFromParentFrame(int offset);
1124
1125 // Load an object pointer from a buffer that isn't in the heap.
1127 return LoadFullTagged(buffer, IntPtrConstant(offset));
1128 }
1129 template <typename T>
1131 return UncheckedCast<T>(
1132 Load(MachineTypeOf<T>::value, buffer, IntPtrConstant(offset)));
1133 }
1135 return LoadBufferData<RawPtrT>(buffer, offset);
1136 }
1138 return CAST(LoadBufferObject(buffer, offset));
1139 }
1141 return LoadBufferData<IntPtrT>(buffer, offset);
1142 }
1144 TNode<Uint64T> LoadUint64Ptr(TNode<RawPtrT> ptr, TNode<IntPtrT> index);
1145
1146 // Load a field from an object on the heap.
1147 template <typename T>
1149 MachineType machine_type = MachineTypeOf<T>::value;
1150 TNode<IntPtrT> raw_offset = IntPtrConstant(offset - kHeapObjectTag);
1151 if constexpr (is_subtype_v<T, UntaggedT>) {
1152 // Load an untagged field.
1153 return UncheckedCast<T>(LoadFromObject(machine_type, object, raw_offset));
1154 } else {
1155 static_assert(is_subtype_v<T, Object>);
1156 // Load a tagged field.
1157 if constexpr (is_subtype_v<T, Map>) {
1158 // If this is potentially loading a map, we need to check the offset.
1159 if (offset == HeapObject::kMapOffset) {
1160 machine_type = MachineType::MapInHeader();
1161 }
1162 }
1163 return CAST(LoadFromObject(machine_type, object, raw_offset));
1164 }
1165 }
1167 return UncheckedCast<Object>(
1168 LoadFromObject(MachineType::AnyTagged(), object,
1169 IntPtrConstant(offset - kHeapObjectTag)));
1170 }
1173 return UncheckedCast<Object>(
1174 LoadFromObject(MachineType::AnyTagged(), object,
1175 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag))));
1176 }
1177 template <class T>
1179 requires std::is_convertible_v<TNode<T>, TNode<UntaggedT>>
1180 {
1181 return UncheckedCast<T>(
1182 LoadFromObject(MachineTypeOf<T>::value, object,
1183 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag))));
1184 }
1185 // Load a positive SMI field and untag it.
1186 TNode<IntPtrT> LoadAndUntagPositiveSmiObjectField(TNode<HeapObject> object,
1187 int offset);
1188 // Load a SMI field, untag it, and convert to Word32.
1189 TNode<Int32T> LoadAndUntagToWord32ObjectField(TNode<HeapObject> object,
1190 int offset);
1191
1193 int offset) {
1194 return UncheckedCast<MaybeObject>(LoadObjectField(object, offset));
1195 }
1196
1198 return LoadObjectField(map,
1199 Map::kConstructorOrBackPointerOrNativeContextOffset);
1200 }
1201
1203 return Load<Simd128T>(ptr);
1204 }
1205
1206 // Reference is the CSA-equivalent of a Torque reference value, representing
1207 // an inner pointer into a HeapObject.
1208 //
1209 // The object can be a HeapObject or an all-zero bitpattern. The latter is
1210 // used for off-heap data, in which case the offset holds the actual address
1211 // and the data must be untagged (i.e. accessed via the Load-/StoreReference
1212 // overloads for TNode<UntaggedT>-convertible types below).
1213 //
1214 // TODO(gsps): Remove in favor of flattened {Load,Store}Reference interface.
1215 struct Reference {
1218
1219 std::tuple<TNode<Object>, TNode<IntPtrT>> Flatten() const {
1220 return std::make_tuple(object, offset);
1221 }
1222 };
1223
1224 template <class T>
1226 requires std::is_convertible_v<TNode<T>, TNode<Object>>
1227 {
1228 if (IsMapOffsetConstant(reference.offset)) {
1229 TNode<Map> map = LoadMap(CAST(reference.object));
1230 DCHECK((std::is_base_of<T, Map>::value));
1231 return ReinterpretCast<T>(map);
1232 }
1233
1235 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag));
1236 CSA_DCHECK(this, TaggedIsNotSmi(reference.object));
1237 return CAST(
1238 LoadFromObject(MachineTypeOf<T>::value, reference.object, offset));
1239 }
1240 template <class T>
1242 requires(std::is_convertible_v<TNode<T>, TNode<UntaggedT>> ||
1243 is_maybe_weak_v<T>)
1244 {
1245 DCHECK(!IsMapOffsetConstant(reference.offset));
1247 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag));
1248 return UncheckedCast<T>(
1249 LoadFromObject(MachineTypeOf<T>::value, reference.object, offset));
1250 }
1251 template <class T>
1252 void StoreReference(Reference reference, TNode<T> value)
1253 requires(std::is_convertible_v<TNode<T>, TNode<MaybeObject>>)
1254 {
1255 if (IsMapOffsetConstant(reference.offset)) {
1256 DCHECK((std::is_base_of<T, Map>::value));
1257 return StoreMap(CAST(reference.object), ReinterpretCast<Map>(value));
1258 }
1260 StoreToObjectWriteBarrier write_barrier = StoreToObjectWriteBarrier::kFull;
1261 if (std::is_same_v<T, Smi>) {
1262 write_barrier = StoreToObjectWriteBarrier::kNone;
1263 } else if (std::is_same_v<T, Map>) {
1264 write_barrier = StoreToObjectWriteBarrier::kMap;
1265 }
1267 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag));
1268 CSA_DCHECK(this, TaggedIsNotSmi(reference.object));
1269 StoreToObject(rep, reference.object, offset, value, write_barrier);
1270 }
1271 template <class T>
1272 void StoreReference(Reference reference, TNode<T> value)
1273 requires std::is_convertible_v<TNode<T>, TNode<UntaggedT>>
1274 {
1275 DCHECK(!IsMapOffsetConstant(reference.offset));
1277 IntPtrSub(reference.offset, IntPtrConstant(kHeapObjectTag));
1278 StoreToObject(MachineRepresentationOf<T>::value, reference.object, offset,
1279 value, StoreToObjectWriteBarrier::kNone);
1280 }
1281
1284 return ReinterpretCast<RawPtrT>(
1285 IntPtrAdd(BitcastTaggedToWord(object),
1286 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag))));
1287 }
1288
1289 // Load the floating point value of a HeapNumber.
1290 TNode<Float64T> LoadHeapNumberValue(TNode<HeapObject> object);
1291 TNode<Int32T> LoadHeapInt32Value(TNode<HeapObject> object);
1292 void StoreHeapInt32Value(TNode<HeapObject> object, TNode<Int32T> value);
1293 // Load the Map of an HeapObject.
1294 TNode<Map> LoadMap(TNode<HeapObject> object);
1295 // Load the instance type of an HeapObject.
1296 TNode<Uint16T> LoadInstanceType(TNode<HeapObject> object);
1297 // Compare the instance the type of the object against the provided one.
1298 TNode<BoolT> HasInstanceType(TNode<HeapObject> object, InstanceType type);
1299 TNode<BoolT> DoesntHaveInstanceType(TNode<HeapObject> object,
1300 InstanceType type);
1301 TNode<BoolT> TaggedDoesntHaveInstanceType(TNode<HeapObject> any_tagged,
1302 InstanceType type);
1303
1305 void GotoIfMapHasSlowProperties(TNode<Map> map, Label* if_slow);
1306
1307 // Load the properties backing store of a JSReceiver.
1308 TNode<HeapObject> LoadSlowProperties(TNode<JSReceiver> object);
1309 TNode<HeapObject> LoadFastProperties(TNode<JSReceiver> object,
1310 bool skip_empty_check = false);
1311 // Load the elements backing store of a JSObject.
1313 return LoadJSObjectElements(object);
1314 }
1315 // Load the length of a JSArray instance.
1316 TNode<Object> LoadJSArgumentsObjectLength(TNode<Context> context,
1318 // Load the length of a fast JSArray instance. Returns a positive Smi.
1319 TNode<Smi> LoadFastJSArrayLength(TNode<JSArray> array);
1320 // Load the length of a fixed array base instance.
1321 TNode<Smi> LoadFixedArrayBaseLength(TNode<FixedArrayBase> array);
1322 template <typename Array>
1324 return LoadObjectField<Smi>(array, offsetof(Array, length_));
1325 }
1326 // Load the length of a fixed array base instance.
1327 TNode<IntPtrT> LoadAndUntagFixedArrayBaseLength(TNode<FixedArrayBase> array);
1328 TNode<Uint32T> LoadAndUntagFixedArrayBaseLengthAsUint32(
1329 TNode<FixedArrayBase> array);
1330 // Load the length of a WeakFixedArray.
1331 TNode<Smi> LoadWeakFixedArrayLength(TNode<WeakFixedArray> array);
1332 TNode<IntPtrT> LoadAndUntagWeakFixedArrayLength(TNode<WeakFixedArray> array);
1333 TNode<Uint32T> LoadAndUntagWeakFixedArrayLengthAsUint32(
1334 TNode<WeakFixedArray> array);
1335 // Load the length of a BytecodeArray.
1336 TNode<Uint32T> LoadAndUntagBytecodeArrayLength(TNode<BytecodeArray> array);
1337 // Load the number of descriptors in DescriptorArray.
1338 TNode<Int32T> LoadNumberOfDescriptors(TNode<DescriptorArray> array);
1339 // Load the number of own descriptors of a map.
1340 TNode<Int32T> LoadNumberOfOwnDescriptors(TNode<Map> map);
1341 // Load the bit field of a Map.
1342 TNode<Int32T> LoadMapBitField(TNode<Map> map);
1343 // Load bit field 2 of a map.
1344 TNode<Int32T> LoadMapBitField2(TNode<Map> map);
1345 // Load bit field 3 of a map.
1346 TNode<Uint32T> LoadMapBitField3(TNode<Map> map);
1347 // Load the instance type of a map.
1348 TNode<Uint16T> LoadMapInstanceType(TNode<Map> map);
1349 // Load the ElementsKind of a map.
1350 TNode<Int32T> LoadMapElementsKind(TNode<Map> map);
1351 TNode<Int32T> LoadElementsKind(TNode<HeapObject> object);
1352 // Load the instance descriptors of a map.
1353 TNode<DescriptorArray> LoadMapDescriptors(TNode<Map> map);
1354 // Load the prototype of a map.
1355 TNode<JSPrototype> LoadMapPrototype(TNode<Map> map);
1356 // Load the instance size of a Map.
1357 TNode<IntPtrT> LoadMapInstanceSizeInWords(TNode<Map> map);
1358 // Load the inobject properties start of a Map (valid only for JSObjects).
1359 TNode<IntPtrT> LoadMapInobjectPropertiesStartInWords(TNode<Map> map);
1360 // Load the constructor function index of a Map (only for primitive maps).
1361 TNode<IntPtrT> LoadMapConstructorFunctionIndex(TNode<Map> map);
1362 // Load the constructor of a Map (equivalent to Map::GetConstructor()).
1363 TNode<Object> LoadMapConstructor(TNode<Map> map);
1364 // Load the EnumLength of a Map.
1365 TNode<Uint32T> LoadMapEnumLength(TNode<Map> map);
1366 // Load the back-pointer of a Map.
1367 TNode<Object> LoadMapBackPointer(TNode<Map> map);
1368 // Compute the used instance size in words of a map.
1369 TNode<IntPtrT> MapUsedInstanceSizeInWords(TNode<Map> map);
1370 // Compute the number of used inobject properties on a map.
1371 TNode<IntPtrT> MapUsedInObjectProperties(TNode<Map> map);
1372 // Checks that |map| has only simple properties, returns bitfield3.
1373 TNode<Uint32T> EnsureOnlyHasSimpleProperties(TNode<Map> map,
1374 TNode<Int32T> instance_type,
1375 Label* bailout);
1376 // Load the identity hash of a JSRececiver.
1377 TNode<Uint32T> LoadJSReceiverIdentityHash(TNode<JSReceiver> receiver,
1378 Label* if_no_hash = nullptr);
1379
1380 // This is only used on a newly allocated PropertyArray which
1381 // doesn't have an existing hash.
1382 void InitializePropertyArrayLength(TNode<PropertyArray> property_array,
1383 TNode<IntPtrT> length);
1384
1385 // Check if the map is set for slow properties.
1386 TNode<BoolT> IsDictionaryMap(TNode<Map> map);
1387
1388 // Load the Name::hash() value of a name as an uint32 value.
1389 // If {if_hash_not_computed} label is specified then it also checks if
1390 // hash is actually computed.
1391 TNode<Uint32T> LoadNameHash(TNode<Name> name,
1392 Label* if_hash_not_computed = nullptr);
1393 TNode<Uint32T> LoadNameHashAssumeComputed(TNode<Name> name);
1394
1395 // Load the Name::RawHash() value of a name as an uint32 value. Follows
1396 // through the forwarding table.
1397 TNode<Uint32T> LoadNameRawHash(TNode<Name> name);
1398
1399 // Load length field of a String object as Smi value.
1400 TNode<Smi> LoadStringLengthAsSmi(TNode<String> string);
1401 // Load length field of a String object as intptr_t value.
1402 TNode<IntPtrT> LoadStringLengthAsWord(TNode<String> string);
1403 // Load length field of a String object as uint32_t value.
1404 TNode<Uint32T> LoadStringLengthAsWord32(TNode<String> string);
1405 // Load value field of a JSPrimitiveWrapper object.
1406 TNode<Object> LoadJSPrimitiveWrapperValue(TNode<JSPrimitiveWrapper> object);
1407
1408 // Figures out whether the value of maybe_object is:
1409 // - a SMI (jump to "if_smi", "extracted" will be the SMI value)
1410 // - a cleared weak reference (jump to "if_cleared", "extracted" will be
1411 // untouched)
1412 // - a weak reference (jump to "if_weak", "extracted" will be the object
1413 // pointed to)
1414 // - a strong reference (jump to "if_strong", "extracted" will be the object
1415 // pointed to)
1416 void DispatchMaybeObject(TNode<MaybeObject> maybe_object, Label* if_smi,
1417 Label* if_cleared, Label* if_weak, Label* if_strong,
1418 TVariable<Object>* extracted);
1419 // See Tagged<MaybeObject> for semantics of these functions.
1420 TNode<BoolT> IsStrong(TNode<MaybeObject> value);
1422 TNode<HeapObject> GetHeapObjectIfStrong(TNode<MaybeObject> value,
1423 Label* if_not_strong);
1424 TNode<HeapObject> GetHeapObjectIfStrong(TNode<HeapObjectReference> value,
1425 Label* if_not_strong);
1426
1427 TNode<BoolT> IsWeakOrCleared(TNode<MaybeObject> value);
1428 TNode<BoolT> IsWeakOrCleared(TNode<HeapObjectReference> value);
1429 TNode<BoolT> IsCleared(TNode<MaybeObject> value);
1431 return Word32BinaryNot(IsCleared(value));
1432 }
1433
1434 // Removes the weak bit + asserts it was set.
1435 TNode<HeapObject> GetHeapObjectAssumeWeak(TNode<MaybeObject> value);
1436
1437 TNode<HeapObject> GetHeapObjectAssumeWeak(TNode<MaybeObject> value,
1438 Label* if_cleared);
1439
1440 // Checks if |maybe_object| is a weak reference to given |heap_object|.
1441 // Works for both any tagged |maybe_object| values.
1442 TNode<BoolT> IsWeakReferenceTo(TNode<MaybeObject> maybe_object,
1443 TNode<HeapObject> heap_object);
1444 // Returns true if the |object| is a HeapObject and |maybe_object| is a weak
1445 // reference to |object|.
1446 // The |maybe_object| must not be a Smi.
1447 TNode<BoolT> IsWeakReferenceToObject(TNode<MaybeObject> maybe_object,
1448 TNode<Object> object);
1449
1452
1453 void FixedArrayBoundsCheck(TNode<FixedArrayBase> array, TNode<Smi> index,
1454 int additional_offset);
1456 int additional_offset) {
1457 FixedArrayBoundsCheck(UncheckedCast<FixedArrayBase>(array), index,
1458 additional_offset);
1459 }
1460
1461 void FixedArrayBoundsCheck(TNode<FixedArrayBase> array, TNode<IntPtrT> index,
1462 int additional_offset);
1464 int additional_offset) {
1465 FixedArrayBoundsCheck(UncheckedCast<FixedArrayBase>(array), index,
1466 additional_offset);
1467 }
1468
1470 int additional_offset) {
1471 FixedArrayBoundsCheck(array, Signed(index), additional_offset);
1472 }
1473
1474 void FixedArrayBoundsCheck(TNode<FixedArrayBase> array,
1475 TNode<TaggedIndex> index, int additional_offset);
1477 int additional_offset) {
1478 FixedArrayBoundsCheck(UncheckedCast<FixedArrayBase>(array), index,
1479 additional_offset);
1480 }
1481
1482 // Array is any array-like type that has a fixed header followed by
1483 // tagged elements.
1484 template <typename Array>
1486
1487 // Array is any array-like type that has a fixed header followed by
1488 // tagged elements.
1489 template <typename Array, typename TIndex, typename TValue = MaybeObject>
1490 TNode<TValue> LoadArrayElement(TNode<Array> array, int array_header_size,
1491 TNode<TIndex> index,
1492 int additional_offset = 0);
1493 template <typename Array, typename TIndex>
1495 TNode<Array> array, TNode<TIndex> index, int additional_offset = 0) {
1496 return LoadArrayElement<Array, TIndex, typename Array::Shape::ElementT>(
1497 array, OFFSET_OF_DATA_START(Array), index, additional_offset);
1498 }
1499
1500 template <typename TIndex>
1501 TNode<Object> LoadFixedArrayElement(
1502 TNode<FixedArray> object, TNode<TIndex> index, int additional_offset = 0,
1503 CheckBounds check_bounds = CheckBounds::kAlways);
1504
1505 // This doesn't emit a bounds-check. As part of the security-performance
1506 // tradeoff, only use it if it is performance critical.
1508 TNode<IntPtrT> index,
1509 int additional_offset = 0) {
1510 return LoadFixedArrayElement(object, index, additional_offset,
1511 CheckBounds::kDebugOnly);
1512 }
1513
1515 int additional_offset = 0) {
1516 return LoadFixedArrayElement(object, IntPtrConstant(index),
1517 additional_offset);
1518 }
1519 // This doesn't emit a bounds-check. As part of the security-performance
1520 // tradeoff, only use it if it is performance critical.
1522 int additional_offset = 0) {
1523 return LoadFixedArrayElement(object, IntPtrConstant(index),
1524 additional_offset, CheckBounds::kDebugOnly);
1525 }
1526
1527 TNode<Object> LoadPropertyArrayElement(TNode<PropertyArray> object,
1528 TNode<IntPtrT> index);
1529 TNode<IntPtrT> LoadPropertyArrayLength(TNode<PropertyArray> object);
1530
1531 // Load an element from an array and untag it and return it as Word32.
1532 // Array is any array-like type that has a fixed header followed by
1533 // tagged elements.
1534 template <typename Array>
1535 TNode<Int32T> LoadAndUntagToWord32ArrayElement(TNode<Array> array,
1536 int array_header_size,
1537 TNode<IntPtrT> index,
1538 int additional_offset = 0);
1539
1540 // Load an array element from a FixedArray, untag it and return it as Word32.
1541 TNode<Int32T> LoadAndUntagToWord32FixedArrayElement(
1542 TNode<FixedArray> object, TNode<IntPtrT> index,
1543 int additional_offset = 0);
1544
1545 // Load an array element from a WeakFixedArray.
1546 TNode<MaybeObject> LoadWeakFixedArrayElement(TNode<WeakFixedArray> object,
1547 TNode<IntPtrT> index,
1548 int additional_offset = 0);
1549
1550 // Load an array element from a FixedDoubleArray.
1551 TNode<Float64T> LoadFixedDoubleArrayElement(
1553 Label* if_hole = nullptr,
1554 MachineType machine_type = MachineType::Float64());
1555#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1556 TNode<Float64T> LoadFixedDoubleArrayElementWithUndefinedCheck(
1557 TNode<FixedDoubleArray> object, TNode<IntPtrT> index, Label* if_undefined,
1558 Label* if_hole, MachineType machine_type = MachineType::Float64());
1559#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1560
1561 // Load an array element from a FixedArray, FixedDoubleArray or a
1562 // NumberDictionary (depending on the |elements_kind|) and return
1563 // it as a tagged value. Assumes that the |index| passed a length
1564 // check before. Bails out to |if_accessor| if the element that
1565 // was found is an accessor, or to |if_hole| if the element at
1566 // the given |index| is not found in |elements|.
1567 TNode<Object> LoadFixedArrayBaseElementAsTagged(
1568 TNode<FixedArrayBase> elements, TNode<IntPtrT> index,
1569 TNode<Int32T> elements_kind, Label* if_accessor, Label* if_hole);
1570
1571 // Load a feedback slot from a FeedbackVector.
1572 template <typename TIndex>
1573 TNode<MaybeObject> LoadFeedbackVectorSlot(
1574 TNode<FeedbackVector> feedback_vector, TNode<TIndex> slot,
1575 int additional_offset = 0);
1576
1577 TNode<IntPtrT> LoadFeedbackVectorLength(TNode<FeedbackVector>);
1578 TNode<Float64T> LoadDoubleWithHoleCheck(TNode<FixedDoubleArray> array,
1579 TNode<IntPtrT> index,
1580 Label* if_hole = nullptr);
1581
1583#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1585 TNode<BoolT> IsDoubleUndefined(TNode<Float64T> value);
1586#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1587 // Load Float64 value by |base| + |offset| address. If the value is a double
1588 // hole then jump to |if_hole|. If |machine_type| is None then only the hole
1589 // check is generated.
1590 TNode<Float64T> LoadDoubleWithHoleCheck(
1592 MachineType machine_type = MachineType::Float64());
1593#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1594 TNode<Float64T> LoadDoubleWithUndefinedAndHoleCheck(
1596 Label* if_hole, MachineType machine_type = MachineType::Float64());
1597#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1598 TNode<Numeric> LoadFixedTypedArrayElementAsTagged(TNode<RawPtrT> data_pointer,
1599 TNode<UintPtrT> index,
1600 ElementsKind elements_kind);
1601 TNode<Numeric> LoadFixedTypedArrayElementAsTagged(
1602 TNode<RawPtrT> data_pointer, TNode<UintPtrT> index,
1603 TNode<Int32T> elements_kind);
1604 // Parts of the above, factored out for readability:
1605 TNode<BigInt> LoadFixedBigInt64ArrayElementAsTagged(
1606 TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset);
1607 TNode<BigInt> LoadFixedBigUint64ArrayElementAsTagged(
1608 TNode<RawPtrT> data_pointer, TNode<IntPtrT> offset);
1609 // 64-bit platforms only:
1610 TNode<BigInt> BigIntFromInt64(TNode<IntPtrT> value);
1611 TNode<BigInt> BigIntFromUint64(TNode<UintPtrT> value);
1612 // 32-bit platforms only:
1613 TNode<BigInt> BigIntFromInt32Pair(TNode<IntPtrT> low, TNode<IntPtrT> high);
1614 TNode<BigInt> BigIntFromUint32Pair(TNode<UintPtrT> low, TNode<UintPtrT> high);
1615
1616 // ScopeInfo:
1617 TNode<ScopeInfo> LoadScopeInfo(TNode<Context> context);
1618 TNode<BoolT> LoadScopeInfoHasExtensionField(TNode<ScopeInfo> scope_info);
1619 TNode<BoolT> LoadScopeInfoClassScopeHasPrivateBrand(
1620 TNode<ScopeInfo> scope_info);
1621
1622 // Context manipulation:
1623 void StoreContextElementNoWriteBarrier(TNode<Context> context, int slot_index,
1624 TNode<Object> value);
1625 TNode<NativeContext> LoadNativeContext(TNode<Context> context);
1626 // Calling this is only valid if there's a module context in the chain.
1627 TNode<Context> LoadModuleContext(TNode<Context> context);
1628
1629 TNode<Object> GetImportMetaObject(TNode<Context> context);
1630
1632 TNode<NativeContext> native_context,
1633 int slot_index, Label* if_equal) {
1634 GotoIf(TaggedEqual(value, LoadContextElement(native_context, slot_index)),
1635 if_equal);
1636 }
1637
1638 // Loads the initial map of the the Object constructor.
1639 TNode<Map> LoadObjectFunctionInitialMap(TNode<NativeContext> native_context);
1640 TNode<Map> LoadSlowObjectWithNullPrototypeMap(
1641 TNode<NativeContext> native_context);
1642 TNode<Map> LoadCachedMap(TNode<NativeContext> native_context,
1643 TNode<IntPtrT> number_of_properties, Label* runtime);
1644
1645 TNode<Map> LoadJSArrayElementsMap(ElementsKind kind,
1646 TNode<NativeContext> native_context);
1647 TNode<Map> LoadJSArrayElementsMap(TNode<Int32T> kind,
1648 TNode<NativeContext> native_context);
1649
1650 TNode<BoolT> IsJSFunctionWithPrototypeSlot(TNode<HeapObject> object);
1651 TNode<Uint32T> LoadFunctionKind(TNode<JSFunction> function);
1653 void BranchIfHasPrototypeProperty(TNode<JSFunction> function,
1654 TNode<Int32T> function_map_bit_field,
1655 Label* if_true, Label* if_false);
1656 void GotoIfPrototypeRequiresRuntimeLookup(TNode<JSFunction> function,
1657 TNode<Map> map, Label* runtime);
1658 // Load the "prototype" property of a JSFunction.
1659 TNode<HeapObject> LoadJSFunctionPrototype(TNode<JSFunction> function,
1660 Label* if_bailout);
1661
1662 // Load the "code" property of a JSFunction.
1663 TNode<Code> LoadJSFunctionCode(TNode<JSFunction> function);
1664
1665 TNode<Object> LoadSharedFunctionInfoTrustedData(
1667 TNode<Object> LoadSharedFunctionInfoUntrustedData(
1669
1670 TNode<BoolT> SharedFunctionInfoHasBaselineCode(TNode<SharedFunctionInfo> sfi);
1671
1672 TNode<Smi> LoadSharedFunctionInfoBuiltinId(TNode<SharedFunctionInfo> sfi);
1673
1674 TNode<BytecodeArray> LoadSharedFunctionInfoBytecodeArray(
1676
1677#ifdef V8_ENABLE_WEBASSEMBLY
1678 TNode<WasmFunctionData> LoadSharedFunctionInfoWasmFunctionData(
1681 LoadSharedFunctionInfoWasmExportedFunctionData(TNode<SharedFunctionInfo> sfi);
1682 TNode<WasmJSFunctionData> LoadSharedFunctionInfoWasmJSFunctionData(
1684#endif // V8_ENABLE_WEBASSEMBLY
1685
1686 TNode<Int32T> LoadBytecodeArrayParameterCount(
1687 TNode<BytecodeArray> bytecode_array);
1688 TNode<Int32T> LoadBytecodeArrayParameterCountWithoutReceiver(
1689 TNode<BytecodeArray> bytecode_array);
1690
1691 void StoreObjectByteNoWriteBarrier(TNode<HeapObject> object, int offset,
1692 TNode<Word32T> value);
1693
1694 // Store the floating point value of a HeapNumber.
1695 void StoreHeapNumberValue(TNode<HeapNumber> object, TNode<Float64T> value);
1696
1697 // Store a field to an object on the heap.
1698 void StoreObjectField(TNode<HeapObject> object, int offset, TNode<Smi> value);
1699 void StoreObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset,
1700 TNode<Smi> value);
1701 void StoreObjectField(TNode<HeapObject> object, int offset,
1702 TNode<Object> value);
1703 void StoreObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset,
1704 TNode<Object> value);
1705
1706 // Store to an indirect pointer field. This involves loading the index for
1707 // the pointer table entry owned by the pointed-to object (which points back
1708 // to it) and storing that into the specified field.
1709 // Stores that may require a write barrier also need to know the indirect
1710 // pointer tag for the field. Otherwise, it is not needed
1711 void StoreIndirectPointerField(TNode<HeapObject> object, int offset,
1714 void StoreIndirectPointerFieldNoWriteBarrier(
1717
1718 // Store a trusted pointer field.
1719 // When the sandbox is enabled, these are indirect pointers using the trusted
1720 // pointer table. Otherwise they are regular tagged fields.
1721 void StoreTrustedPointerField(TNode<HeapObject> object, int offset,
1724 void StoreTrustedPointerFieldNoWriteBarrier(
1727
1728 void ClearTrustedPointerField(TNode<HeapObject> object, int offset);
1729
1730 // Store a code pointer field.
1731 // These are special versions of trusted pointers that, when the sandbox is
1732 // enabled, reference code objects through the code pointer table.
1734 TNode<Code> value) {
1735 StoreTrustedPointerField(object, offset, kCodeIndirectPointerTag, value);
1736 }
1738 TNode<Code> value) {
1739 StoreTrustedPointerFieldNoWriteBarrier(object, offset,
1740 kCodeIndirectPointerTag, value);
1741 }
1742
1743 template <class T>
1746 int const_offset;
1747 if (TryToInt32Constant(offset, &const_offset)) {
1748 return StoreObjectFieldNoWriteBarrier<T>(object, const_offset, value);
1749 }
1750 StoreNoWriteBarrier(MachineRepresentationOf<T>::value, object,
1751 IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)),
1752 value);
1753 }
1754 template <class T>
1756 TNode<T> value) {
1758 OptimizedStoreFieldAssertNoWriteBarrier(MachineRepresentationOf<T>::value,
1759 object, offset, value);
1760 } else {
1761 OptimizedStoreFieldUnsafeNoWriteBarrier(MachineRepresentationOf<T>::value,
1762 object, offset, value);
1763 }
1764 }
1765
1766 void UnsafeStoreObjectFieldNoWriteBarrier(TNode<HeapObject> object,
1767 int offset, TNode<Object> value);
1768
1769 // Store the Map of an HeapObject.
1770 void StoreMap(TNode<HeapObject> object, TNode<Map> map);
1771 void StoreMapNoWriteBarrier(TNode<HeapObject> object,
1772 RootIndex map_root_index);
1773 void StoreMapNoWriteBarrier(TNode<HeapObject> object, TNode<Map> map);
1774 void StoreObjectFieldRoot(TNode<HeapObject> object, int offset,
1775 RootIndex root);
1776
1777 // Store an array element to a FixedArray.
1779 TNode<FixedArray> object, int index, TNode<Object> value,
1780 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
1781 CheckBounds check_bounds = CheckBounds::kAlways) {
1782 return StoreFixedArrayElement(object, IntPtrConstant(index), value,
1783 barrier_mode, 0, check_bounds);
1784 }
1785
1787 TNode<Smi> value,
1788 CheckBounds check_bounds = CheckBounds::kAlways) {
1789 return StoreFixedArrayElement(object, IntPtrConstant(index),
1790 TNode<Object>{value},
1791 UNSAFE_SKIP_WRITE_BARRIER, 0, check_bounds);
1792 }
1793
1794 template <typename TIndex>
1796 TNode<FixedArray> array, TNode<TIndex> index, TNode<Object> value,
1797 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
1798 int additional_offset = 0,
1799 CheckBounds check_bounds = CheckBounds::kAlways) {
1800 // TODO(v8:9708): Do we want to keep both IntPtrT and UintPtrT variants?
1801 static_assert(std::is_same<TIndex, Smi>::value ||
1802 std::is_same<TIndex, UintPtrT>::value ||
1803 std::is_same<TIndex, IntPtrT>::value,
1804 "Only Smi, UintPtrT or IntPtrT index is allowed");
1805 if (NeedsBoundsCheck(check_bounds)) {
1806 FixedArrayBoundsCheck(array, index, additional_offset);
1807 }
1808 StoreFixedArrayOrPropertyArrayElement(array, index, value, barrier_mode,
1809 additional_offset);
1810 }
1811
1812 template <typename TIndex>
1814 TNode<Smi> value, int additional_offset = 0) {
1815 static_assert(std::is_same<TIndex, Smi>::value ||
1816 std::is_same<TIndex, IntPtrT>::value,
1817 "Only Smi or IntPtrT indeces is allowed");
1818 StoreFixedArrayElement(array, index, TNode<Object>{value},
1819 UNSAFE_SKIP_WRITE_BARRIER, additional_offset);
1820 }
1821
1822 // These don't emit a bounds-check. As part of the security-performance
1823 // tradeoff, only use it if it is performance critical.
1825 TNode<FixedArray> object, int index, TNode<Object> value,
1826 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
1827 return StoreFixedArrayElement(object, IntPtrConstant(index), value,
1828 barrier_mode, 0, CheckBounds::kDebugOnly);
1829 }
1830 template <typename Array>
1832 TNode<Array> object, int index,
1834 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
1835 DCHECK(barrier_mode == SKIP_WRITE_BARRIER ||
1836 barrier_mode == UNSAFE_SKIP_WRITE_BARRIER ||
1837 barrier_mode == UPDATE_WRITE_BARRIER);
1838 // TODO(jgruber): This is just a barebones implementation taken from
1839 // StoreFixedArrayOrPropertyArrayElement. We can make it more robust and
1840 // generic if needed.
1841 int offset = Array::OffsetOfElementAt(index);
1842 if (barrier_mode == UNSAFE_SKIP_WRITE_BARRIER) {
1843 UnsafeStoreObjectFieldNoWriteBarrier(object, offset, value);
1844 } else if (barrier_mode == SKIP_WRITE_BARRIER) {
1845 StoreObjectFieldNoWriteBarrier(object, offset, value);
1846 } else if (barrier_mode == UPDATE_WRITE_BARRIER) {
1847 StoreObjectField(object, offset, value);
1848 } else {
1849 UNREACHABLE();
1850 }
1851 }
1852 template <typename Array>
1854 TNode<Array> object, TNode<Smi> index,
1856 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
1857 DCHECK(barrier_mode == SKIP_WRITE_BARRIER ||
1858 barrier_mode == UPDATE_WRITE_BARRIER);
1859 // TODO(jgruber): This is just a barebones implementation taken from
1860 // StoreFixedArrayOrPropertyArrayElement. We can make it more robust and
1861 // generic if needed.
1862 TNode<IntPtrT> offset = ElementOffsetFromIndex(index, PACKED_ELEMENTS,
1864 if (barrier_mode == SKIP_WRITE_BARRIER) {
1865 StoreObjectFieldNoWriteBarrier(object, offset, value);
1866 } else if (barrier_mode == UPDATE_WRITE_BARRIER) {
1867 StoreObjectField(object, offset, value);
1868 } else {
1869 UNREACHABLE();
1870 }
1871 }
1872
1874 TNode<Smi> value) {
1875 return StoreFixedArrayElement(object, IntPtrConstant(index), value,
1877 CheckBounds::kDebugOnly);
1878 }
1879
1882 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
1883 int additional_offset = 0) {
1884 return StoreFixedArrayElement(array, index, value, barrier_mode,
1885 additional_offset, CheckBounds::kDebugOnly);
1886 }
1887
1889 TNode<IntPtrT> index, TNode<Smi> value,
1890 int additional_offset) {
1891 return StoreFixedArrayElement(array, index, value,
1892 UNSAFE_SKIP_WRITE_BARRIER, additional_offset,
1893 CheckBounds::kDebugOnly);
1894 }
1895
1897 TNode<IntPtrT> index, TNode<Object> value) {
1898 StoreFixedArrayOrPropertyArrayElement(array, index, value,
1900 }
1901
1902 template <typename TIndex>
1903 void StoreFixedDoubleArrayElement(
1905 TNode<Float64T> value, CheckBounds check_bounds = CheckBounds::kAlways);
1906
1907 void StoreDoubleHole(TNode<HeapObject> object, TNode<IntPtrT> offset);
1908#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1909 void StoreDoubleUndefined(TNode<HeapObject> object, TNode<IntPtrT> offset);
1910#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1911 void StoreFixedDoubleArrayHole(TNode<FixedDoubleArray> array,
1912 TNode<IntPtrT> index);
1913#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1914 void StoreFixedDoubleArrayUndefined(TNode<FixedDoubleArray> array,
1915 TNode<IntPtrT> index);
1916#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
1917 void StoreFeedbackVectorSlot(
1918 TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot,
1919 TNode<AnyTaggedT> value,
1920 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
1921 int additional_offset = 0);
1922
1923 void StoreSharedObjectField(TNode<HeapObject> object, TNode<IntPtrT> offset,
1924 TNode<Object> value);
1925
1927 TNode<IntPtrT> index,
1928 TNode<Object> value) {
1929 StoreFixedArrayOrPropertyArrayElement(array, index, value);
1930 }
1931
1932 // EnsureArrayPushable verifies that receiver with this map is:
1933 // 1. Is not a prototype.
1934 // 2. Is not a dictionary.
1935 // 3. Has a writeable length property.
1936 // It returns ElementsKind as a node for further division into cases.
1937 TNode<Int32T> EnsureArrayPushable(TNode<Context> context, TNode<Map> map,
1938 Label* bailout);
1939
1940 void TryStoreArrayElement(ElementsKind kind, Label* bailout,
1941 TNode<FixedArrayBase> elements, TNode<BInt> index,
1942 TNode<Object> value);
1943 // Consumes args into the array, and returns tagged new length.
1944 TNode<Smi> BuildAppendJSArray(ElementsKind kind, TNode<JSArray> array,
1946 TVariable<IntPtrT>* arg_index, Label* bailout);
1947 // Pushes value onto the end of array.
1948 void BuildAppendJSArray(ElementsKind kind, TNode<JSArray> array,
1949 TNode<Object> value, Label* bailout);
1950
1951 void StoreFieldsNoWriteBarrier(TNode<IntPtrT> start_address,
1952 TNode<IntPtrT> end_address,
1953 TNode<Object> value);
1954
1955 // Marks the FixedArray copy-on-write without moving it.
1956 void MakeFixedArrayCOW(TNode<FixedArray> array);
1957
1958 TNode<Cell> AllocateCellWithValue(
1959 TNode<Object> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
1961 return AllocateCellWithValue(SmiConstant(value), SKIP_WRITE_BARRIER);
1962 }
1963
1964 TNode<Object> LoadCellValue(TNode<Cell> cell);
1965
1966 void StoreCellValue(TNode<Cell> cell, TNode<Object> value,
1967 WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
1968
1969 // Allocate a HeapNumber without initializing its value.
1970 TNode<HeapNumber> AllocateHeapNumber();
1971 // Allocate a HeapNumber with a specific value.
1972 TNode<HeapNumber> AllocateHeapNumberWithValue(TNode<Float64T> value);
1974 return AllocateHeapNumberWithValue(Float64Constant(value));
1975 }
1976 TNode<HeapNumber> AllocateHeapInt32WithValue(TNode<Int32T> value);
1977
1978 // Allocate a BigInt with {length} digits. Sets the sign bit to {false}.
1979 // Does not initialize the digits.
1980 TNode<BigInt> AllocateBigInt(TNode<IntPtrT> length);
1981 // Like above, but allowing custom bitfield initialization.
1982 TNode<BigInt> AllocateRawBigInt(TNode<IntPtrT> length);
1983 void StoreBigIntBitfield(TNode<BigInt> bigint, TNode<Word32T> bitfield);
1984 void StoreBigIntDigit(TNode<BigInt> bigint, intptr_t digit_index,
1985 TNode<UintPtrT> digit);
1986 void StoreBigIntDigit(TNode<BigInt> bigint, TNode<IntPtrT> digit_index,
1987 TNode<UintPtrT> digit);
1988
1989 TNode<Word32T> LoadBigIntBitfield(TNode<BigInt> bigint);
1990 TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, intptr_t digit_index);
1991 TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint,
1992 TNode<IntPtrT> digit_index);
1993
1994 // Allocate a ByteArray with the given non-zero length.
1995 TNode<ByteArray> AllocateNonEmptyByteArray(
1996 TNode<UintPtrT> length, AllocationFlags flags = AllocationFlag::kNone);
1997
1998 // Allocate a ByteArray with the given length.
1999 TNode<ByteArray> AllocateByteArray(
2000 TNode<UintPtrT> length, AllocationFlags flags = AllocationFlag::kNone);
2001
2002 // Allocate a SeqOneByteString with the given length.
2003 TNode<String> AllocateSeqOneByteString(
2004 uint32_t length, AllocationFlags flags = AllocationFlag::kNone);
2005 using TorqueGeneratedExportedMacrosAssembler::AllocateSeqOneByteString;
2006
2007 // Allocate a SeqTwoByteString with the given length.
2008 TNode<String> AllocateSeqTwoByteString(
2009 uint32_t length, AllocationFlags flags = AllocationFlag::kNone);
2010 using TorqueGeneratedExportedMacrosAssembler::AllocateSeqTwoByteString;
2011
2012 // Allocate a SlicedOneByteString with the given length, parent and offset.
2013 // |length| and |offset| are expected to be tagged.
2014
2015 TNode<String> AllocateSlicedOneByteString(TNode<Uint32T> length,
2016 TNode<String> parent,
2018 // Allocate a SlicedTwoByteString with the given length, parent and offset.
2019 // |length| and |offset| are expected to be tagged.
2020 TNode<String> AllocateSlicedTwoByteString(TNode<Uint32T> length,
2021 TNode<String> parent,
2023
2024 TNode<NameDictionary> AllocateNameDictionary(int at_least_space_for);
2025 TNode<NameDictionary> AllocateNameDictionary(
2026 TNode<IntPtrT> at_least_space_for,
2027 AllocationFlags = AllocationFlag::kNone);
2028 TNode<NameDictionary> AllocateNameDictionaryWithCapacity(
2029 TNode<IntPtrT> capacity, AllocationFlags = AllocationFlag::kNone);
2030
2031 TNode<PropertyDictionary> AllocatePropertyDictionary(int at_least_space_for);
2032 TNode<PropertyDictionary> AllocatePropertyDictionary(
2033 TNode<IntPtrT> at_least_space_for,
2034 AllocationFlags = AllocationFlag::kNone);
2035 TNode<PropertyDictionary> AllocatePropertyDictionaryWithCapacity(
2036 TNode<IntPtrT> capacity, AllocationFlags = AllocationFlag::kNone);
2037
2038 TNode<NameDictionary> CopyNameDictionary(TNode<NameDictionary> dictionary,
2039 Label* large_object_fallback);
2040
2041 TNode<OrderedHashSet> AllocateOrderedHashSet();
2042 TNode<OrderedHashSet> AllocateOrderedHashSet(TNode<IntPtrT> capacity);
2043
2044 TNode<OrderedHashMap> AllocateOrderedHashMap();
2045
2046 // Allocates an OrderedNameDictionary of the given capacity. This guarantees
2047 // that |capacity| entries can be added without reallocating.
2048 TNode<OrderedNameDictionary> AllocateOrderedNameDictionary(
2049 TNode<IntPtrT> capacity);
2050 TNode<OrderedNameDictionary> AllocateOrderedNameDictionary(int capacity);
2051
2052 TNode<JSObject> AllocateJSObjectFromMap(
2053 TNode<Map> map,
2054 std::optional<TNode<HeapObject>> properties = std::nullopt,
2055 std::optional<TNode<FixedArray>> elements = std::nullopt,
2056 AllocationFlags flags = AllocationFlag::kNone,
2057 SlackTrackingMode slack_tracking_mode = kNoSlackTracking);
2058
2059 void InitializeJSObjectFromMap(
2060 TNode<HeapObject> object, TNode<Map> map, TNode<IntPtrT> instance_size,
2061 std::optional<TNode<HeapObject>> properties = std::nullopt,
2062 std::optional<TNode<FixedArray>> elements = std::nullopt,
2063 SlackTrackingMode slack_tracking_mode = kNoSlackTracking);
2064
2065 void InitializeJSObjectBodyWithSlackTracking(TNode<HeapObject> object,
2066 TNode<Map> map,
2067 TNode<IntPtrT> instance_size);
2068 void InitializeJSObjectBodyNoSlackTracking(
2069 TNode<HeapObject> object, TNode<Map> map, TNode<IntPtrT> instance_size,
2070 int start_offset = JSObject::kHeaderSize);
2071
2072 TNode<BoolT> IsValidFastJSArrayCapacity(TNode<IntPtrT> capacity);
2073
2074 //
2075 // Allocate and return a JSArray with initialized header fields and its
2076 // uninitialized elements.
2077 std::pair<TNode<JSArray>, TNode<FixedArrayBase>>
2078 AllocateUninitializedJSArrayWithElements(
2079 ElementsKind kind, TNode<Map> array_map, TNode<Smi> length,
2080 std::optional<TNode<AllocationSite>> allocation_site,
2081 TNode<IntPtrT> capacity,
2082 AllocationFlags allocation_flags = AllocationFlag::kNone,
2083 int array_header_size = JSArray::kHeaderSize);
2084
2085 // Allocate a JSArray and fill elements with the hole.
2086 TNode<JSArray> AllocateJSArray(
2087 ElementsKind kind, TNode<Map> array_map, TNode<IntPtrT> capacity,
2088 TNode<Smi> length, std::optional<TNode<AllocationSite>> allocation_site,
2089 AllocationFlags allocation_flags = AllocationFlag::kNone);
2091 ElementsKind kind, TNode<Map> array_map, TNode<Smi> capacity,
2092 TNode<Smi> length, std::optional<TNode<AllocationSite>> allocation_site,
2093 AllocationFlags allocation_flags = AllocationFlag::kNone) {
2094 return AllocateJSArray(kind, array_map, PositiveSmiUntag(capacity), length,
2095 allocation_site, allocation_flags);
2096 }
2098 ElementsKind kind, TNode<Map> array_map, TNode<Smi> capacity,
2099 TNode<Smi> length,
2100 AllocationFlags allocation_flags = AllocationFlag::kNone) {
2101 return AllocateJSArray(kind, array_map, PositiveSmiUntag(capacity), length,
2102 std::nullopt, allocation_flags);
2103 }
2105 ElementsKind kind, TNode<Map> array_map, TNode<IntPtrT> capacity,
2106 TNode<Smi> length,
2107 AllocationFlags allocation_flags = AllocationFlag::kNone) {
2108 return AllocateJSArray(kind, array_map, capacity, length, std::nullopt,
2109 allocation_flags);
2110 }
2111
2112 // Allocate a JSArray and initialize the header fields.
2113 TNode<JSArray> AllocateJSArray(
2114 TNode<Map> array_map, TNode<FixedArrayBase> elements, TNode<Smi> length,
2115 std::optional<TNode<AllocationSite>> allocation_site = std::nullopt,
2116 int array_header_size = JSArray::kHeaderSize);
2117
2118 enum class HoleConversionMode { kDontConvert, kConvertToUndefined };
2119 // Clone a fast JSArray |array| into a new fast JSArray.
2120 // |convert_holes| tells the function to convert holes into undefined or not.
2121 // If |convert_holes| is set to kConvertToUndefined, but the function did not
2122 // find any hole in |array|, the resulting array will have the same elements
2123 // kind as |array|. If the function did find a hole, it will convert holes in
2124 // |array| to undefined in the resulting array, who will now have
2125 // PACKED_ELEMENTS kind.
2126 // If |convert_holes| is set kDontConvert, holes are also copied to the
2127 // resulting array, who will have the same elements kind as |array|. The
2128 // function generates significantly less code in this case.
2129 TNode<JSArray> CloneFastJSArray(
2130 TNode<Context> context, TNode<JSArray> array,
2131 std::optional<TNode<AllocationSite>> allocation_site = std::nullopt,
2132 HoleConversionMode convert_holes = HoleConversionMode::kDontConvert);
2133
2134 TNode<JSArray> ExtractFastJSArray(TNode<Context> context,
2135 TNode<JSArray> array, TNode<BInt> begin,
2137
2138 template <typename TIndex>
2139 TNode<FixedArrayBase> AllocateFixedArray(
2141 AllocationFlags flags = AllocationFlag::kNone,
2142 std::optional<TNode<Map>> fixed_array_map = std::nullopt);
2143
2144 template <typename Function>
2145 TNode<Object> FastCloneJSObject(TNode<HeapObject> source,
2146 TNode<Map> source_map, TNode<Map> target_map,
2147 const Function& materialize_target,
2148 bool target_is_new);
2149
2150 TNode<NativeContext> GetCreationContextFromMap(TNode<Map> map,
2151 Label* if_bailout);
2153 Label* if_bailout);
2154 TNode<NativeContext> GetFunctionRealm(TNode<Context> context,
2156 Label* if_bailout);
2157 TNode<Object> GetConstructor(TNode<Map> map);
2158
2159 void FindNonDefaultConstructor(TNode<JSFunction> this_function,
2160 TVariable<Object>& constructor,
2161 Label* found_default_base_ctor,
2162 Label* found_something_else);
2163
2164 TNode<Map> GetInstanceTypeMap(InstanceType instance_type);
2165
2167 return UncheckedCast<FixedArray>(AllocateFixedArray(
2168 PACKED_ELEMENTS, IntPtrConstant(capacity), AllocationFlag::kNone));
2169 }
2170
2172 TNode<FixedArray> result = UncheckedCast<FixedArray>(
2173 AllocateFixedArray(PACKED_ELEMENTS, capacity));
2174 FillEntireFixedArrayWithSmiZero(PACKED_ELEMENTS, result, capacity);
2175 return result;
2176 }
2177
2179 TNode<IntPtrT> capacity) {
2180 TNode<FixedDoubleArray> result = UncheckedCast<FixedDoubleArray>(
2181 AllocateFixedArray(PACKED_DOUBLE_ELEMENTS, capacity));
2182 FillEntireFixedDoubleArrayWithZero(result, capacity);
2183 return result;
2184 }
2185
2187 TNode<IntPtrT> capacity, AllocationFlags flags = AllocationFlag::kNone) {
2188 TNode<FixedArray> result = UncheckedCast<FixedArray>(
2189 AllocateFixedArray(PACKED_ELEMENTS, capacity, flags));
2190 FillFixedArrayWithValue(PACKED_ELEMENTS, result, IntPtrConstant(0),
2191 capacity, RootIndex::kTheHoleValue);
2192 return result;
2193 }
2194
2196 TNode<IntPtrT> capacity, AllocationFlags flags = AllocationFlag::kNone) {
2197 TNode<FixedDoubleArray> result = UncheckedCast<FixedDoubleArray>(
2198 AllocateFixedArray(PACKED_DOUBLE_ELEMENTS, capacity, flags));
2199 FillFixedArrayWithValue(PACKED_DOUBLE_ELEMENTS, result, IntPtrConstant(0),
2200 capacity, RootIndex::kTheHoleValue);
2201 return result;
2202 }
2203
2204 TNode<PropertyArray> AllocatePropertyArray(TNode<IntPtrT> capacity);
2205
2206 // TODO(v8:9722): Return type should be JSIteratorResult
2207 TNode<JSObject> AllocateJSIteratorResult(TNode<Context> context,
2208 TNode<Object> value,
2209 TNode<Boolean> done);
2210
2211 // TODO(v8:9722): Return type should be JSIteratorResult
2212 TNode<JSObject> AllocateJSIteratorResultForEntry(TNode<Context> context,
2214 TNode<Object> value);
2215
2216 TNode<JSObject> AllocatePromiseWithResolversResult(TNode<Context> context,
2217 TNode<Object> promise,
2218 TNode<Object> resolve,
2219 TNode<Object> reject);
2220
2221 TNode<JSReceiver> ArraySpeciesCreate(TNode<Context> context,
2222 TNode<Object> originalArray,
2223 TNode<Number> len);
2224
2225 template <typename TIndex>
2226 void FillFixedArrayWithValue(ElementsKind kind, TNode<FixedArrayBase> array,
2227 TNode<TIndex> from_index, TNode<TIndex> to_index,
2228 RootIndex value_root_index);
2229 template <typename TIndex>
2231 TNode<TIndex> from_index, TNode<TIndex> to_index,
2232 RootIndex value_root_index) {
2233 FillFixedArrayWithValue(kind, UncheckedCast<FixedArrayBase>(array),
2234 from_index, to_index, value_root_index);
2235 }
2236
2237 // Uses memset to effectively initialize the given FixedArray with zeroes.
2238 void FillFixedArrayWithSmiZero(ElementsKind kind, TNode<FixedArray> array,
2241 TNode<FixedArray> array,
2242 TNode<IntPtrT> length) {
2243 CSA_DCHECK(this,
2244 WordEqual(length, LoadAndUntagFixedArrayBaseLength(array)));
2245 FillFixedArrayWithSmiZero(kind, array, IntPtrConstant(0), length);
2246 }
2247
2248 void FillFixedDoubleArrayWithZero(TNode<FixedDoubleArray> array,
2250 TNode<IntPtrT> length);
2252 TNode<IntPtrT> length) {
2253 CSA_DCHECK(this,
2254 WordEqual(length, LoadAndUntagFixedArrayBaseLength(array)));
2255 FillFixedDoubleArrayWithZero(array, IntPtrConstant(0), length);
2256 }
2257
2258 void FillPropertyArrayWithUndefined(TNode<PropertyArray> array,
2259 TNode<IntPtrT> from_index,
2260 TNode<IntPtrT> to_index);
2261
2262 enum class DestroySource { kNo, kYes };
2263
2264 // Increment the call count for a CALL_IC or construct call.
2265 // The call count is located at feedback_vector[slot_id + 1].
2266 void IncrementCallCount(TNode<FeedbackVector> feedback_vector,
2267 TNode<UintPtrT> slot_id);
2268
2269 // Specify DestroySource::kYes if {from_array} is being supplanted by
2270 // {to_array}. This offers a slight performance benefit by simply copying the
2271 // array word by word. The source may be destroyed at the end of this macro.
2272 //
2273 // Otherwise, specify DestroySource::kNo for operations where an Object is
2274 // being cloned, to ensure that mutable HeapNumbers are unique between the
2275 // source and cloned object.
2276 void CopyPropertyArrayValues(TNode<HeapObject> from_array,
2277 TNode<PropertyArray> to_array,
2278 TNode<IntPtrT> length,
2279 WriteBarrierMode barrier_mode,
2280 DestroySource destroy_source);
2281
2282 // Copies all elements from |from_array| of |length| size to
2283 // |to_array| of the same size respecting the elements kind.
2284 template <typename TIndex>
2287 TNode<FixedArrayBase> to_array, TNode<TIndex> length,
2288 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
2289 CopyFixedArrayElements(kind, from_array, kind, to_array,
2290 IntPtrOrSmiConstant<TIndex>(0), length, length,
2291 barrier_mode);
2292 }
2293
2294 // Copies |element_count| elements from |from_array| starting from element
2295 // zero to |to_array| of |capacity| size respecting both array's elements
2296 // kinds.
2297 template <typename TIndex>
2299 ElementsKind from_kind, TNode<FixedArrayBase> from_array,
2300 ElementsKind to_kind, TNode<FixedArrayBase> to_array,
2301 TNode<TIndex> element_count, TNode<TIndex> capacity,
2302 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER) {
2303 CopyFixedArrayElements(from_kind, from_array, to_kind, to_array,
2304 IntPtrOrSmiConstant<TIndex>(0), element_count,
2305 capacity, barrier_mode);
2306 }
2307
2308 // Copies |element_count| elements from |from_array| starting from element
2309 // |first_element| to |to_array| of |capacity| size respecting both array's
2310 // elements kinds.
2311 // |convert_holes| tells the function whether to convert holes to undefined.
2312 // |var_holes_converted| can be used to signify that the conversion happened
2313 // (i.e. that there were holes). If |convert_holes_to_undefined| is
2314 // HoleConversionMode::kConvertToUndefined, then it must not be the case that
2315 // IsDoubleElementsKind(to_kind).
2316 template <typename TIndex>
2317 void CopyFixedArrayElements(
2318 ElementsKind from_kind, TNode<FixedArrayBase> from_array,
2319 ElementsKind to_kind, TNode<FixedArrayBase> to_array,
2320 TNode<TIndex> first_element, TNode<TIndex> element_count,
2321 TNode<TIndex> capacity,
2322 WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
2323 HoleConversionMode convert_holes = HoleConversionMode::kDontConvert,
2324 TVariable<BoolT>* var_holes_converted = nullptr);
2325
2326 void TrySkipWriteBarrier(TNode<Object> object, Label* if_needs_write_barrier);
2327
2328 // Efficiently copy elements within a single array. The regions
2329 // [src_index, src_index + length) and [dst_index, dst_index + length)
2330 // can be overlapping.
2331 void MoveElements(ElementsKind kind, TNode<FixedArrayBase> elements,
2332 TNode<IntPtrT> dst_index, TNode<IntPtrT> src_index,
2333 TNode<IntPtrT> length);
2334
2335 // Efficiently copy elements from one array to another. The ElementsKind
2336 // needs to be the same. Copy from src_elements at
2337 // [src_index, src_index + length) to dst_elements at
2338 // [dst_index, dst_index + length).
2339 // The function decides whether it can use memcpy. In case it cannot,
2340 // |write_barrier| can help it to skip write barrier. SKIP_WRITE_BARRIER is
2341 // only safe when copying to new space, or when copying to old space and the
2342 // array does not contain object pointers.
2343 void CopyElements(ElementsKind kind, TNode<FixedArrayBase> dst_elements,
2344 TNode<IntPtrT> dst_index,
2345 TNode<FixedArrayBase> src_elements,
2346 TNode<IntPtrT> src_index, TNode<IntPtrT> length,
2347 WriteBarrierMode write_barrier = UPDATE_WRITE_BARRIER);
2348
2349 void CopyRange(TNode<HeapObject> dst_object, int dst_offset,
2350 TNode<HeapObject> src_object, int src_offset,
2351 TNode<IntPtrT> length_in_tagged,
2352 WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
2353
2354 TNode<FixedArray> HeapObjectToFixedArray(TNode<HeapObject> base,
2355 Label* cast_fail);
2356
2358 Label* cast_fail) {
2359 GotoIf(TaggedNotEqual(LoadMap(base), FixedDoubleArrayMapConstant()),
2360 cast_fail);
2361 return UncheckedCast<FixedDoubleArray>(base);
2362 }
2363
2364 TNode<ArrayList> AllocateArrayList(TNode<Smi> size);
2365 TNode<ArrayList> ArrayListEnsureSpace(TNode<ArrayList> array,
2366 TNode<Smi> length);
2367 TNode<ArrayList> ArrayListAdd(TNode<ArrayList> array, TNode<Object> object);
2368 void ArrayListSet(TNode<ArrayList> array, TNode<Smi> index,
2369 TNode<Object> object);
2370 TNode<Smi> ArrayListGetLength(TNode<ArrayList> array);
2371 void ArrayListSetLength(TNode<ArrayList> array, TNode<Smi> length);
2372 // TODO(jgruber): Rename to ArrayListToFixedArray.
2373 TNode<FixedArray> ArrayListElements(TNode<ArrayList> array);
2374
2375 template <typename T>
2377 return false;
2378 }
2379
2380 template <typename T>
2382 UNREACHABLE();
2383 return TNode<Map>();
2384 }
2385
2387 kFixedArrays = 1,
2388 kFixedDoubleArrays = 2,
2389 kDontCopyCOW = 4,
2390 kAllFixedArrays = kFixedArrays | kFixedDoubleArrays,
2391 kAllFixedArraysDontCopyCOW = kAllFixedArrays | kDontCopyCOW
2392 };
2393
2395
2396 // Copy a portion of an existing FixedArray or FixedDoubleArray into a new
2397 // array, including special appropriate handling for empty arrays and COW
2398 // arrays. The result array will be of the same type as the original array.
2399 //
2400 // * |source| is either a FixedArray or FixedDoubleArray from which to copy
2401 // elements.
2402 // * |first| is the starting element index to copy from, if nullptr is passed
2403 // then index zero is used by default.
2404 // * |count| is the number of elements to copy out of the source array
2405 // starting from and including the element indexed by |start|. If |count| is
2406 // nullptr, then all of the elements from |start| to the end of |source| are
2407 // copied.
2408 // * |capacity| determines the size of the allocated result array, with
2409 // |capacity| >= |count|. If |capacity| is nullptr, then |count| is used as
2410 // the destination array's capacity.
2411 // * |extract_flags| determines whether FixedArrays, FixedDoubleArrays or both
2412 // are detected and copied. Although it's always correct to pass
2413 // kAllFixedArrays, the generated code is more compact and efficient if the
2414 // caller can specify whether only FixedArrays or FixedDoubleArrays will be
2415 // passed as the |source| parameter.
2416 // * |parameter_mode| determines the parameter mode of |first|, |count| and
2417 // |capacity|.
2418 // * If |var_holes_converted| is given, any holes will be converted to
2419 // undefined and the variable will be set according to whether or not there
2420 // were any hole.
2421 // * If |source_elements_kind| is given, the function will try to use the
2422 // runtime elements kind of source to make copy faster. More specifically, it
2423 // can skip write barriers.
2424 template <typename TIndex>
2425 TNode<FixedArrayBase> ExtractFixedArray(
2426 TNode<FixedArrayBase> source, std::optional<TNode<TIndex>> first,
2427 std::optional<TNode<TIndex>> count = std::nullopt,
2428 std::optional<TNode<TIndex>> capacity = std::nullopt,
2429 ExtractFixedArrayFlags extract_flags =
2430 ExtractFixedArrayFlag::kAllFixedArrays,
2431 TVariable<BoolT>* var_holes_converted = nullptr,
2432 std::optional<TNode<Int32T>> source_elements_kind = std::nullopt);
2433
2434 // Copy a portion of an existing FixedArray or FixedDoubleArray into a new
2435 // FixedArray, including special appropriate handling for COW arrays.
2436 // * |source| is either a FixedArray or FixedDoubleArray from which to copy
2437 // elements. |source| is assumed to be non-empty.
2438 // * |first| is the starting element index to copy from.
2439 // * |count| is the number of elements to copy out of the source array
2440 // starting from and including the element indexed by |start|.
2441 // * |capacity| determines the size of the allocated result array, with
2442 // |capacity| >= |count|.
2443 // * |source_map| is the map of the |source|.
2444 // * |from_kind| is the elements kind that is consistent with |source| being
2445 // a FixedArray or FixedDoubleArray. This function only cares about double vs.
2446 // non-double, so as to distinguish FixedDoubleArray vs. FixedArray. It does
2447 // not care about holeyness. For example, when |source| is a FixedArray,
2448 // PACKED/HOLEY_ELEMENTS can be used, but not PACKED_DOUBLE_ELEMENTS.
2449 // * |allocation_flags| and |extract_flags| influence how the target
2450 // FixedArray is allocated.
2451 // * |convert_holes| is used to signify that the target array should use
2452 // undefined in places of holes.
2453 // * If |convert_holes| is true and |var_holes_converted| not nullptr, then
2454 // |var_holes_converted| is used to signal whether any holes were found and
2455 // converted. The caller should use this information to decide which map is
2456 // compatible with the result array. For example, if the input was of
2457 // HOLEY_SMI_ELEMENTS kind, and a conversion took place, the result will be
2458 // compatible only with HOLEY_ELEMENTS and PACKED_ELEMENTS.
2459 template <typename TIndex>
2460 TNode<FixedArray> ExtractToFixedArray(
2462 TNode<TIndex> capacity, TNode<Map> source_map, ElementsKind from_kind,
2463 AllocationFlags allocation_flags, ExtractFixedArrayFlags extract_flags,
2464 HoleConversionMode convert_holes,
2465 TVariable<BoolT>* var_holes_converted = nullptr,
2466 std::optional<TNode<Int32T>> source_runtime_kind = std::nullopt);
2467
2468 // Attempt to copy a FixedDoubleArray to another FixedDoubleArray. In the case
2469 // where the source array has a hole, produce a FixedArray instead where holes
2470 // are replaced with undefined.
2471 // * |source| is a FixedDoubleArray from which to copy elements.
2472 // * |first| is the starting element index to copy from.
2473 // * |count| is the number of elements to copy out of the source array
2474 // starting from and including the element indexed by |start|.
2475 // * |capacity| determines the size of the allocated result array, with
2476 // |capacity| >= |count|.
2477 // * |source_map| is the map of |source|. It will be used as the map of the
2478 // target array if the target can stay a FixedDoubleArray. Otherwise if the
2479 // target array needs to be a FixedArray, the FixedArrayMap will be used.
2480 // * |var_holes_converted| is used to signal whether a FixedArray
2481 // is produced or not.
2482 // * |allocation_flags| and |extract_flags| influence how the target array is
2483 // allocated.
2484 template <typename TIndex>
2485 TNode<FixedArrayBase> ExtractFixedDoubleArrayFillingHoles(
2487 TNode<TIndex> capacity, TNode<Map> source_map,
2488 TVariable<BoolT>* var_holes_converted, AllocationFlags allocation_flags,
2489 ExtractFixedArrayFlags extract_flags);
2490
2491 // Copy the entire contents of a FixedArray or FixedDoubleArray to a new
2492 // array, including special appropriate handling for empty arrays and COW
2493 // arrays.
2494 //
2495 // * |source| is either a FixedArray or FixedDoubleArray from which to copy
2496 // elements.
2497 // * |extract_flags| determines whether FixedArrays, FixedDoubleArrays or both
2498 // are detected and copied. Although it's always correct to pass
2499 // kAllFixedArrays, the generated code is more compact and efficient if the
2500 // caller can specify whether only FixedArrays or FixedDoubleArrays will be
2501 // passed as the |source| parameter.
2502 TNode<FixedArrayBase> CloneFixedArray(
2503 TNode<FixedArrayBase> source,
2505 ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW);
2506
2507 // Loads an element from |array| of |from_kind| elements by given |offset|
2508 // (NOTE: not index!), does a hole check if |if_hole| is provided and
2509 // converts the value so that it becomes ready for storing to array of
2510 // |to_kind| elements.
2511 template <typename TResult>
2514 ElementsKind from_kind,
2515 ElementsKind to_kind,
2516 Label* if_hole);
2517
2518 template <typename TIndex>
2519 TNode<TIndex> CalculateNewElementsCapacity(TNode<TIndex> old_capacity);
2520
2521 // Tries to grow the |elements| array of given |object| to store the |key|
2522 // or bails out if the growing gap is too big. Returns new elements.
2523 TNode<FixedArrayBase> TryGrowElementsCapacity(TNode<HeapObject> object,
2524 TNode<FixedArrayBase> elements,
2526 TNode<Smi> key, Label* bailout);
2527
2528 // Tries to grow the |capacity|-length |elements| array of given |object|
2529 // to store the |key| or bails out if the growing gap is too big. Returns
2530 // new elements.
2531 template <typename TIndex>
2532 TNode<FixedArrayBase> TryGrowElementsCapacity(TNode<HeapObject> object,
2533 TNode<FixedArrayBase> elements,
2536 TNode<TIndex> capacity,
2537 Label* bailout);
2538
2539 // Grows elements capacity of given object. Returns new elements.
2540 template <typename TIndex>
2541 TNode<FixedArrayBase> GrowElementsCapacity(
2543 ElementsKind from_kind, ElementsKind to_kind, TNode<TIndex> capacity,
2544 TNode<TIndex> new_capacity, Label* bailout);
2545
2546 // Given a need to grow by |growth|, allocate an appropriate new capacity
2547 // if necessary, and return a new elements FixedArray object. Label |bailout|
2548 // is followed for allocation failure.
2549 void PossiblyGrowElementsCapacity(ElementsKind kind, TNode<HeapObject> array,
2550 TNode<BInt> length,
2551 TVariable<FixedArrayBase>* var_elements,
2552 TNode<BInt> growth, Label* bailout);
2553
2554 // Allocation site manipulation
2555 void InitializeAllocationMemento(TNode<HeapObject> base,
2556 TNode<IntPtrT> base_allocation_size,
2557 TNode<AllocationSite> allocation_site);
2558
2559 TNode<IntPtrT> TryTaggedToInt32AsIntPtr(TNode<Object> value,
2560 Label* if_not_possible);
2561 TNode<Float64T> TryTaggedToFloat64(TNode<Object> value,
2562#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2563 Label* if_valueisundefined,
2564#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
2565 Label* if_valueisnotnumber);
2566 TNode<Float64T> TruncateTaggedToFloat64(TNode<Context> context,
2567 TNode<Object> value);
2568 TNode<Word32T> TruncateTaggedToWord32(TNode<Context> context,
2569 TNode<Object> value);
2570 void TaggedToWord32OrBigInt(TNode<Context> context, TNode<Object> value,
2571 Label* if_number, TVariable<Word32T>* var_word32,
2572 Label* if_bigint, Label* if_bigint64,
2573 TVariable<BigInt>* var_maybe_bigint);
2575 TVariable<Smi>* var_feedback = nullptr;
2576 const LazyNode<HeapObject>* maybe_feedback_vector = nullptr;
2577 TNode<UintPtrT>* slot = nullptr;
2578 UpdateFeedbackMode update_mode = UpdateFeedbackMode::kNoFeedback;
2579 };
2580 void TaggedToWord32OrBigIntWithFeedback(TNode<Context> context,
2581 TNode<Object> value, Label* if_number,
2582 TVariable<Word32T>* var_word32,
2583 Label* if_bigint, Label* if_bigint64,
2584 TVariable<BigInt>* var_maybe_bigint,
2585 const FeedbackValues& feedback);
2586 void TaggedPointerToWord32OrBigIntWithFeedback(
2587 TNode<Context> context, TNode<HeapObject> pointer, Label* if_number,
2588 TVariable<Word32T>* var_word32, Label* if_bigint, Label* if_bigint64,
2589 TVariable<BigInt>* var_maybe_bigint, const FeedbackValues& feedback);
2590
2591 TNode<Int32T> TruncateNumberToWord32(TNode<Number> value);
2592 // Truncate the floating point value of a HeapNumber to an Int32.
2593 TNode<Int32T> TruncateHeapNumberValueToWord32(TNode<HeapNumber> object);
2594
2595 // Conversions.
2596 TNode<Smi> TryHeapNumberToSmi(TNode<HeapNumber> number, Label* not_smi);
2597 TNode<Smi> TryFloat32ToSmi(TNode<Float32T> number, Label* not_smi);
2598 TNode<Smi> TryFloat64ToSmi(TNode<Float64T> number, Label* not_smi);
2599 TNode<Int32T> TryFloat64ToInt32(TNode<Float64T> number, Label* if_failed);
2600 TNode<AdditiveSafeIntegerT> TryFloat64ToAdditiveSafeInteger(
2601 TNode<Float64T> number, Label* if_failed);
2602
2603 TNode<BoolT> IsAdditiveSafeInteger(TNode<Float64T> number);
2604
2605 TNode<Uint32T> BitcastFloat16ToUint32(TNode<Float16RawBitsT> value);
2606 TNode<Float16RawBitsT> BitcastUint32ToFloat16(TNode<Uint32T> value);
2607 TNode<Float16RawBitsT> RoundInt32ToFloat16(TNode<Int32T> value);
2608
2609 TNode<Float64T> ChangeFloat16ToFloat64(TNode<Float16RawBitsT> value);
2611 TNode<Number> ChangeFloat32ToTagged(TNode<Float32T> value);
2612 TNode<Number> ChangeFloat64ToTagged(TNode<Float64T> value);
2613 TNode<Number> ChangeInt32ToTagged(TNode<Int32T> value);
2614 TNode<Number> ChangeInt32ToTaggedNoOverflow(TNode<Int32T> value);
2615 TNode<Number> ChangeUint32ToTagged(TNode<Uint32T> value);
2616 TNode<Number> ChangeUintPtrToTagged(TNode<UintPtrT> value);
2617 TNode<Uint32T> ChangeNonNegativeNumberToUint32(TNode<Number> value);
2618 TNode<Float64T> ChangeNumberToFloat64(TNode<Number> value);
2619
2620 TNode<Int32T> ChangeTaggedNonSmiToInt32(TNode<Context> context,
2621 TNode<HeapObject> input);
2622 TNode<Float64T> ChangeTaggedToFloat64(TNode<Context> context,
2623 TNode<Object> input);
2624
2625 TNode<Int32T> ChangeBoolToInt32(TNode<BoolT> b);
2626
2627 void TaggedToBigInt(TNode<Context> context, TNode<Object> value,
2628 Label* if_not_bigint, Label* if_bigint,
2629 Label* if_bigint64, TVariable<BigInt>* var_bigint,
2630 TVariable<Smi>* var_feedback);
2631
2632 // Ensures that {var_shared_value} is shareable across Isolates, and throws if
2633 // not.
2634 void SharedValueBarrier(TNode<Context> context,
2635 TVariable<Object>* var_shared_value);
2636
2637 TNode<WordT> TimesSystemPointerSize(TNode<WordT> value);
2639 return Signed(TimesSystemPointerSize(implicit_cast<TNode<WordT>>(value)));
2640 }
2642 return Unsigned(TimesSystemPointerSize(implicit_cast<TNode<WordT>>(value)));
2643 }
2644
2645 TNode<WordT> TimesTaggedSize(TNode<WordT> value);
2647 return Signed(TimesTaggedSize(implicit_cast<TNode<WordT>>(value)));
2648 }
2650 return Unsigned(TimesTaggedSize(implicit_cast<TNode<WordT>>(value)));
2651 }
2652
2653 TNode<WordT> TimesDoubleSize(TNode<WordT> value);
2655 return Unsigned(TimesDoubleSize(implicit_cast<TNode<WordT>>(value)));
2656 }
2658 return Signed(TimesDoubleSize(implicit_cast<TNode<WordT>>(value)));
2659 }
2660
2661 // Type conversions.
2662 // Throws a TypeError for {method_name} if {value} is not coercible to Object,
2663 // or returns the {value} converted to a String otherwise.
2664 TNode<String> ToThisString(TNode<Context> context, TNode<Object> value,
2665 TNode<String> method_name);
2667 char const* method_name) {
2668 return ToThisString(context, value, StringConstant(method_name));
2669 }
2670
2671 // Throws a TypeError for {method_name} if {value} is neither of the given
2672 // {primitive_type} nor a JSPrimitiveWrapper wrapping a value of
2673 // {primitive_type}, or returns the {value} (or wrapped value) otherwise.
2674 TNode<JSAny> ToThisValue(TNode<Context> context, TNode<JSAny> value,
2675 PrimitiveType primitive_type,
2676 char const* method_name);
2677
2678 // Throws a TypeError for {method_name} if {value} is not of the given
2679 // instance type.
2680 void ThrowIfNotInstanceType(TNode<Context> context, TNode<Object> value,
2681 InstanceType instance_type,
2682 char const* method_name);
2683 // Throws a TypeError for {method_name} if {value} is not a JSReceiver.
2684 void ThrowIfNotJSReceiver(TNode<Context> context, TNode<Object> value,
2685 MessageTemplate msg_template,
2686 const char* method_name);
2687 void ThrowIfNotCallable(TNode<Context> context, TNode<Object> value,
2688 const char* method_name);
2689
2690 void ThrowRangeError(TNode<Context> context, MessageTemplate message,
2691 std::optional<TNode<Object>> arg0 = std::nullopt,
2692 std::optional<TNode<Object>> arg1 = std::nullopt,
2693 std::optional<TNode<Object>> arg2 = std::nullopt);
2694 void ThrowTypeError(TNode<Context> context, MessageTemplate message,
2695 char const* arg0 = nullptr, char const* arg1 = nullptr);
2696 void ThrowTypeError(TNode<Context> context, MessageTemplate message,
2697 std::optional<TNode<Object>> arg0,
2698 std::optional<TNode<Object>> arg1 = std::nullopt,
2699 std::optional<TNode<Object>> arg2 = std::nullopt);
2700
2701 void TerminateExecution(TNode<Context> context);
2702
2703 TNode<Union<Hole, JSMessageObject>> GetPendingMessage();
2704 void SetPendingMessage(TNode<Union<Hole, JSMessageObject>> message);
2705 TNode<BoolT> IsExecutionTerminating();
2706
2707 TNode<Object> GetContinuationPreservedEmbedderData();
2708 void SetContinuationPreservedEmbedderData(TNode<Object> value);
2709
2710 // Type checks.
2711 // Check whether the map is for an object with special properties, such as a
2712 // JSProxy or an object with interceptors.
2713 TNode<BoolT> InstanceTypeEqual(TNode<Int32T> instance_type, int type);
2714 TNode<BoolT> IsNoElementsProtectorCellInvalid();
2715 TNode<BoolT> IsMegaDOMProtectorCellInvalid();
2716 TNode<BoolT> IsAlwaysSharedSpaceJSObjectInstanceType(
2717 TNode<Int32T> instance_type);
2718 TNode<BoolT> IsArrayIteratorProtectorCellInvalid();
2719 TNode<BoolT> IsBigIntInstanceType(TNode<Int32T> instance_type);
2720 TNode<BoolT> IsBigInt(TNode<HeapObject> object);
2721 TNode<BoolT> IsBoolean(TNode<HeapObject> object);
2722 TNode<BoolT> IsCallableMap(TNode<Map> map);
2723 TNode<BoolT> IsCallable(TNode<HeapObject> object);
2724 TNode<BoolT> TaggedIsCallable(TNode<Object> object);
2725 TNode<BoolT> IsCode(TNode<HeapObject> object);
2726 TNode<BoolT> TaggedIsCode(TNode<Object> object);
2727 TNode<BoolT> IsConsStringInstanceType(TNode<Int32T> instance_type);
2728 TNode<BoolT> IsConstructorMap(TNode<Map> map);
2729 TNode<BoolT> IsConstructor(TNode<HeapObject> object);
2730 TNode<BoolT> IsDeprecatedMap(TNode<Map> map);
2731 TNode<BoolT> IsPropertyDictionary(TNode<HeapObject> object);
2732 TNode<BoolT> IsOrderedNameDictionary(TNode<HeapObject> object);
2733 TNode<BoolT> IsGlobalDictionary(TNode<HeapObject> object);
2734 TNode<BoolT> IsExtensibleMap(TNode<Map> map);
2735 TNode<BoolT> IsExtensibleNonPrototypeMap(TNode<Map> map);
2736 TNode<BoolT> IsExternalStringInstanceType(TNode<Int32T> instance_type);
2737 TNode<BoolT> IsFixedArray(TNode<HeapObject> object);
2738 TNode<BoolT> IsFixedArraySubclass(TNode<HeapObject> object);
2739 TNode<BoolT> IsFixedArrayWithKind(TNode<HeapObject> object,
2741 TNode<BoolT> IsFixedArrayWithKindOrEmpty(TNode<FixedArrayBase> object,
2743 TNode<BoolT> IsFunctionWithPrototypeSlotMap(TNode<Map> map);
2744 TNode<BoolT> IsHashTable(TNode<HeapObject> object);
2745 TNode<BoolT> IsEphemeronHashTable(TNode<HeapObject> object);
2746 TNode<BoolT> IsHeapNumberInstanceType(TNode<Int32T> instance_type);
2747 // We only want to check for any hole in a negated way. For regular hole
2748 // checks, we should check for a specific hole kind instead.
2749 TNode<BoolT> IsNotAnyHole(TNode<Object> object);
2750 TNode<BoolT> IsHoleInstanceType(TNode<Int32T> instance_type);
2751 TNode<BoolT> IsOddball(TNode<HeapObject> object);
2752 TNode<BoolT> IsOddballInstanceType(TNode<Int32T> instance_type);
2753 TNode<BoolT> IsIndirectStringInstanceType(TNode<Int32T> instance_type);
2754 TNode<BoolT> IsJSArrayBuffer(TNode<HeapObject> object);
2755 TNode<BoolT> IsJSDataView(TNode<HeapObject> object);
2756 TNode<BoolT> IsJSRabGsabDataView(TNode<HeapObject> object);
2757 TNode<BoolT> IsJSArrayInstanceType(TNode<Int32T> instance_type);
2758 TNode<BoolT> IsJSArrayMap(TNode<Map> map);
2759 TNode<BoolT> IsJSArray(TNode<HeapObject> object);
2760 TNode<BoolT> IsJSArrayIterator(TNode<HeapObject> object);
2761 TNode<BoolT> IsJSAsyncGeneratorObject(TNode<HeapObject> object);
2762 TNode<BoolT> IsFunctionInstanceType(TNode<Int32T> instance_type);
2763 TNode<BoolT> IsJSFunctionInstanceType(TNode<Int32T> instance_type);
2764 TNode<BoolT> IsJSFunctionMap(TNode<Map> map);
2765 TNode<BoolT> IsJSFunction(TNode<HeapObject> object);
2766 TNode<BoolT> IsJSBoundFunction(TNode<HeapObject> object);
2767 TNode<BoolT> IsJSGeneratorObject(TNode<HeapObject> object);
2768 TNode<BoolT> IsJSGlobalProxyInstanceType(TNode<Int32T> instance_type);
2769 TNode<BoolT> IsJSGlobalProxyMap(TNode<Map> map);
2770 TNode<BoolT> IsJSGlobalProxy(TNode<HeapObject> object);
2771 TNode<BoolT> IsJSObjectInstanceType(TNode<Int32T> instance_type);
2772 TNode<BoolT> IsJSObjectMap(TNode<Map> map);
2773 TNode<BoolT> IsJSObject(TNode<HeapObject> object);
2774 TNode<BoolT> IsJSApiObjectInstanceType(TNode<Int32T> instance_type);
2775 TNode<BoolT> IsJSApiObjectMap(TNode<Map> map);
2776 TNode<BoolT> IsJSApiObject(TNode<HeapObject> object);
2777 TNode<BoolT> IsJSFinalizationRegistryMap(TNode<Map> map);
2778 TNode<BoolT> IsJSFinalizationRegistry(TNode<HeapObject> object);
2779 TNode<BoolT> IsJSPromiseMap(TNode<Map> map);
2780 TNode<BoolT> IsJSPromise(TNode<HeapObject> object);
2781 TNode<BoolT> IsJSProxy(TNode<HeapObject> object);
2782 TNode<BoolT> IsJSStringIterator(TNode<HeapObject> object);
2783 TNode<BoolT> IsJSShadowRealm(TNode<HeapObject> object);
2784 TNode<BoolT> IsJSRegExpStringIterator(TNode<HeapObject> object);
2785 TNode<BoolT> IsJSReceiverInstanceType(TNode<Int32T> instance_type);
2786 TNode<BoolT> IsJSReceiverMap(TNode<Map> map);
2787 TNode<BoolT> IsJSReceiver(TNode<HeapObject> object);
2788 // The following two methods assume that we deal either with a primitive
2789 // object or a JS receiver.
2790 TNode<BoolT> JSAnyIsNotPrimitiveMap(TNode<Map> map);
2791 TNode<BoolT> JSAnyIsNotPrimitive(TNode<HeapObject> object);
2792 TNode<BoolT> IsJSRegExp(TNode<HeapObject> object);
2793 TNode<BoolT> IsJSTypedArrayInstanceType(TNode<Int32T> instance_type);
2794 TNode<BoolT> IsJSTypedArrayMap(TNode<Map> map);
2795 TNode<BoolT> IsJSTypedArray(TNode<HeapObject> object);
2796 TNode<BoolT> IsJSGeneratorMap(TNode<Map> map);
2797 TNode<BoolT> IsJSPrimitiveWrapperInstanceType(TNode<Int32T> instance_type);
2798 TNode<BoolT> IsJSPrimitiveWrapperMap(TNode<Map> map);
2799 TNode<BoolT> IsJSPrimitiveWrapper(TNode<HeapObject> object);
2800 TNode<BoolT> IsJSSharedArrayInstanceType(TNode<Int32T> instance_type);
2801 TNode<BoolT> IsJSSharedArrayMap(TNode<Map> map);
2802 TNode<BoolT> IsJSSharedArray(TNode<HeapObject> object);
2803 TNode<BoolT> IsJSSharedArray(TNode<Object> object);
2804 TNode<BoolT> IsJSSharedStructInstanceType(TNode<Int32T> instance_type);
2805 TNode<BoolT> IsJSSharedStructMap(TNode<Map> map);
2806 TNode<BoolT> IsJSSharedStruct(TNode<HeapObject> object);
2807 TNode<BoolT> IsJSSharedStruct(TNode<Object> object);
2808 TNode<BoolT> IsJSWrappedFunction(TNode<HeapObject> object);
2809 TNode<BoolT> IsMap(TNode<HeapObject> object);
2810 TNode<BoolT> IsName(TNode<HeapObject> object);
2811 TNode<BoolT> IsNameInstanceType(TNode<Int32T> instance_type);
2812 TNode<BoolT> IsNullOrJSReceiver(TNode<HeapObject> object);
2814 TNode<BoolT> IsNumberDictionary(TNode<HeapObject> object);
2815 TNode<BoolT> IsOneByteStringInstanceType(TNode<Int32T> instance_type);
2816 TNode<BoolT> IsSeqOneByteStringInstanceType(TNode<Int32T> instance_type);
2817 TNode<BoolT> IsPrimitiveInstanceType(TNode<Int32T> instance_type);
2818 TNode<BoolT> IsPrivateName(TNode<Symbol> symbol);
2819 TNode<BoolT> IsPropertyArray(TNode<HeapObject> object);
2820 TNode<BoolT> IsPropertyCell(TNode<HeapObject> object);
2821 TNode<BoolT> IsPromiseReactionJobTask(TNode<HeapObject> object);
2822 TNode<BoolT> IsPrototypeInitialArrayPrototype(TNode<Context> context,
2823 TNode<Map> map);
2824 TNode<BoolT> IsPrototypeTypedArrayPrototype(TNode<Context> context,
2825 TNode<Map> map);
2826
2827 TNode<BoolT> IsFastAliasedArgumentsMap(TNode<Context> context,
2828 TNode<Map> map);
2829 TNode<BoolT> IsSlowAliasedArgumentsMap(TNode<Context> context,
2830 TNode<Map> map);
2831 TNode<BoolT> IsSloppyArgumentsMap(TNode<Context> context, TNode<Map> map);
2832 TNode<BoolT> IsStrictArgumentsMap(TNode<Context> context, TNode<Map> map);
2833
2834 TNode<BoolT> IsSequentialStringInstanceType(TNode<Int32T> instance_type);
2835 TNode<BoolT> IsUncachedExternalStringInstanceType(
2836 TNode<Int32T> instance_type);
2839 TNode<Int32T> instance_type);
2841 TNode<BoolT> IsStringInstanceType(TNode<Int32T> instance_type);
2842 TNode<BoolT> IsString(TNode<HeapObject> object);
2843 TNode<Word32T> IsStringWrapper(TNode<HeapObject> object);
2844 TNode<BoolT> IsSeqOneByteString(TNode<HeapObject> object);
2845 TNode<BoolT> IsSequentialString(TNode<HeapObject> object);
2846
2847 TNode<BoolT> IsSeqOneByteStringMap(TNode<Map> map);
2848 TNode<BoolT> IsSequentialStringMap(TNode<Map> map);
2849 TNode<BoolT> IsExternalStringMap(TNode<Map> map);
2850 TNode<BoolT> IsUncachedExternalStringMap(TNode<Map> map);
2851 TNode<BoolT> IsOneByteStringMap(TNode<Map> map);
2852
2853 TNode<BoolT> IsSymbolInstanceType(TNode<Int32T> instance_type);
2854 TNode<BoolT> IsInternalizedStringInstanceType(TNode<Int32T> instance_type);
2855 TNode<BoolT> IsSharedStringInstanceType(TNode<Int32T> instance_type);
2856 TNode<BoolT> IsTemporalInstantInstanceType(TNode<Int32T> instance_type);
2858 TNode<BoolT> IsUniqueNameNoIndex(TNode<HeapObject> object);
2859 TNode<BoolT> IsUniqueNameNoCachedIndex(TNode<HeapObject> object);
2860 TNode<BoolT> IsUndetectableMap(TNode<Map> map);
2861 TNode<BoolT> IsNotWeakFixedArraySubclass(TNode<HeapObject> object);
2862 TNode<BoolT> IsZeroOrContext(TNode<Object> object);
2863
2864 TNode<BoolT> IsPromiseResolveProtectorCellInvalid();
2865 TNode<BoolT> IsPromiseThenProtectorCellInvalid();
2866 TNode<BoolT> IsArraySpeciesProtectorCellInvalid();
2867 TNode<BoolT> IsIsConcatSpreadableProtectorCellInvalid();
2868 TNode<BoolT> IsTypedArraySpeciesProtectorCellInvalid();
2869 TNode<BoolT> IsRegExpSpeciesProtectorCellInvalid();
2870 TNode<BoolT> IsPromiseSpeciesProtectorCellInvalid();
2871 TNode<BoolT> IsNumberStringNotRegexpLikeProtectorCellInvalid();
2872 TNode<BoolT> IsSetIteratorProtectorCellInvalid();
2873 TNode<BoolT> IsMapIteratorProtectorCellInvalid();
2874 void InvalidateStringWrapperToPrimitiveProtector();
2875
2876 TNode<IntPtrT> LoadMemoryChunkFlags(TNode<HeapObject> object);
2877
2879 TNode<Word32T> flag_value = UncheckedCast<Word32T>(
2880 Load(MachineType::Uint8(), ExternalConstant(address_of_flag)));
2881 return Word32NotEqual(Word32And(flag_value, Int32Constant(0xFF)),
2882 Int32Constant(0));
2883 }
2884
2886 return LoadRuntimeFlag(
2887 ExternalReference::address_of_mock_arraybuffer_allocator_flag());
2888 }
2889
2891 return LoadRuntimeFlag(
2892 ExternalReference::address_of_builtin_subclassing_flag());
2893 }
2894
2896 return LoadRuntimeFlag(
2897 ExternalReference::address_of_shared_string_table_flag());
2898 }
2899
2901 return LoadRuntimeFlag(
2902 ExternalReference::script_context_mutable_heap_number_flag());
2903 }
2904
2906#ifdef SUPPORT_SCRIPT_CONTEXT_MUTABLE_HEAP_INT32
2907 return LoadRuntimeFlag(
2908 ExternalReference::script_context_mutable_heap_int32_flag());
2909#else
2910 return BoolConstant(false);
2911#endif // SUPPORT_SCRIPT_CONTEXT_MUTABLE_HEAP_INT32
2912 }
2913
2915 if (Is64()) {
2916 return LoadRuntimeFlag(
2917 ExternalReference::additive_safe_int_feedback_flag());
2918 } else {
2919 return BoolConstant(false);
2920 }
2921 }
2922
2923 // True iff |object| is a Smi or a HeapNumber or a BigInt.
2925
2926 // True iff |number| is either a Smi, or a HeapNumber whose value is not
2927 // within Smi range.
2928 TNode<BoolT> IsNumberNormalized(TNode<Number> number);
2929 TNode<BoolT> IsNumberPositive(TNode<Number> number);
2930 TNode<BoolT> IsHeapNumberPositive(TNode<HeapNumber> number);
2931
2932 // True iff {number} is non-negative and less or equal than 2**53-1.
2933 TNode<BoolT> IsNumberNonNegativeSafeInteger(TNode<Number> number);
2934
2935 // True iff {number} represents an integer value.
2936 TNode<BoolT> IsInteger(TNode<Object> number);
2937 TNode<BoolT> IsInteger(TNode<HeapNumber> number);
2938
2939 // True iff abs({number}) <= 2**53 -1
2940 TNode<BoolT> IsSafeInteger(TNode<Object> number);
2941 TNode<BoolT> IsSafeInteger(TNode<HeapNumber> number);
2942
2943 // True iff {number} represents a valid uint32t value.
2944 TNode<BoolT> IsHeapNumberUint32(TNode<HeapNumber> number);
2945
2946 // True iff {number} is a positive number and a valid array index in the range
2947 // [0, 2^32-1).
2948 TNode<BoolT> IsNumberArrayIndex(TNode<Number> number);
2949
2950 template <typename TIndex>
2951 TNode<BoolT> FixedArraySizeDoesntFitInNewSpace(TNode<TIndex> element_count,
2952 int base_size);
2953
2954 // ElementsKind helpers:
2956 return Word32Equal(a, b);
2957 }
2958 bool ElementsKindEqual(ElementsKind a, ElementsKind b) { return a == b; }
2967 TNode<BoolT> IsFastOrNonExtensibleOrSealedElementsKind(
2968 TNode<Int32T> elements_kind);
2969
2971 return ElementsKindEqual(elements_kind, Int32Constant(DICTIONARY_ELEMENTS));
2972 }
2977 TNode<BoolT> IsFastSmiOrTaggedElementsKind(TNode<Int32T> elements_kind);
2978 TNode<BoolT> IsFastSmiElementsKind(TNode<Int32T> elements_kind);
2979 TNode<BoolT> IsHoleyFastElementsKind(TNode<Int32T> elements_kind);
2980 TNode<BoolT> IsHoleyFastElementsKindForRead(TNode<Int32T> elements_kind);
2981 TNode<BoolT> IsElementsKindGreaterThan(TNode<Int32T> target_kind,
2982 ElementsKind reference_kind);
2983 TNode<BoolT> IsElementsKindGreaterThanOrEqual(TNode<Int32T> target_kind,
2984 ElementsKind reference_kind);
2985 TNode<BoolT> IsElementsKindLessThanOrEqual(TNode<Int32T> target_kind,
2986 ElementsKind reference_kind);
2987 // Check if lower_reference_kind <= target_kind <= higher_reference_kind.
2989 ElementsKind lower_reference_kind,
2990 ElementsKind higher_reference_kind) {
2991 return IsInRange(target_kind, lower_reference_kind, higher_reference_kind);
2992 }
2993 TNode<Int32T> GetNonRabGsabElementsKind(TNode<Int32T> elements_kind);
2994
2995 // String helpers.
2996 // Load a character from a String (might flatten a ConsString).
2997 TNode<Uint16T> StringCharCodeAt(TNode<String> string, TNode<UintPtrT> index);
2998 // Return the single character string with only {code}.
2999 TNode<String> StringFromSingleCharCode(TNode<Int32T> code);
3000
3001 // Type conversion helpers.
3002 enum class BigIntHandling { kConvertToNumber, kThrow };
3003 // Convert a String to a Number.
3004 TNode<Number> StringToNumber(TNode<String> input);
3005 // Convert a Number to a String.
3006 TNode<String> NumberToString(TNode<Number> input);
3007 TNode<String> NumberToString(TNode<Number> input, Label* bailout);
3008
3009 // Convert a Non-Number object to a Number.
3010 TNode<Number> NonNumberToNumber(
3011 TNode<Context> context, TNode<HeapObject> input,
3012 BigIntHandling bigint_handling = BigIntHandling::kThrow);
3013 // Convert a Non-Number object to a Numeric.
3014 TNode<Numeric> NonNumberToNumeric(TNode<Context> context,
3015 TNode<HeapObject> input);
3016 // Convert any object to a Number.
3017 // Conforms to ES#sec-tonumber if {bigint_handling} == kThrow.
3018 // With {bigint_handling} == kConvertToNumber, matches behavior of
3019 // tc39.github.io/proposal-bigint/#sec-number-constructor-number-value.
3021 TNode<Context> context, TNode<Object> input,
3022 BigIntHandling bigint_handling = BigIntHandling::kThrow);
3023 TNode<Number> ToNumber_Inline(TNode<Context> context, TNode<Object> input);
3024 TNode<Numeric> ToNumberOrNumeric(
3025 LazyNode<Context> context, TNode<Object> input,
3026 TVariable<Smi>* var_type_feedback, Object::Conversion mode,
3027 BigIntHandling bigint_handling = BigIntHandling::kThrow);
3028 // Convert any plain primitive to a Number. No need to handle BigInts since
3029 // they are not plain primitives.
3030 TNode<Number> PlainPrimitiveToNumber(TNode<Object> input);
3031
3032 // Try to convert an object to a BigInt. Throws on failure (e.g. for Numbers).
3033 // https://tc39.github.io/proposal-bigint/#sec-to-bigint
3034 TNode<BigInt> ToBigInt(TNode<Context> context, TNode<Object> input);
3035 // Try to convert any object to a BigInt, including Numbers.
3036 TNode<BigInt> ToBigIntConvertNumber(TNode<Context> context,
3037 TNode<Object> input);
3038
3039 // Converts |input| to one of 2^32 integer values in the range 0 through
3040 // 2^32-1, inclusive.
3041 // ES#sec-touint32
3042 TNode<Number> ToUint32(TNode<Context> context, TNode<Object> input);
3043
3044 // No-op on 32-bit, otherwise zero extend.
3046 CSA_DCHECK(this, Int32GreaterThanOrEqual(input, Int32Constant(0)));
3047 return Signed(ChangeUint32ToWord(input));
3048 }
3049
3050 // Convert any object to a String.
3051 TNode<String> ToString_Inline(TNode<Context> context, TNode<Object> input);
3052
3053 TNode<JSReceiver> ToObject(TNode<Context> context, TNode<Object> input);
3054
3055 // Same as ToObject but avoids the Builtin call if |input| is already a
3056 // JSReceiver.
3057 TNode<JSReceiver> ToObject_Inline(TNode<Context> context,
3058 TNode<Object> input);
3059
3060 // ES6 7.1.15 ToLength, but with inlined fast path.
3061 TNode<Number> ToLength_Inline(TNode<Context> context, TNode<Object> input);
3062
3063 TNode<Object> OrdinaryToPrimitive(TNode<Context> context, TNode<Object> input,
3065
3066 // Returns a node that contains a decoded (unsigned!) value of a bit
3067 // field |BitField| in |word32|. Returns result as an uint32 node.
3068 template <typename BitField>
3070 return DecodeWord32(word32, BitField::kShift, BitField::kMask);
3071 }
3072
3073 // Returns a node that contains a decoded (unsigned!) value of a bit
3074 // field |BitField| in |word|. Returns result as a word-size node.
3075 template <typename BitField>
3077 return DecodeWord(word, BitField::kShift, BitField::kMask);
3078 }
3079
3080 // Returns a node that contains a decoded (unsigned!) value of a bit
3081 // field |BitField| in |word32|. Returns result as a word-size node.
3082 template <typename BitField>
3084 return DecodeWord<BitField>(ChangeUint32ToWord(word32));
3085 }
3086
3087 // Returns a node that contains a decoded (unsigned!) value of a bit
3088 // field |BitField| in |word|. Returns result as an uint32 node.
3089 template <typename BitField>
3091 return UncheckedCast<Uint32T>(
3092 TruncateIntPtrToInt32(Signed(DecodeWord<BitField>(word))));
3093 }
3094
3095 // Decodes an unsigned (!) value from |word32| to an uint32 node.
3096 TNode<Uint32T> DecodeWord32(TNode<Word32T> word32, uint32_t shift,
3097 uint32_t mask);
3098
3099 // Decodes an unsigned (!) value from |word| to a word-size node.
3100 TNode<UintPtrT> DecodeWord(TNode<WordT> word, uint32_t shift, uintptr_t mask);
3101
3102 // Returns a node that contains the updated values of a |BitField|.
3103 template <typename BitField>
3105 bool starts_as_zero = false) {
3106 return UpdateWord32(word, value, BitField::kShift, BitField::kMask,
3107 starts_as_zero);
3108 }
3109
3110 // Returns a node that contains the updated values of a |BitField|.
3111 template <typename BitField>
3113 bool starts_as_zero = false) {
3114 return UpdateWord(word, value, BitField::kShift, BitField::kMask,
3115 starts_as_zero);
3116 }
3117
3118 // Returns a node that contains the updated values of a |BitField|.
3119 template <typename BitField>
3121 bool starts_as_zero = false) {
3122 return UncheckedCast<Uint32T>(
3123 TruncateIntPtrToInt32(Signed(UpdateWord<BitField>(
3124 ChangeUint32ToWord(word), value, starts_as_zero))));
3125 }
3126
3127 // Returns a node that contains the updated values of a |BitField|.
3128 template <typename BitField>
3130 bool starts_as_zero = false) {
3131 return UpdateWord<BitField>(word, ChangeUint32ToWord(value),
3132 starts_as_zero);
3133 }
3134
3135 // Returns a node that contains the updated {value} inside {word} starting
3136 // at {shift} and fitting in {mask}.
3137 TNode<Word32T> UpdateWord32(TNode<Word32T> word, TNode<Uint32T> value,
3138 uint32_t shift, uint32_t mask,
3139 bool starts_as_zero = false);
3140
3141 // Returns a node that contains the updated {value} inside {word} starting
3142 // at {shift} and fitting in {mask}.
3143 TNode<WordT> UpdateWord(TNode<WordT> word, TNode<UintPtrT> value,
3144 uint32_t shift, uintptr_t mask,
3145 bool starts_as_zero = false);
3146
3147 // Returns true if any of the |T|'s bits in given |word32| are set.
3148 template <typename T>
3150 return IsSetWord32(word32, T::kMask);
3151 }
3152
3153 // Returns true if none of the |T|'s bits in given |word32| are set.
3154 template <typename T>
3156 return IsNotSetWord32(word32, T::kMask);
3157 }
3158
3159 // Returns true if any of the mask's bits in given |word32| are set.
3161 return Word32NotEqual(Word32And(word32, Int32Constant(mask)),
3162 Int32Constant(0));
3163 }
3164
3165 // Returns true if none of the mask's bits in given |word32| are set.
3167 return Word32Equal(Word32And(word32, Int32Constant(mask)),
3168 Int32Constant(0));
3169 }
3170
3171 // Returns true if all of the mask's bits in a given |word32| are set.
3173 TNode<Int32T> const_mask = Int32Constant(mask);
3174 return Word32Equal(Word32And(word32, const_mask), const_mask);
3175 }
3176
3177 // Returns true if the bit field |BitField| in |word32| is equal to a given
3178 // constant |value|. Avoids a shift compared to using DecodeWord32.
3179 template <typename BitField>
3181 typename BitField::FieldType value) {
3182 TNode<Word32T> masked_word32 =
3183 Word32And(word32, Int32Constant(BitField::kMask));
3184 return Word32Equal(masked_word32, Int32Constant(BitField::encode(value)));
3185 }
3186
3187 // Checks if two values of non-overlapping bitfields are both set.
3188 template <typename BitField1, typename BitField2>
3190 typename BitField1::FieldType value1,
3191 typename BitField2::FieldType value2) {
3192 static_assert((BitField1::kMask & BitField2::kMask) == 0);
3193 TNode<Word32T> combined_masked_word32 =
3194 Word32And(word32, Int32Constant(BitField1::kMask | BitField2::kMask));
3195 TNode<Int32T> combined_value =
3196 Int32Constant(BitField1::encode(value1) | BitField2::encode(value2));
3197 return Word32Equal(combined_masked_word32, combined_value);
3198 }
3199
3200 // Returns true if the bit field |BitField| in |word32| is not equal to a
3201 // given constant |value|. Avoids a shift compared to using DecodeWord32.
3202 template <typename BitField>
3204 typename BitField::FieldType value) {
3205 return Word32BinaryNot(IsEqualInWord32<BitField>(word32, value));
3206 }
3207
3208 // Returns true if any of the |T|'s bits in given |word| are set.
3209 template <typename T>
3211 return IsSetWord(word, T::kMask);
3212 }
3213
3214 // Returns true if any of the mask's bits in given |word| are set.
3216 return WordNotEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
3217 }
3218
3219 // Returns true if any of the mask's bit are set in the given Smi.
3220 // Smi-encoding of the mask is performed implicitly!
3221 TNode<BoolT> IsSetSmi(TNode<Smi> smi, int untagged_mask) {
3222 intptr_t mask_word = base::bit_cast<intptr_t>(Smi::FromInt(untagged_mask));
3223 return WordNotEqual(WordAnd(BitcastTaggedToWordForTagAndSmiBits(smi),
3224 IntPtrConstant(mask_word)),
3225 IntPtrConstant(0));
3226 }
3227
3228 // Returns true if all of the |T|'s bits in given |word32| are clear.
3229 template <typename T>
3231 return IsClearWord32(word32, T::kMask);
3232 }
3233
3234 // Returns true if all of the mask's bits in given |word32| are clear.
3236 return Word32Equal(Word32And(word32, Int32Constant(mask)),
3237 Int32Constant(0));
3238 }
3239
3240 // Returns true if all of the |T|'s bits in given |word| are clear.
3241 template <typename T>
3243 return IsClearWord(word, T::kMask);
3244 }
3245
3246 // Returns true if all of the mask's bits in given |word| are clear.
3248 return IntPtrEqual(WordAnd(word, IntPtrConstant(mask)), IntPtrConstant(0));
3249 }
3250
3251 void SetCounter(StatsCounter* counter, int value);
3252 void IncrementCounter(StatsCounter* counter, int delta);
3253 void DecrementCounter(StatsCounter* counter, int delta);
3254
3255 template <typename TIndex>
3256 void Increment(TVariable<TIndex>* variable, int value = 1);
3257
3258 template <typename TIndex>
3259 void Decrement(TVariable<TIndex>* variable, int value = 1) {
3260 Increment(variable, -value);
3261 }
3262
3263 // Generates "if (false) goto label" code. Useful for marking a label as
3264 // "live" to avoid assertion failures during graph building. In the resulting
3265 // code this check will be eliminated.
3266 void Use(Label* label);
3267
3268 // Various building blocks for stubs doing property lookups.
3269
3270 // |if_notinternalized| is optional; |if_bailout| will be used by default.
3271 // Note: If |key| does not yet have a hash, |if_notinternalized| will be taken
3272 // even if |key| is an array index. |if_keyisunique| will never
3273 // be taken for array indices.
3274 void TryToName(TNode<Object> key, Label* if_keyisindex,
3275 TVariable<IntPtrT>* var_index, Label* if_keyisunique,
3276 TVariable<Name>* var_unique, Label* if_bailout,
3277 Label* if_notinternalized = nullptr);
3278
3279 // Call non-allocating runtime String::WriteToFlat using fast C-calls.
3280 void StringWriteToFlatOneByte(TNode<String> source, TNode<RawPtrT> sink,
3282 void StringWriteToFlatTwoByte(TNode<String> source, TNode<RawPtrT> sink,
3284
3285 // Calls External{One,Two}ByteString::GetChars with a fast C-call.
3286 TNode<RawPtr<Uint8T>> ExternalOneByteStringGetChars(
3288 TNode<RawPtr<Uint16T>> ExternalTwoByteStringGetChars(
3290
3291 TNode<RawPtr<Uint8T>> IntlAsciiCollationWeightsL1();
3292 TNode<RawPtr<Uint8T>> IntlAsciiCollationWeightsL3();
3293
3294 // Performs a hash computation and string table lookup for the given string,
3295 // and jumps to:
3296 // - |if_index| if the string is an array index like "123"; |var_index|
3297 // will contain the intptr representation of that index.
3298 // - |if_internalized| if the string exists in the string table; the
3299 // internalized version will be in |var_internalized|.
3300 // - |if_not_internalized| if the string is not in the string table (but
3301 // does not add it).
3302 // - |if_bailout| for unsupported cases (e.g. uncachable array index).
3303 void TryInternalizeString(TNode<String> string, Label* if_index,
3304 TVariable<IntPtrT>* var_index,
3305 Label* if_internalized,
3306 TVariable<Name>* var_internalized,
3307 Label* if_not_internalized, Label* if_bailout);
3308
3309 // Calculates array index for given dictionary entry and entry field.
3310 // See Dictionary::EntryToIndex().
3311 template <typename Dictionary>
3312 TNode<IntPtrT> EntryToIndex(TNode<IntPtrT> entry, int field_index);
3313 template <typename Dictionary>
3315 return EntryToIndex<Dictionary>(entry, Dictionary::kEntryKeyIndex);
3316 }
3317
3318 // Loads the details for the entry with the given key_index.
3319 // Returns an untagged int32.
3320 template <class ContainerType>
3321 TNode<Uint32T> LoadDetailsByKeyIndex(TNode<ContainerType> container,
3322 TNode<IntPtrT> key_index);
3323
3324 // Loads the value for the entry with the given key_index.
3325 // Returns a tagged value.
3326 template <class ContainerType>
3327 TNode<Object> LoadValueByKeyIndex(TNode<ContainerType> container,
3328 TNode<IntPtrT> key_index);
3329
3330 // Stores the details for the entry with the given key_index.
3331 // |details| must be a Smi.
3332 template <class ContainerType>
3333 void StoreDetailsByKeyIndex(TNode<ContainerType> container,
3334 TNode<IntPtrT> key_index, TNode<Smi> details);
3335
3336 // Stores the value for the entry with the given key_index.
3337 template <class ContainerType>
3338 void StoreValueByKeyIndex(
3339 TNode<ContainerType> container, TNode<IntPtrT> key_index,
3340 TNode<Object> value,
3341 WriteBarrierMode write_barrier = UPDATE_WRITE_BARRIER);
3342
3343 // Calculate a valid size for the a hash table.
3344 TNode<IntPtrT> HashTableComputeCapacity(TNode<IntPtrT> at_least_space_for);
3345
3346 TNode<IntPtrT> NameToIndexHashTableLookup(TNode<NameToIndexHashTable> table,
3347 TNode<Name> name, Label* not_found);
3348
3349 template <class Dictionary>
3350 TNode<Smi> GetNumberOfElements(TNode<Dictionary> dictionary);
3351
3353 TNode<NumberDictionary> dictionary) {
3354 return GetNumberOfElements<NumberDictionary>(dictionary);
3355 }
3356
3357 template <class Dictionary>
3359 TNode<Smi> num_elements_smi) {
3360 // Not supposed to be used for SwissNameDictionary.
3361 static_assert(!(std::is_same<Dictionary, SwissNameDictionary>::value));
3362
3363 StoreFixedArrayElement(dictionary, Dictionary::kNumberOfElementsIndex,
3364 num_elements_smi, SKIP_WRITE_BARRIER);
3365 }
3366
3367 template <class Dictionary>
3369 // Not supposed to be used for SwissNameDictionary.
3370 static_assert(!(std::is_same<Dictionary, SwissNameDictionary>::value));
3371
3372 return CAST(LoadFixedArrayElement(
3373 dictionary, Dictionary::kNumberOfDeletedElementsIndex));
3374 }
3375
3376 template <class Dictionary>
3378 TNode<Smi> num_deleted_smi) {
3379 // Not supposed to be used for SwissNameDictionary.
3380 static_assert(!(std::is_same<Dictionary, SwissNameDictionary>::value));
3381
3382 StoreFixedArrayElement(dictionary,
3383 Dictionary::kNumberOfDeletedElementsIndex,
3384 num_deleted_smi, SKIP_WRITE_BARRIER);
3385 }
3386
3387 template <class Dictionary>
3389 // Not supposed to be used for SwissNameDictionary.
3390 static_assert(!(std::is_same<Dictionary, SwissNameDictionary>::value));
3391
3392 return CAST(
3393 UnsafeLoadFixedArrayElement(dictionary, Dictionary::kCapacityIndex));
3394 }
3395
3396 template <class Dictionary>
3398 return CAST(LoadFixedArrayElement(dictionary,
3399 Dictionary::kNextEnumerationIndexIndex));
3400 }
3401
3402 template <class Dictionary>
3404 TNode<Smi> next_enum_index_smi) {
3405 StoreFixedArrayElement(dictionary, Dictionary::kNextEnumerationIndexIndex,
3406 next_enum_index_smi, SKIP_WRITE_BARRIER);
3407 }
3408
3409 template <class Dictionary>
3411 template <class Dictionary>
3413
3417 kFindExistingOrInsertionIndex
3419
3420 template <typename Dictionary>
3422
3423 // Looks up an entry in a NameDictionaryBase successor.
3424 // If the entry is found control goes to {if_found} and {var_name_index}
3425 // contains an index of the key field of the entry found.
3426 // If the key is not found control goes to {if_not_found}. If mode is
3427 // {kFindExisting}, {var_name_index} might contain garbage, otherwise
3428 // {var_name_index} contains the index of the key field to insert the given
3429 // name at.
3430 template <typename Dictionary>
3431 void NameDictionaryLookup(TNode<Dictionary> dictionary,
3432 TNode<Name> unique_name, Label* if_found,
3433 TVariable<IntPtrT>* var_name_index,
3434 Label* if_not_found,
3435 LookupMode mode = kFindExisting);
3436 // Slow lookup for unique_names with forwarding index.
3437 // Both resolving the actual hash and the lookup are handled via runtime.
3438 template <typename Dictionary>
3439 void NameDictionaryLookupWithForwardIndex(TNode<Dictionary> dictionary,
3440 TNode<Name> unique_name,
3441 Label* if_found,
3442 TVariable<IntPtrT>* var_name_index,
3443 Label* if_not_found,
3444 LookupMode mode = kFindExisting);
3445
3447
3448 // Looks up an entry in a NameDictionaryBase successor. If the entry is found
3449 // control goes to {if_found} and {var_name_index} contains an index of the
3450 // key field of the entry found. If the key is not found control goes to
3451 // {if_not_found}.
3452 void NumberDictionaryLookup(TNode<NumberDictionary> dictionary,
3453 TNode<IntPtrT> intptr_index, Label* if_found,
3454 TVariable<IntPtrT>* var_entry,
3455 Label* if_not_found);
3456
3457 TNode<JSAny> BasicLoadNumberDictionaryElement(
3458 TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
3459 Label* not_data, Label* if_hole);
3460
3461 template <class Dictionary>
3462 void FindInsertionEntry(TNode<Dictionary> dictionary, TNode<Name> key,
3463 TVariable<IntPtrT>* var_key_index);
3464
3465 template <class Dictionary>
3466 void InsertEntry(TNode<Dictionary> dictionary, TNode<Name> key,
3467 TNode<Object> value, TNode<IntPtrT> index,
3468 TNode<Smi> enum_index);
3469
3470 template <class Dictionary>
3471 void AddToDictionary(
3473 Label* bailout,
3474 std::optional<TNode<IntPtrT>> insertion_index = std::nullopt);
3475
3476 // Tries to check if {object} has own {unique_name} property.
3477 void TryHasOwnProperty(TNode<HeapObject> object, TNode<Map> map,
3478 TNode<Int32T> instance_type, TNode<Name> unique_name,
3479 Label* if_found, Label* if_not_found,
3480 Label* if_bailout);
3481
3482 // Operating mode for TryGetOwnProperty and CallGetterIfAccessor
3484 // kCallJSGetterDontUseCachedName is used when we want to get the result of
3485 // the getter call, and don't use cached_name_property when the getter is
3486 // the function template and it has cached_property_name, which would just
3487 // bailout for the IC system to create a named property handler
3489 // kCallJSGetterUseCachedName is used when we want to get the result of
3490 // the getter call, and use cached_name_property when the getter is
3491 // the function template and it has cached_property_name, which would call
3492 // GetProperty rather than bailout for Generic/NoFeedback load
3494 // kReturnAccessorPair is used when we're only getting the property
3495 // descriptor
3496 kReturnAccessorPair
3498 // Receiver handling mode for TryGetOwnProperty and CallGetterIfAccessor.
3500 // The receiver is guaranteed to be JSReceiver, no conversion is necessary
3501 // in case a function callback template has to be called.
3503 // The receiver can be anything, it has to be converted to JSReceiver
3504 // in case a function callback template has to be called.
3506 };
3507 // Tries to get {object}'s own {unique_name} property value. If the property
3508 // is an accessor then it also calls a getter. If the property is a double
3509 // field it re-wraps value in an immutable heap number. {unique_name} must be
3510 // a unique name (Symbol or InternalizedString) that is not an array index.
3511 void TryGetOwnProperty(
3513 TNode<Map> map, TNode<Int32T> instance_type, TNode<Name> unique_name,
3514 Label* if_found_value, TVariable<Object>* var_value, Label* if_not_found,
3515 Label* if_bailout,
3516 ExpectedReceiverMode expected_receiver_mode = kExpectingAnyReceiver);
3517 void TryGetOwnProperty(
3519 TNode<Map> map, TNode<Int32T> instance_type, TNode<Name> unique_name,
3520 Label* if_found_value, TVariable<Object>* var_value,
3521 TVariable<Uint32T>* var_details, TVariable<Object>* var_raw_value,
3522 Label* if_not_found, Label* if_bailout, GetOwnPropertyMode mode,
3523 ExpectedReceiverMode expected_receiver_mode = kExpectingAnyReceiver);
3524
3525 TNode<PropertyDescriptorObject> AllocatePropertyDescriptorObject(
3526 TNode<Context> context);
3527 void InitializePropertyDescriptorObject(
3529 TNode<Uint32T> details, Label* if_bailout);
3530
3532 Handle<Name> name) {
3533 return GetProperty(context, receiver, HeapConstantNoHole(name));
3534 }
3535
3537 TNode<Object> name) {
3538 return CallBuiltin<JSAny>(Builtin::kGetProperty, context, receiver, name);
3539 }
3540
3541 TNode<BoolT> IsInterestingProperty(TNode<Name> name);
3542 TNode<JSAny> GetInterestingProperty(TNode<Context> context,
3544 TNode<Name> name, Label* if_not_found);
3545 TNode<JSAny> GetInterestingProperty(TNode<Context> context,
3547 TVariable<JSAnyNotSmi>* var_holder,
3548 TVariable<Map>* var_holder_map,
3549 TNode<Name> name, Label* if_not_found);
3550
3553 return CallBuiltin(Builtin::kSetProperty, context, receiver, key, value);
3554 }
3555
3558 TNode<Object> value) {
3559 return CallBuiltin(Builtin::kCreateDataProperty, context, receiver, key,
3560 value);
3561 }
3562
3563 TNode<JSAny> GetMethod(TNode<Context> context, TNode<JSAny> object,
3564 Handle<Name> name, Label* if_null_or_undefined);
3565
3566 TNode<JSAny> GetIteratorMethod(TNode<Context> context,
3567 TNode<JSAnyNotSmi> heap_obj,
3568 Label* if_iteratorundefined);
3569
3570 TNode<JSAny> CreateAsyncFromSyncIterator(TNode<Context> context,
3571 TNode<JSAny> sync_iterator);
3572 TNode<JSObject> CreateAsyncFromSyncIterator(TNode<Context> context,
3573 TNode<JSReceiver> sync_iterator,
3574 TNode<Object> next);
3575
3576 void LoadPropertyFromFastObject(TNode<HeapObject> object, TNode<Map> map,
3577 TNode<DescriptorArray> descriptors,
3578 TNode<IntPtrT> name_index,
3579 TVariable<Uint32T>* var_details,
3580 TVariable<Object>* var_value);
3581
3582 void LoadPropertyFromFastObject(TNode<HeapObject> object, TNode<Map> map,
3583 TNode<DescriptorArray> descriptors,
3584 TNode<IntPtrT> name_index, TNode<Uint32T>,
3585 TVariable<Object>* var_value);
3586
3587 template <typename Dictionary>
3588 void LoadPropertyFromDictionary(TNode<Dictionary> dictionary,
3589 TNode<IntPtrT> name_index,
3590 TVariable<Uint32T>* var_details,
3591 TVariable<Object>* var_value);
3592 void LoadPropertyFromGlobalDictionary(TNode<GlobalDictionary> dictionary,
3593 TNode<IntPtrT> name_index,
3594 TVariable<Uint32T>* var_details,
3595 TVariable<Object>* var_value,
3596 Label* if_deleted);
3597
3598 // Generic property lookup generator. If the {object} is fast and
3599 // {unique_name} property is found then the control goes to {if_found_fast}
3600 // label and {var_meta_storage} and {var_name_index} will contain
3601 // DescriptorArray and an index of the descriptor's name respectively.
3602 // If the {object} is slow or global then the control goes to {if_found_dict}
3603 // or {if_found_global} and the {var_meta_storage} and {var_name_index} will
3604 // contain a dictionary and an index of the key field of the found entry.
3605 // If property is not found or given lookup is not supported then
3606 // the control goes to {if_not_found} or {if_bailout} respectively.
3607 //
3608 // Note: this code does not check if the global dictionary points to deleted
3609 // entry! This has to be done by the caller.
3610 void TryLookupProperty(TNode<HeapObject> object, TNode<Map> map,
3611 TNode<Int32T> instance_type, TNode<Name> unique_name,
3612 Label* if_found_fast, Label* if_found_dict,
3613 Label* if_found_global,
3614 TVariable<HeapObject>* var_meta_storage,
3615 TVariable<IntPtrT>* var_name_index,
3616 Label* if_not_found, Label* if_bailout);
3617
3618 // This is a building block for TryLookupProperty() above. Supports only
3619 // non-special fast and dictionary objects.
3620 // TODO(v8:11167, v8:11177) |bailout| only needed for SetDataProperties
3621 // workaround.
3622 void TryLookupPropertyInSimpleObject(TNode<JSObject> object, TNode<Map> map,
3623 TNode<Name> unique_name,
3624 Label* if_found_fast,
3625 Label* if_found_dict,
3626 TVariable<HeapObject>* var_meta_storage,
3627 TVariable<IntPtrT>* var_name_index,
3628 Label* if_not_found, Label* bailout);
3629
3630 // This method jumps to if_found if the element is known to exist. To
3631 // if_absent if it's known to not exist. To if_not_found if the prototype
3632 // chain needs to be checked. And if_bailout if the lookup is unsupported.
3633 void TryLookupElement(TNode<HeapObject> object, TNode<Map> map,
3634 TNode<Int32T> instance_type,
3635 TNode<IntPtrT> intptr_index, Label* if_found,
3636 Label* if_absent, Label* if_not_found,
3637 Label* if_bailout);
3638
3639 // For integer indexed exotic cases, check if the given string cannot be a
3640 // special index. If we are not sure that the given string is not a special
3641 // index with a simple check, return False. Note that "False" return value
3642 // does not mean that the name_string is a special index in the current
3643 // implementation.
3644 void BranchIfMaybeSpecialIndex(TNode<String> name_string,
3645 Label* if_maybe_special_index,
3646 Label* if_not_special_index);
3647
3648 // This is a type of a lookup property in holder generator function. The {key}
3649 // is guaranteed to be an unique name.
3650 using LookupPropertyInHolder = std::function<void(
3652 TNode<Int32T> instance_type, TNode<Name> key, Label* next_holder,
3653 Label* if_bailout)>;
3654
3655 // This is a type of a lookup element in holder generator function. The {key}
3656 // is an Int32 index.
3657 using LookupElementInHolder = std::function<void(
3659 TNode<Int32T> instance_type, TNode<IntPtrT> key, Label* next_holder,
3660 Label* if_bailout)>;
3661
3662 // Generic property prototype chain lookup generator.
3663 // For properties it generates lookup using given {lookup_property_in_holder}
3664 // and for elements it uses {lookup_element_in_holder}.
3665 // Upon reaching the end of prototype chain the control goes to {if_end}.
3666 // If it can't handle the case {receiver}/{key} case then the control goes
3667 // to {if_bailout}.
3668 // If {if_proxy} is nullptr, proxies go to if_bailout.
3669 void TryPrototypeChainLookup(
3671 const LookupPropertyInHolder& lookup_property_in_holder,
3672 const LookupElementInHolder& lookup_element_in_holder, Label* if_end,
3673 Label* if_bailout, Label* if_proxy, bool handle_private_names = false);
3674
3675 // Instanceof helpers.
3676 // Returns true if {object} has {prototype} somewhere in it's prototype
3677 // chain, otherwise false is returned. Might cause arbitrary side effects
3678 // due to [[GetPrototypeOf]] invocations.
3679 TNode<Boolean> HasInPrototypeChain(TNode<Context> context,
3680 TNode<HeapObject> object,
3681 TNode<Object> prototype);
3682 // ES6 section 7.3.19 OrdinaryHasInstance (C, O)
3683 TNode<Boolean> OrdinaryHasInstance(TNode<Context> context,
3684 TNode<Object> callable,
3685 TNode<Object> object);
3686
3687 TNode<BytecodeArray> LoadBytecodeArrayFromBaseline();
3688
3689 // Load type feedback vector from the stub caller's frame.
3690 TNode<FeedbackVector> LoadFeedbackVectorForStub();
3691 TNode<FeedbackVector> LoadFeedbackVectorFromBaseline();
3692 TNode<Context> LoadContextFromBaseline();
3693 // Load type feedback vector from the stub caller's frame, skipping an
3694 // intermediate trampoline frame.
3695 TNode<FeedbackVector> LoadFeedbackVectorForStubWithTrampoline();
3696
3697 // Load the value from closure's feedback cell.
3698 TNode<HeapObject> LoadFeedbackCellValue(TNode<JSFunction> closure);
3699
3700 // Load the object from feedback vector cell for the given closure.
3701 // The returned object could be undefined if the closure does not have
3702 // a feedback vector associated with it.
3703 TNode<HeapObject> LoadFeedbackVector(TNode<JSFunction> closure);
3704 TNode<FeedbackVector> LoadFeedbackVector(TNode<JSFunction> closure,
3705 Label* if_no_feedback_vector);
3706
3707 // Load the ClosureFeedbackCellArray that contains the feedback cells
3708 // used when creating closures from this function. This array could be
3709 // directly hanging off the FeedbackCell when there is no feedback vector
3710 // or available from the feedback vector's header.
3711 TNode<ClosureFeedbackCellArray> LoadClosureFeedbackArray(
3712 TNode<JSFunction> closure);
3713
3714 // Update the type feedback vector.
3716 return a == b;
3717 }
3718 void UpdateFeedback(TNode<Smi> feedback,
3719 TNode<HeapObject> maybe_feedback_vector,
3720 TNode<UintPtrT> slot_id, UpdateFeedbackMode mode);
3721 void UpdateFeedback(TNode<Smi> feedback,
3722 TNode<FeedbackVector> feedback_vector,
3723 TNode<UintPtrT> slot_id);
3724 void MaybeUpdateFeedback(TNode<Smi> feedback,
3725 TNode<HeapObject> maybe_feedback_vector,
3726 TNode<UintPtrT> slot_id);
3727
3728 // Report that there was a feedback update, performing any tasks that should
3729 // be done after a feedback update.
3730 void ReportFeedbackUpdate(TNode<FeedbackVector> feedback_vector,
3731 TNode<UintPtrT> slot_id, const char* reason);
3732
3733 // Combine the new feedback with the existing_feedback. Do nothing if
3734 // existing_feedback is nullptr.
3735 void CombineFeedback(TVariable<Smi>* existing_feedback, int feedback);
3736 void CombineFeedback(TVariable<Smi>* existing_feedback, TNode<Smi> feedback);
3737
3738 // Overwrite the existing feedback with new_feedback. Do nothing if
3739 // existing_feedback is nullptr.
3740 void OverwriteFeedback(TVariable<Smi>* existing_feedback, int new_feedback);
3741
3742 // Check if a property name might require protector invalidation when it is
3743 // used for a property store or deletion.
3744 void CheckForAssociatedProtector(TNode<Name> name, Label* if_protector);
3745
3746 TNode<Map> LoadReceiverMap(TNode<Object> receiver);
3747
3748 // Loads script context from the script context table.
3749 TNode<Context> LoadScriptContext(TNode<Context> context,
3750 TNode<IntPtrT> context_index);
3751
3752 TNode<Uint8T> Int32ToUint8Clamped(TNode<Int32T> int32_value);
3753 TNode<Uint8T> Float64ToUint8Clamped(TNode<Float64T> float64_value);
3754
3755 template <typename T>
3757 ElementsKind elements_kind,
3758 TNode<Context> context);
3759
3760 // Store value to an elements array with given elements kind.
3761 // TODO(turbofan): For BIGINT64_ELEMENTS and BIGUINT64_ELEMENTS
3762 // we pass {value} as BigInt object instead of int64_t. We should
3763 // teach TurboFan to handle int64_t on 32-bit platforms eventually.
3764 template <typename TIndex, typename TValue>
3765 void StoreElement(TNode<RawPtrT> elements, ElementsKind kind,
3766 TNode<TIndex> index, TNode<TValue> value);
3767
3768 // Implements the BigInt part of
3769 // https://tc39.github.io/proposal-bigint/#sec-numbertorawbytes,
3770 // including truncation to 64 bits (i.e. modulo 2^64).
3771 // {var_high} is only used on 32-bit platforms.
3772 void BigIntToRawBytes(TNode<BigInt> bigint, TVariable<UintPtrT>* var_low,
3773 TVariable<UintPtrT>* var_high);
3774
3775#if V8_ENABLE_WEBASSEMBLY
3776 TorqueStructInt64AsInt32Pair BigIntToRawBytes(TNode<BigInt> value);
3777#endif // V8_ENABLE_WEBASSEMBLY
3778
3779 void EmitElementStore(TNode<JSObject> object, TNode<Object> key,
3780 TNode<Object> value, ElementsKind elements_kind,
3781 KeyedAccessStoreMode store_mode, Label* bailout,
3782 TNode<Context> context,
3783 TVariable<Object>* maybe_converted_value = nullptr);
3784
3785 TNode<FixedArrayBase> CheckForCapacityGrow(
3787 TNode<UintPtrT> length, TNode<IntPtrT> key, Label* bailout);
3788
3789 TNode<FixedArrayBase> CopyElementsOnWrite(TNode<HeapObject> object,
3790 TNode<FixedArrayBase> elements,
3792 TNode<IntPtrT> length,
3793 Label* bailout);
3794
3795 void TransitionElementsKind(TNode<JSObject> object, TNode<Map> map,
3796 ElementsKind from_kind, ElementsKind to_kind,
3797 Label* bailout);
3798
3799 void TrapAllocationMemento(TNode<JSObject> object, Label* memento_found);
3800
3801 // Helpers to look up Page metadata for a given address.
3802 // Equivalent to MemoryChunk::FromAddress().
3803 TNode<IntPtrT> MemoryChunkFromAddress(TNode<IntPtrT> address);
3804 // Equivalent to MemoryChunk::MutablePageMetadata().
3805 TNode<IntPtrT> PageMetadataFromMemoryChunk(TNode<IntPtrT> address);
3806 // Equivalent to MemoryChunkMetadata::FromAddress().
3807 TNode<IntPtrT> PageMetadataFromAddress(TNode<IntPtrT> address);
3808
3809 // Store a weak in-place reference into the FeedbackVector.
3810 TNode<MaybeObject> StoreWeakReferenceInFeedbackVector(
3811 TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot,
3812 TNode<HeapObject> value, int additional_offset = 0);
3813
3814 // Create a new AllocationSite and install it into a feedback vector.
3815 TNode<AllocationSite> CreateAllocationSiteInFeedbackVector(
3816 TNode<FeedbackVector> feedback_vector, TNode<UintPtrT> slot);
3817
3818 TNode<BoolT> HasBoilerplate(TNode<Object> maybe_literal_site);
3819 TNode<Smi> LoadTransitionInfo(TNode<AllocationSite> allocation_site);
3820 TNode<JSObject> LoadBoilerplate(TNode<AllocationSite> allocation_site);
3821 TNode<Int32T> LoadElementsKind(TNode<AllocationSite> allocation_site);
3822 TNode<Object> LoadNestedAllocationSite(TNode<AllocationSite> allocation_site);
3823
3825 return LoadObjectField<Object>(accessor_pair,
3826 offsetof(AccessorPair, getter_));
3827 }
3829 return LoadObjectField<Object>(accessor_pair,
3830 offsetof(AccessorPair, setter_));
3831 }
3832
3833 enum class IndexAdvanceMode { kPre, kPost };
3834 enum class IndexAdvanceDirection { kUp, kDown };
3835 enum class LoopUnrollingMode { kNo, kYes };
3836
3837 template <typename TIndex>
3838 using FastLoopBody = std::function<void(TNode<TIndex> index)>;
3839
3840 template <typename TIndex>
3841 void BuildFastLoop(const VariableList& vars, TVariable<TIndex>& var_index,
3842 TNode<TIndex> start_index, TNode<TIndex> end_index,
3844 LoopUnrollingMode unrolling_mode,
3845 IndexAdvanceMode advance_mode,
3846 IndexAdvanceDirection advance_direction);
3847
3848 template <typename TIndex>
3849 void BuildFastLoop(const VariableList& vars, TVariable<TIndex>& var_index,
3850 TNode<TIndex> start_index, TNode<TIndex> end_index,
3851 const FastLoopBody<TIndex>& body, int increment,
3852 LoopUnrollingMode unrolling_mode,
3853 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre);
3854
3855 template <typename TIndex>
3856 void BuildFastLoop(TVariable<TIndex>& var_index, TNode<TIndex> start_index,
3857 TNode<TIndex> end_index, const FastLoopBody<TIndex>& body,
3858 int increment, LoopUnrollingMode unrolling_mode,
3859 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre) {
3860 BuildFastLoop(VariableList(0, zone()), var_index, start_index, end_index,
3861 body, increment, unrolling_mode, advance_mode);
3862 }
3863
3864 template <typename TIndex>
3865 void BuildFastLoop(const VariableList& vars, TNode<TIndex> start_index,
3866 TNode<TIndex> end_index, const FastLoopBody<TIndex>& body,
3867 int increment, LoopUnrollingMode unrolling_mode,
3868 IndexAdvanceMode advance_mode) {
3869 TVARIABLE(TIndex, var_index);
3870 BuildFastLoop(vars, var_index, start_index, end_index, body, increment,
3871 unrolling_mode, advance_mode);
3872 }
3873
3874 template <typename TIndex>
3875 void BuildFastLoop(TNode<TIndex> start_index, TNode<TIndex> end_index,
3876 const FastLoopBody<TIndex>& body, int increment,
3877 LoopUnrollingMode unrolling_mode,
3878 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPre) {
3879 BuildFastLoop(VariableList(0, zone()), start_index, end_index, body,
3880 increment, unrolling_mode, advance_mode);
3881 }
3882
3883 enum class ForEachDirection { kForward, kReverse };
3884
3886 std::function<void(TNode<HeapObject> array, TNode<IntPtrT> offset)>;
3887
3888 template <typename TIndex>
3891 ElementsKind kind, TNode<TIndex> first_element_inclusive,
3892 TNode<TIndex> last_element_exclusive, const FastArrayForEachBody& body,
3893 LoopUnrollingMode loop_unrolling_mode,
3894 ForEachDirection direction = ForEachDirection::kReverse);
3895
3896 template <typename TIndex>
3898 ElementsKind kind, int header_size) {
3899 return ElementOffsetFromIndex(element_count, kind, header_size);
3900 }
3901
3902 template <typename TIndex>
3905 return GetArrayAllocationSize(element_count, kind,
3907 }
3908
3910 return GetArrayAllocationSize(element_count, PACKED_ELEMENTS,
3911 PropertyArray::kHeaderSize);
3912 }
3913
3914 template <typename TIndex>
3915 void GotoIfFixedArraySizeDoesntFitInNewSpace(TNode<TIndex> element_count,
3916 Label* doesnt_fit,
3917 int base_size);
3918
3919 void InitializeFieldsWithRoot(TNode<HeapObject> object,
3920 TNode<IntPtrT> start_offset,
3921 TNode<IntPtrT> end_offset, RootIndex root);
3922
3923 // Goto the given |target| if the context chain starting at |context| has any
3924 // extensions up to the given |depth|. Returns the Context with the
3925 // extensions if there was one, otherwise returns the Context at the given
3926 // |depth|.
3927 TNode<Context> GotoIfHasContextExtensionUpToDepth(TNode<Context> context,
3928 TNode<Uint32T> depth,
3929 Label* target);
3930
3932 Operation op, TNode<Object> left, TNode<Object> right,
3933 TNode<Context> context, TVariable<Smi>* var_type_feedback = nullptr) {
3934 return RelationalComparison(
3935 op, left, right, [=]() { return context; }, var_type_feedback);
3936 }
3937
3938 TNode<Boolean> RelationalComparison(
3939 Operation op, TNode<Object> left, TNode<Object> right,
3940 const LazyNode<Context>& context,
3941 TVariable<Smi>* var_type_feedback = nullptr);
3942
3943 void BranchIfNumberRelationalComparison(Operation op, TNode<Number> left,
3944 TNode<Number> right, Label* if_true,
3945 Label* if_false);
3946
3948 Label* if_true, Label* if_false) {
3949 BranchIfNumberRelationalComparison(Operation::kEqual, left, right, if_true,
3950 if_false);
3951 }
3952
3954 Label* if_true, Label* if_false) {
3955 BranchIfNumberEqual(left, right, if_false, if_true);
3956 }
3957
3959 Label* if_true, Label* if_false) {
3960 BranchIfNumberRelationalComparison(Operation::kLessThan, left, right,
3961 if_true, if_false);
3962 }
3963
3965 Label* if_true, Label* if_false) {
3966 BranchIfNumberRelationalComparison(Operation::kLessThanOrEqual, left, right,
3967 if_true, if_false);
3968 }
3969
3971 Label* if_true, Label* if_false) {
3972 BranchIfNumberRelationalComparison(Operation::kGreaterThan, left, right,
3973 if_true, if_false);
3974 }
3975
3977 Label* if_true, Label* if_false) {
3978 BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, left,
3979 right, if_true, if_false);
3980 }
3981
3982 void BranchIfAccessorPair(TNode<Object> value, Label* if_accessor_pair,
3983 Label* if_not_accessor_pair) {
3984 GotoIf(TaggedIsSmi(value), if_not_accessor_pair);
3985 Branch(IsAccessorPair(CAST(value)), if_accessor_pair, if_not_accessor_pair);
3986 }
3987
3988 void GotoIfNumberGreaterThanOrEqual(TNode<Number> left, TNode<Number> right,
3989 Label* if_false);
3990
3992 TNode<Context> context,
3993 TVariable<Smi>* var_type_feedback = nullptr) {
3994 return Equal(
3995 lhs, rhs, [=]() { return context; }, var_type_feedback);
3996 }
3998 const LazyNode<Context>& context,
3999 TVariable<Smi>* var_type_feedback = nullptr);
4000
4001 TNode<Boolean> StrictEqual(TNode<Object> lhs, TNode<Object> rhs,
4002 TVariable<Smi>* var_type_feedback = nullptr);
4003
4005 TNode<String> rhs, Label* if_true) {
4006 Label if_false(this);
4007 // Callers must handle the case where {lhs} and {rhs} refer to the same
4008 // String object.
4009 CSA_DCHECK(this, TaggedNotEqual(lhs, rhs));
4010 TNode<IntPtrT> rhs_length = LoadStringLengthAsWord(rhs);
4011 BranchIfStringEqual(lhs, lhs_length, rhs, rhs_length, if_true, &if_false,
4012 nullptr);
4013
4014 BIND(&if_false);
4015 }
4016
4018 Label* if_false,
4019 TVariable<Boolean>* result = nullptr) {
4020 return BranchIfStringEqual(lhs, LoadStringLengthAsWord(lhs), rhs,
4021 LoadStringLengthAsWord(rhs), if_true, if_false,
4022 result);
4023 }
4024
4025 void BranchIfStringEqual(TNode<String> lhs, TNode<IntPtrT> lhs_length,
4026 TNode<String> rhs, TNode<IntPtrT> rhs_length,
4027 Label* if_true, Label* if_false,
4028 TVariable<Boolean>* result = nullptr);
4029
4030 // ECMA#sec-samevalue
4031 // Similar to StrictEqual except that NaNs are treated as equal and minus zero
4032 // differs from positive zero.
4033 enum class SameValueMode { kNumbersOnly, kFull };
4034 void BranchIfSameValue(TNode<Object> lhs, TNode<Object> rhs, Label* if_true,
4035 Label* if_false,
4036 SameValueMode mode = SameValueMode::kFull);
4037 // A part of BranchIfSameValue() that handles two double values.
4038 // Treats NaN == NaN and +0 != -0.
4039 void BranchIfSameNumberValue(TNode<Float64T> lhs_value,
4040 TNode<Float64T> rhs_value, Label* if_true,
4041 Label* if_false);
4042
4043 enum HasPropertyLookupMode { kHasProperty, kForInHasProperty };
4044
4045 TNode<Boolean> HasProperty(TNode<Context> context, TNode<JSAny> object,
4046 TNode<Object> key, HasPropertyLookupMode mode);
4047
4048 // Due to naming conflict with the builtin function namespace.
4050 TNode<JSReceiver> object,
4052 return HasProperty(context, object, key,
4053 HasPropertyLookupMode::kHasProperty);
4054 }
4055
4056 void ForInPrepare(TNode<HeapObject> enumerator, TNode<UintPtrT> slot,
4057 TNode<HeapObject> maybe_feedback_vector,
4058 TNode<FixedArray>* cache_array_out,
4059 TNode<Smi>* cache_length_out,
4060 UpdateFeedbackMode update_feedback_mode);
4061
4062 TNode<String> Typeof(
4063 TNode<Object> value, std::optional<TNode<UintPtrT>> slot_id = {},
4064 std::optional<TNode<HeapObject>> maybe_feedback_vector = {});
4065
4066 TNode<HeapObject> GetSuperConstructor(TNode<JSFunction> active_function);
4067
4068 TNode<JSReceiver> SpeciesConstructor(TNode<Context> context,
4069 TNode<JSAny> object,
4070 TNode<JSReceiver> default_constructor);
4071
4072 TNode<Boolean> InstanceOf(TNode<Object> object, TNode<JSAny> callable,
4073 TNode<Context> context);
4074
4075 // Debug helpers
4076 TNode<BoolT> IsDebugActive();
4077
4078 // JSArrayBuffer helpers
4079 TNode<UintPtrT> LoadJSArrayBufferByteLength(
4080 TNode<JSArrayBuffer> array_buffer);
4081 TNode<UintPtrT> LoadJSArrayBufferMaxByteLength(
4082 TNode<JSArrayBuffer> array_buffer);
4083 TNode<RawPtrT> LoadJSArrayBufferBackingStorePtr(
4084 TNode<JSArrayBuffer> array_buffer);
4085 void ThrowIfArrayBufferIsDetached(TNode<Context> context,
4086 TNode<JSArrayBuffer> array_buffer,
4087 const char* method_name);
4088
4089 // JSArrayBufferView helpers
4090 TNode<JSArrayBuffer> LoadJSArrayBufferViewBuffer(
4091 TNode<JSArrayBufferView> array_buffer_view);
4092 TNode<UintPtrT> LoadJSArrayBufferViewByteLength(
4093 TNode<JSArrayBufferView> array_buffer_view);
4094 void StoreJSArrayBufferViewByteLength(
4095 TNode<JSArrayBufferView> array_buffer_view, TNode<UintPtrT> value);
4096 TNode<UintPtrT> LoadJSArrayBufferViewByteOffset(
4097 TNode<JSArrayBufferView> array_buffer_view);
4098 void StoreJSArrayBufferViewByteOffset(
4099 TNode<JSArrayBufferView> array_buffer_view, TNode<UintPtrT> value);
4100 void ThrowIfArrayBufferViewBufferIsDetached(
4101 TNode<Context> context, TNode<JSArrayBufferView> array_buffer_view,
4102 const char* method_name);
4103
4104 // JSTypedArray helpers
4105 TNode<UintPtrT> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
4106 void StoreJSTypedArrayLength(TNode<JSTypedArray> typed_array,
4107 TNode<UintPtrT> value);
4108 TNode<UintPtrT> LoadJSTypedArrayLengthAndCheckDetached(
4109 TNode<JSTypedArray> typed_array, Label* detached);
4110 // Helper for length tracking JSTypedArrays and JSTypedArrays backed by
4111 // ResizableArrayBuffer.
4112 TNode<UintPtrT> LoadVariableLengthJSTypedArrayLength(
4113 TNode<JSTypedArray> array, TNode<JSArrayBuffer> buffer,
4114 Label* detached_or_out_of_bounds);
4115 // Helper for length tracking JSTypedArrays and JSTypedArrays backed by
4116 // ResizableArrayBuffer.
4117 TNode<UintPtrT> LoadVariableLengthJSTypedArrayByteLength(
4118 TNode<Context> context, TNode<JSTypedArray> array,
4119 TNode<JSArrayBuffer> buffer);
4120 TNode<UintPtrT> LoadVariableLengthJSArrayBufferViewByteLength(
4121 TNode<JSArrayBufferView> array, TNode<JSArrayBuffer> buffer,
4122 Label* detached_or_out_of_bounds);
4123
4124 void IsJSArrayBufferViewDetachedOrOutOfBounds(
4125 TNode<JSArrayBufferView> array_buffer_view, Label* detached_or_oob,
4126 Label* not_detached_nor_oob);
4127
4128 TNode<BoolT> IsJSArrayBufferViewDetachedOrOutOfBoundsBoolean(
4129 TNode<JSArrayBufferView> array_buffer_view);
4130
4131 void CheckJSTypedArrayIndex(TNode<JSTypedArray> typed_array,
4132 TNode<UintPtrT> index,
4133 Label* detached_or_out_of_bounds);
4134
4135 TNode<IntPtrT> RabGsabElementsKindToElementByteSize(
4136 TNode<Int32T> elementsKind);
4137 TNode<RawPtrT> LoadJSTypedArrayDataPtr(TNode<JSTypedArray> typed_array);
4138 TNode<JSArrayBuffer> GetTypedArrayBuffer(TNode<Context> context,
4139 TNode<JSTypedArray> array);
4140
4141 template <typename TIndex>
4142 TNode<IntPtrT> ElementOffsetFromIndex(TNode<TIndex> index, ElementsKind kind,
4143 int base_size = 0);
4144 template <typename Array, typename TIndex>
4146 static_assert(Array::kElementSize == kTaggedSize);
4147 return ElementOffsetFromIndex(index, PACKED_ELEMENTS,
4149 }
4150
4151 // Check that a field offset is within the bounds of the an object.
4152 TNode<BoolT> IsOffsetInBounds(TNode<IntPtrT> offset, TNode<IntPtrT> length,
4153 int header_size,
4154 ElementsKind kind = HOLEY_ELEMENTS);
4155
4156 // Load a builtin's code from the builtin array in the isolate.
4157 TNode<Code> LoadBuiltin(TNode<Smi> builtin_id);
4158
4159#ifdef V8_ENABLE_LEAPTIERING
4160 // Load a builtin's handle into the JSDispatchTable.
4161#if V8_STATIC_DISPATCH_HANDLES_BOOL
4162 TNode<JSDispatchHandleT> LoadBuiltinDispatchHandle(
4163 JSBuiltinDispatchHandleRoot::Idx dispatch_root_idx);
4164#endif // V8_STATIC_DISPATCH_HANDLES_BOOL
4165 TNode<JSDispatchHandleT> LoadBuiltinDispatchHandle(RootIndex idx);
4166
4167 // Load the Code object of a JSDispatchTable entry.
4168 TNode<Code> LoadCodeObjectFromJSDispatchTable(
4169 TNode<JSDispatchHandleT> dispatch_handle);
4170 // Load the parameter count of a JSDispatchTable entry.
4171 TNode<Uint16T> LoadParameterCountFromJSDispatchTable(
4172 TNode<JSDispatchHandleT> dispatch_handle);
4173
4174 TNode<UintPtrT> ComputeJSDispatchTableEntryOffset(
4176#endif
4177
4178 // Indicate that this code must support a dynamic parameter count.
4179 //
4180 // This is used for builtins that must work on functions with different
4181 // parameter counts. In that case, the true JS parameter count is only known
4182 // at runtime and must be obtained in order to compute the total number of
4183 // arguments (which may include padding arguments). The parameter count is
4184 // subsequently available through the corresponding CodeAssembler accessors.
4185 // The target function object and the dispatch handle need to be passed in
4186 // and are used to obtain the actual parameter count of the called function.
4187 //
4188 // This should generally be invoked directly at the start of the function.
4189 //
4190 // TODO(saelo): it would be a bit nicer if this would happen automatically in
4191 // the function prologue for functions marked as requiring this (e.g. via the
4192 // call descriptor). It's not clear if that's worth the effort though for the
4193 // handful of builtins that need this.
4194 void SetSupportsDynamicParameterCount(
4195 TNode<JSFunction> callee, TNode<JSDispatchHandleT> dispatch_handle);
4196
4197 // Figure out the SFI's code object using its data field.
4198 // If |data_type_out| is provided, the instance type of the function data will
4199 // be stored in it. In case the code object is a builtin (data is a Smi),
4200 // data_type_out will be set to 0.
4201 // If |if_compile_lazy| is provided then the execution will go to the given
4202 // label in case of an CompileLazy code object.
4203 TNode<Code> GetSharedFunctionInfoCode(
4204 TNode<SharedFunctionInfo> shared_info,
4205 TVariable<Uint16T>* data_type_out = nullptr,
4206 Label* if_compile_lazy = nullptr);
4207
4208 TNode<JSFunction> AllocateRootFunctionWithContext(
4209 RootIndex function, TNode<Context> context,
4210 std::optional<TNode<NativeContext>> maybe_native_context);
4211 // Used from Torque because Torque
4213 intptr_t function, TNode<Context> context,
4214 TNode<NativeContext> native_context) {
4215 return AllocateRootFunctionWithContext(static_cast<RootIndex>(function),
4216 context, native_context);
4217 }
4218
4219 // Promise helpers
4220 TNode<Uint32T> PromiseHookFlags();
4221 TNode<BoolT> HasAsyncEventDelegate();
4222#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
4223 TNode<BoolT> IsContextPromiseHookEnabled(TNode<Uint32T> flags);
4224#endif
4225 TNode<BoolT> IsIsolatePromiseHookEnabled(TNode<Uint32T> flags);
4226 TNode<BoolT> IsAnyPromiseHookEnabled(TNode<Uint32T> flags);
4228 return IsAnyPromiseHookEnabled(PromiseHookFlags());
4229 }
4230 TNode<BoolT> IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate(
4231 TNode<Uint32T> flags);
4233 return IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate(
4234 PromiseHookFlags());
4235 }
4237 IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
4238 TNode<Uint32T> flags);
4241 return IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate(
4242 PromiseHookFlags());
4243 }
4244
4245 TNode<BoolT> NeedsAnyPromiseHooks(TNode<Uint32T> flags);
4247 return NeedsAnyPromiseHooks(PromiseHookFlags());
4248 }
4249
4250 // for..in helpers
4251 void CheckPrototypeEnumCache(TNode<JSReceiver> receiver,
4252 TNode<Map> receiver_map, Label* if_fast,
4253 Label* if_slow);
4254 TNode<Map> CheckEnumCache(TNode<JSReceiver> receiver, Label* if_empty,
4255 Label* if_runtime);
4256
4257 TNode<JSAny> GetArgumentValue(TorqueStructArguments args,
4258 TNode<IntPtrT> index);
4259
4260 void SetArgumentValue(TorqueStructArguments args, TNode<IntPtrT> index,
4261 TNode<JSAny> value);
4262
4264 kCountIncludesReceiver,
4265 kCountExcludesReceiver
4266 };
4267
4268 TorqueStructArguments GetFrameArguments(
4269 TNode<RawPtrT> frame, TNode<IntPtrT> argc,
4270 FrameArgumentsArgcType argc_type =
4271 FrameArgumentsArgcType::kCountExcludesReceiver);
4272
4273 inline TNode<Int32T> JSParameterCount(int argc_without_receiver) {
4274 return Int32Constant(argc_without_receiver + kJSArgcReceiverSlots);
4275 }
4276 inline TNode<Word32T> JSParameterCount(TNode<Word32T> argc_without_receiver) {
4277 return Int32Add(argc_without_receiver, Int32Constant(kJSArgcReceiverSlots));
4278 }
4279
4280 // Support for printf-style debugging
4281 void Print(const char* s);
4282 void Print(const char* prefix, TNode<MaybeObject> tagged_value);
4283 void Print(TNode<MaybeObject> tagged_value) {
4284 return Print(nullptr, tagged_value);
4285 }
4286 void Print(const char* prefix, TNode<UintPtrT> value);
4287 void Print(const char* prefix, TNode<Float64T> value);
4288 void PrintErr(const char* s);
4289 void PrintErr(const char* prefix, TNode<MaybeObject> tagged_value);
4290 void PrintErr(TNode<MaybeObject> tagged_value) {
4291 return PrintErr(nullptr, tagged_value);
4292 }
4293 void PrintToStream(const char* s, int stream);
4294 void PrintToStream(const char* prefix, TNode<MaybeObject> tagged_value,
4295 int stream);
4296 void PrintToStream(const char* prefix, TNode<UintPtrT> value, int stream);
4297 void PrintToStream(const char* prefix, TNode<Float64T> value, int stream);
4298
4299 template <class... TArgs>
4301 TNode<Context> context, TArgs... args) {
4302 static_assert(sizeof...(TArgs) <= 3);
4303 return CAST(CallRuntime(Runtime::kNewTypeError, context,
4304 SmiConstant(message), args...));
4305 }
4306
4307 void Abort(AbortReason reason) {
4308 CallRuntime(Runtime::kAbort, NoContextConstant(), SmiConstant(reason));
4309 Unreachable();
4310 }
4311
4312 bool ConstexprBoolNot(bool value) { return !value; }
4314 return int31_t(i.To<int32_t>());
4315 }
4317 return i.To<int32_t>();
4318 }
4320 return i.To<uint32_t>();
4321 }
4323 return i.To<int8_t>();
4324 }
4326 return i.To<uint8_t>();
4327 }
4329 return i.To<int64_t>();
4330 }
4332 return i.To<uint64_t>();
4333 }
4335 return i.To<intptr_t>();
4336 }
4338 return i.To<uintptr_t>();
4339 }
4341 int64_t i_value = i.To<int64_t>();
4342 double d_value = static_cast<double>(i_value);
4343 CHECK_EQ(i_value, static_cast<int64_t>(d_value));
4344 return d_value;
4345 }
4347 return lhs == rhs;
4348 }
4349 IntegerLiteral ConstexprIntegerLiteralAdd(const IntegerLiteral& lhs,
4350 const IntegerLiteral& rhs);
4351 IntegerLiteral ConstexprIntegerLiteralLeftShift(const IntegerLiteral& lhs,
4352 const IntegerLiteral& rhs);
4353 IntegerLiteral ConstexprIntegerLiteralBitwiseOr(const IntegerLiteral& lhs,
4354 const IntegerLiteral& rhs);
4355
4356 bool ConstexprInt31Equal(int31_t a, int31_t b) { return a == b; }
4357 bool ConstexprInt31NotEqual(int31_t a, int31_t b) { return a != b; }
4358 bool ConstexprInt31GreaterThanEqual(int31_t a, int31_t b) { return a >= b; }
4359 bool ConstexprUint32Equal(uint32_t a, uint32_t b) { return a == b; }
4360 bool ConstexprUint32NotEqual(uint32_t a, uint32_t b) { return a != b; }
4361 bool ConstexprInt32Equal(int32_t a, int32_t b) { return a == b; }
4362 bool ConstexprInt32NotEqual(int32_t a, int32_t b) { return a != b; }
4363 bool ConstexprInt32GreaterThanEqual(int32_t a, int32_t b) { return a >= b; }
4364 uint32_t ConstexprUint32Add(uint32_t a, uint32_t b) { return a + b; }
4365 int32_t ConstexprUint32Sub(uint32_t a, uint32_t b) { return a - b; }
4366 int32_t ConstexprInt32Sub(int32_t a, int32_t b) { return a - b; }
4367 int32_t ConstexprInt32Add(int32_t a, int32_t b) { return a + b; }
4369 int32_t val;
4370 CHECK(!base::bits::SignedAddOverflow32(a, b, &val));
4371 return val;
4372 }
4374 int32_t val;
4375 CHECK(!base::bits::SignedMulOverflow32(a, b, &val));
4376 return val;
4377 }
4378
4379 int32_t ConstexprWord32Or(int32_t a, int32_t b) { return a | b; }
4380 uint32_t ConstexprWord32Shl(uint32_t a, int32_t b) { return a << b; }
4381
4382 bool ConstexprUintPtrLessThan(uintptr_t a, uintptr_t b) { return a < b; }
4383
4384 // CSA does not support 64-bit types on 32-bit platforms so as a workaround
4385 // the kMaxSafeIntegerUint64 is defined as uintptr and allowed to be used only
4386 // inside if constexpr (Is64()) i.e. on 64-bit architectures.
4387 static uintptr_t MaxSafeIntegerUintPtr() {
4388#if defined(V8_HOST_ARCH_64_BIT)
4389 // This ifdef is required to avoid build issues on 32-bit MSVC which
4390 // complains about static_cast<uintptr_t>(kMaxSafeIntegerUint64).
4391 return kMaxSafeIntegerUint64;
4392#else
4393 UNREACHABLE();
4394#endif
4395 }
4396
4397 void PerformStackCheck(TNode<Context> context);
4398
4399 void SetPropertyLength(TNode<Context> context, TNode<JSAny> array,
4400 TNode<Number> length);
4401
4402 // Implements DescriptorArray::Search().
4403 void DescriptorLookup(TNode<Name> unique_name,
4404 TNode<DescriptorArray> descriptors,
4405 TNode<Uint32T> bitfield3, Label* if_found,
4406 TVariable<IntPtrT>* var_name_index,
4407 Label* if_not_found);
4408
4409 // Implements TransitionArray::SearchName() - searches for first transition
4410 // entry with given name (note that there could be multiple entries with
4411 // the same name).
4412 void TransitionLookup(TNode<Name> unique_name,
4413 TNode<TransitionArray> transitions, Label* if_found,
4414 TVariable<IntPtrT>* var_name_index,
4415 Label* if_not_found);
4416
4417 // Implements generic search procedure like i::Search<Array>().
4418 template <typename Array>
4419 void Lookup(TNode<Name> unique_name, TNode<Array> array,
4420 TNode<Uint32T> number_of_valid_entries, Label* if_found,
4421 TVariable<IntPtrT>* var_name_index, Label* if_not_found);
4422
4423 // Implements generic linear search procedure like i::LinearSearch<Array>().
4424 template <typename Array>
4425 void LookupLinear(TNode<Name> unique_name, TNode<Array> array,
4426 TNode<Uint32T> number_of_valid_entries, Label* if_found,
4427 TVariable<IntPtrT>* var_name_index, Label* if_not_found);
4428
4429 // Implements generic binary search procedure like i::BinarySearch<Array>().
4430 template <typename Array>
4431 void LookupBinary(TNode<Name> unique_name, TNode<Array> array,
4432 TNode<Uint32T> number_of_valid_entries, Label* if_found,
4433 TVariable<IntPtrT>* var_name_index, Label* if_not_found);
4434
4435 // Converts [Descriptor/Transition]Array entry number to a fixed array index.
4436 template <typename Array>
4437 TNode<IntPtrT> EntryIndexToIndex(TNode<Uint32T> entry_index);
4438
4439 // Implements [Descriptor/Transition]Array::ToKeyIndex.
4440 template <typename Array>
4441 TNode<IntPtrT> ToKeyIndex(TNode<Uint32T> entry_index);
4442
4443 // Implements [Descriptor/Transition]Array::GetKey.
4444 template <typename Array>
4445 TNode<Name> GetKey(TNode<Array> array, TNode<Uint32T> entry_index);
4446
4447 // Implements DescriptorArray::GetDetails.
4448 TNode<Uint32T> DescriptorArrayGetDetails(TNode<DescriptorArray> descriptors,
4449 TNode<Uint32T> descriptor_number);
4450
4452 std::function<void(TNode<IntPtrT> descriptor_key_index)>;
4453
4454 // Descriptor array accessors based on key_index, which is equal to
4455 // DescriptorArray::ToKeyIndex(descriptor).
4456 TNode<Name> LoadKeyByKeyIndex(TNode<DescriptorArray> container,
4457 TNode<IntPtrT> key_index);
4458 TNode<Uint32T> LoadDetailsByKeyIndex(TNode<DescriptorArray> container,
4459 TNode<IntPtrT> key_index);
4460 TNode<Object> LoadValueByKeyIndex(TNode<DescriptorArray> container,
4461 TNode<IntPtrT> key_index);
4462 TNode<MaybeObject> LoadFieldTypeByKeyIndex(TNode<DescriptorArray> container,
4463 TNode<IntPtrT> key_index);
4464
4465 TNode<IntPtrT> DescriptorEntryToIndex(TNode<IntPtrT> descriptor);
4466
4467 // Descriptor array accessors based on descriptor.
4468 TNode<Name> LoadKeyByDescriptorEntry(TNode<DescriptorArray> descriptors,
4469 TNode<IntPtrT> descriptor);
4470 TNode<Name> LoadKeyByDescriptorEntry(TNode<DescriptorArray> descriptors,
4471 int descriptor);
4472 TNode<Uint32T> LoadDetailsByDescriptorEntry(
4473 TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor);
4474 TNode<Uint32T> LoadDetailsByDescriptorEntry(
4475 TNode<DescriptorArray> descriptors, int descriptor);
4476 TNode<Object> LoadValueByDescriptorEntry(TNode<DescriptorArray> descriptors,
4477 TNode<IntPtrT> descriptor);
4478 TNode<Object> LoadValueByDescriptorEntry(TNode<DescriptorArray> descriptors,
4479 int descriptor);
4480 TNode<MaybeObject> LoadFieldTypeByDescriptorEntry(
4481 TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor);
4482
4484 std::function<void(TNode<Name> key, LazyNode<Object> value)>;
4485
4486 // For each JSObject property (in DescriptorArray order), check if the key is
4487 // enumerable, and if so, load the value from the receiver and evaluate the
4488 // closure. The value is provided as a LazyNode, which lazily evaluates
4489 // accessors if present.
4490 void ForEachEnumerableOwnProperty(TNode<Context> context, TNode<Map> map,
4491 TNode<JSObject> object,
4493 const ForEachKeyValueFunction& body,
4494 Label* bailout);
4495
4496 TNode<Object> CallGetterIfAccessor(
4499 TNode<Object> name, Label* if_bailout,
4500 GetOwnPropertyMode mode = kCallJSGetterDontUseCachedName,
4501 ExpectedReceiverMode expected_receiver_mode = kExpectingJSReceiver);
4502
4503 TNode<IntPtrT> TryToIntptr(TNode<Object> key, Label* if_not_intptr,
4504 TVariable<Int32T>* var_instance_type = nullptr);
4505
4506 TNode<JSArray> ArrayCreate(TNode<Context> context, TNode<Number> length);
4507
4508 // Allocate a clone of a mutable primitive, if {object} is a mutable
4509 // HeapNumber.
4510 TNode<Object> CloneIfMutablePrimitive(TNode<Object> object);
4511
4512 TNode<Smi> RefillMathRandom(TNode<NativeContext> native_context);
4513
4515 return IntPtrConstant(FeedbackIterator::kEntrySize);
4516 }
4517
4519 return IntPtrConstant(FeedbackIterator::kHandlerOffset);
4520 }
4521
4522 TNode<SwissNameDictionary> AllocateSwissNameDictionary(
4523 TNode<IntPtrT> at_least_space_for);
4524 TNode<SwissNameDictionary> AllocateSwissNameDictionary(
4525 int at_least_space_for);
4526
4527 TNode<SwissNameDictionary> AllocateSwissNameDictionaryWithCapacity(
4528 TNode<IntPtrT> capacity);
4529
4530 // MT stands for "minus tag".
4531 TNode<IntPtrT> SwissNameDictionaryOffsetIntoDataTableMT(
4532 TNode<SwissNameDictionary> dict, TNode<IntPtrT> index, int field_index);
4533
4534 // MT stands for "minus tag".
4535 TNode<IntPtrT> SwissNameDictionaryOffsetIntoPropertyDetailsTableMT(
4537 TNode<IntPtrT> index);
4538
4539 TNode<IntPtrT> LoadSwissNameDictionaryNumberOfElements(
4541
4542 TNode<IntPtrT> LoadSwissNameDictionaryNumberOfDeletedElements(
4544
4545 // Specialized operation to be used when adding entries:
4546 // If used capacity (= number of present + deleted elements) is less than
4547 // |max_usable|, increment the number of present entries and return the used
4548 // capacity value (prior to the incrementation). Otherwise, goto |bailout|.
4549 TNode<Uint32T> SwissNameDictionaryIncreaseElementCountOrBailout(
4550 TNode<ByteArray> meta_table, TNode<IntPtrT> capacity,
4551 TNode<Uint32T> max_usable_capacity, Label* bailout);
4552
4553 // Specialized operation to be used when deleting entries: Decreases the
4554 // number of present entries and increases the number of deleted ones. Returns
4555 // new (= decremented) number of present entries.
4556 TNode<Uint32T> SwissNameDictionaryUpdateCountsForDeletion(
4557 TNode<ByteArray> meta_table, TNode<IntPtrT> capacity);
4558
4559 void StoreSwissNameDictionaryCapacity(TNode<SwissNameDictionary> table,
4560 TNode<Int32T> capacity);
4561
4562 void StoreSwissNameDictionaryEnumToEntryMapping(
4564 TNode<IntPtrT> enum_index, TNode<Int32T> entry);
4565
4566 TNode<Name> LoadSwissNameDictionaryKey(TNode<SwissNameDictionary> dict,
4567 TNode<IntPtrT> entry);
4568
4569 void StoreSwissNameDictionaryKeyAndValue(TNode<SwissNameDictionary> dict,
4570 TNode<IntPtrT> entry,
4572 TNode<Object> value);
4573
4574 // Equivalent to SwissNameDictionary::SetCtrl, therefore preserves the copy of
4575 // the first group at the end of the control table.
4576 void SwissNameDictionarySetCtrl(TNode<SwissNameDictionary> table,
4577 TNode<IntPtrT> capacity, TNode<IntPtrT> entry,
4578 TNode<Uint8T> ctrl);
4579
4580 TNode<Uint64T> LoadSwissNameDictionaryCtrlTableGroup(TNode<IntPtrT> address);
4581
4582 TNode<Uint8T> LoadSwissNameDictionaryPropertyDetails(
4584 TNode<IntPtrT> entry);
4585
4586 void StoreSwissNameDictionaryPropertyDetails(TNode<SwissNameDictionary> table,
4587 TNode<IntPtrT> capacity,
4588 TNode<IntPtrT> entry,
4589 TNode<Uint8T> details);
4590
4591 TNode<SwissNameDictionary> CopySwissNameDictionary(
4593
4594 void SwissNameDictionaryFindEntry(TNode<SwissNameDictionary> table,
4595 TNode<Name> key, Label* found,
4596 TVariable<IntPtrT>* var_found_entry,
4597 Label* not_found);
4598
4599 void SwissNameDictionaryAdd(TNode<SwissNameDictionary> table, TNode<Name> key,
4600 TNode<Object> value,
4601 TNode<Uint8T> property_details,
4602 Label* needs_resize);
4603
4604 TNode<BoolT> IsMarked(TNode<Object> object);
4605
4606 void GetMarkBit(TNode<IntPtrT> object, TNode<IntPtrT>* cell,
4608
4610 TNode<IntPtrT> header = MemoryChunkFromAddress(object);
4611 TNode<IntPtrT> flags = UncheckedCast<IntPtrT>(
4612 Load(MachineType::Pointer(), header,
4613 IntPtrConstant(MemoryChunk::FlagsOffset())));
4614 return WordNotEqual(WordAnd(flags, IntPtrConstant(mask)),
4615 IntPtrConstant(0));
4616 }
4617
4619 TNode<IntPtrT> header = MemoryChunkFromAddress(object);
4620 TNode<IntPtrT> flags = UncheckedCast<IntPtrT>(
4621 Load(MachineType::Pointer(), header,
4622 IntPtrConstant(MemoryChunk::FlagsOffset())));
4623 return WordEqual(WordAnd(flags, IntPtrConstant(mask)), IntPtrConstant(0));
4624 }
4625
4626 private:
4627 friend class CodeStubArguments;
4628
4629 void BigInt64Comparison(Operation op, TNode<Object>& left,
4630 TNode<Object>& right, Label* return_true,
4631 Label* return_false);
4632
4633 void HandleBreakOnNode();
4634
4635 TNode<HeapObject> AllocateRawDoubleAligned(TNode<IntPtrT> size_in_bytes,
4636 AllocationFlags flags,
4637 TNode<RawPtrT> top_address,
4638 TNode<RawPtrT> limit_address);
4639 TNode<HeapObject> AllocateRawUnaligned(TNode<IntPtrT> size_in_bytes,
4640 AllocationFlags flags,
4641 TNode<RawPtrT> top_address,
4642 TNode<RawPtrT> limit_address);
4643 TNode<HeapObject> AllocateRaw(TNode<IntPtrT> size_in_bytes,
4644 AllocationFlags flags,
4645 TNode<RawPtrT> top_address,
4646 TNode<RawPtrT> limit_address);
4647
4648 // Allocate and return a JSArray of given total size in bytes with header
4649 // fields initialized.
4650 TNode<JSArray> AllocateUninitializedJSArray(
4651 TNode<Map> array_map, TNode<Smi> length,
4652 std::optional<TNode<AllocationSite>> allocation_site,
4653 TNode<IntPtrT> size_in_bytes);
4654
4655 // Increases the provided capacity to the next valid value, if necessary.
4656 template <typename CollectionType>
4657 TNode<CollectionType> AllocateOrderedHashTable(TNode<IntPtrT> capacity);
4658
4659 // Uses the provided capacity (which must be valid) in verbatim.
4660 template <typename CollectionType>
4661 TNode<CollectionType> AllocateOrderedHashTableWithCapacity(
4662 TNode<IntPtrT> capacity);
4663
4665 return IntPtrConstant(kSmiShiftSize + kSmiTagSize);
4666 }
4668 return Int32Constant(kSmiShiftSize + kSmiTagSize);
4669 }
4670
4671 TNode<String> AllocateSlicedString(RootIndex map_root_index,
4672 TNode<Uint32T> length,
4674
4675 // Implements [Descriptor/Transition]Array::number_of_entries.
4676 template <typename Array>
4678
4679 template <typename Array>
4680 constexpr int MaxNumberOfEntries();
4681
4682 // Implements [Descriptor/Transition]Array::GetSortedKeyIndex.
4683 template <typename Array>
4685 TNode<Uint32T> entry_index);
4686
4687 TNode<Smi> CollectFeedbackForString(TNode<Int32T> instance_type);
4688 void GenerateEqual_Same(TNode<Object> value, Label* if_equal,
4689 Label* if_notequal,
4690 TVariable<Smi>* var_type_feedback = nullptr);
4691
4692 static const int kElementLoopUnrollThreshold = 8;
4693
4694 // {convert_bigint} is only meaningful when {mode} == kToNumber.
4695 TNode<Numeric> NonNumberToNumberOrNumeric(
4697 BigIntHandling bigint_handling = BigIntHandling::kThrow);
4698
4700 template <Object::Conversion conversion>
4701 void TaggedToWord32OrBigIntImpl(
4702 TNode<Context> context, TNode<Object> value, Label* if_number,
4703 TVariable<Word32T>* var_word32,
4704 IsKnownTaggedPointer is_known_tagged_pointer,
4705 const FeedbackValues& feedback, Label* if_bigint = nullptr,
4706 Label* if_bigint64 = nullptr,
4707 TVariable<BigInt>* var_maybe_bigint = nullptr);
4708
4709 // Low-level accessors for Descriptor arrays.
4710 template <typename T>
4711 TNode<T> LoadDescriptorArrayElement(TNode<DescriptorArray> object,
4712 TNode<IntPtrT> index,
4713 int additional_offset);
4714
4715 // Hide LoadRoot for subclasses of CodeStubAssembler. If you get an error
4716 // complaining about this method, don't make it public, add your root to
4717 // HEAP_(IM)MUTABLE_IMMOVABLE_OBJECT_LIST instead. If you *really* need
4718 // LoadRoot, use CodeAssembler::LoadRoot.
4720 return CodeAssembler::LoadRoot(root_index);
4721 }
4722
4724 return CodeAssembler::LoadRootMapWord(root_index);
4725 }
4726
4727 template <typename TIndex>
4728 void StoreFixedArrayOrPropertyArrayElement(
4730 TNode<Object> value, WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER,
4731 int additional_offset = 0);
4732
4733 template <typename TIndex>
4734 void StoreElementTypedArrayBigInt(TNode<RawPtrT> elements, ElementsKind kind,
4735 TNode<TIndex> index, TNode<BigInt> value);
4736
4737 template <typename TIndex>
4738 void StoreElementTypedArrayWord32(TNode<RawPtrT> elements, ElementsKind kind,
4739 TNode<TIndex> index, TNode<Word32T> value);
4740
4741 // Store value to an elements array with given elements kind.
4742 // TODO(turbofan): For BIGINT64_ELEMENTS and BIGUINT64_ELEMENTS
4743 // we pass {value} as BigInt object instead of int64_t. We should
4744 // teach TurboFan to handle int64_t on 32-bit platforms eventually.
4745 // TODO(solanes): This method can go away and simplify into only one version
4746 // of StoreElement once we have "if constexpr" available to use.
4747 template <typename TArray, typename TIndex, typename TValue>
4748 void StoreElementTypedArray(TNode<TArray> elements, ElementsKind kind,
4749 TNode<TIndex> index, TNode<TValue> value);
4750
4751 template <typename TIndex>
4752 void StoreElement(TNode<FixedArrayBase> elements, ElementsKind kind,
4753 TNode<TIndex> index, TNode<Object> value);
4754
4755 template <typename TIndex>
4756 void StoreElement(TNode<FixedArrayBase> elements, ElementsKind kind,
4757 TNode<TIndex> index, TNode<Float64T> value);
4758
4759 // Converts {input} to a number if {input} is a plain primitive (i.e. String
4760 // or Oddball) and stores the result in {var_result}. Otherwise, it bails out
4761 // to {if_bailout}.
4762 void TryPlainPrimitiveNonNumberToNumber(TNode<HeapObject> input,
4763 TVariable<Number>* var_result,
4764 Label* if_bailout);
4765
4766 void DcheckHasValidMap(TNode<HeapObject> object);
4767
4768 template <typename TValue>
4769 void EmitElementStoreTypedArray(TNode<JSTypedArray> typed_array,
4771 ElementsKind elements_kind,
4772 KeyedAccessStoreMode store_mode,
4773 Label* bailout, TNode<Context> context,
4774 TVariable<Object>* maybe_converted_value);
4775
4776 template <typename TValue>
4778 TNode<Object> value, ElementsKind elements_kind,
4779 TNode<TValue> converted_value, TVariable<Object>* maybe_converted_value);
4780};
4781
4783 public:
4784 // |argc| specifies the number of arguments passed to the builtin.
4786 : CodeStubArguments(assembler, argc, TNode<RawPtrT>()) {}
4788 : CodeStubArguments(assembler, assembler->ChangeInt32ToIntPtr(argc)) {}
4790 TNode<RawPtrT> fp);
4791
4792 // Used by Torque to construct arguments based on a Torque-defined
4793 // struct of values.
4795 TorqueStructArguments torque_arguments)
4796 : assembler_(assembler),
4797 argc_(torque_arguments.actual_count),
4798 base_(torque_arguments.base),
4799 fp_(torque_arguments.frame) {}
4800
4801 // Return true if there may be additional padding arguments, false otherwise.
4802 bool MayHavePaddingArguments() const;
4803
4804 TNode<JSAny> GetReceiver() const;
4805 // Replaces receiver argument on the expression stack. Should be used only
4806 // for manipulating arguments in trampoline builtins before tail calling
4807 // further with passing all the JS arguments as is.
4808 void SetReceiver(TNode<JSAny> object) const;
4809
4810 // Computes address of the index'th argument.
4811 TNode<RawPtrT> AtIndexPtr(TNode<IntPtrT> index) const;
4812
4813 // |index| is zero-based and does not include the receiver
4814 TNode<JSAny> AtIndex(TNode<IntPtrT> index) const;
4815 TNode<JSAny> AtIndex(int index) const;
4816
4817 // Return the number of arguments (excluding the receiver).
4818 TNode<IntPtrT> GetLengthWithoutReceiver() const;
4819 // Return the number of arguments (including the receiver).
4820 TNode<IntPtrT> GetLengthWithReceiver() const;
4821
4822 TorqueStructArguments GetTorqueArguments() const {
4823 return TorqueStructArguments{fp_, base_, GetLengthWithoutReceiver(), argc_};
4824 }
4825
4826 TNode<JSAny> GetOptionalArgumentValue(TNode<IntPtrT> index,
4827 TNode<JSAny> default_value);
4829 return GetOptionalArgumentValue(index, assembler_->UndefinedConstant());
4830 }
4832 return GetOptionalArgumentValue(assembler_->IntPtrConstant(index));
4833 }
4834
4835 void SetArgumentValue(TNode<IntPtrT> index, TNode<JSAny> value);
4836
4837 // Iteration doesn't include the receiver. |first| and |last| are zero-based.
4838 using ForEachBodyFunction = std::function<void(TNode<JSAny> arg)>;
4839 void ForEach(const ForEachBodyFunction& body, TNode<IntPtrT> first = {},
4840 TNode<IntPtrT> last = {}) const {
4841 CodeStubAssembler::VariableList list(0, assembler_->zone());
4842 ForEach(list, body, first, last);
4843 }
4844 void ForEach(const CodeStubAssembler::VariableList& vars,
4845 const ForEachBodyFunction& body, TNode<IntPtrT> first = {},
4846 TNode<IntPtrT> last = {}) const;
4847
4848 void PopAndReturn(TNode<JSAny> value);
4849
4850 private:
4855};
4856
4858 private:
4860
4861 public:
4862 enum Flag {
4864 };
4866
4868 TNode<String> string, Flags flags = Flags());
4869
4870 // Converts flat cons, thin, and sliced strings and returns the direct
4871 // string. The result can be either a sequential or external string.
4872 // Jumps to if_bailout if the string if the string is indirect and cannot
4873 // be unpacked.
4874 TNode<String> TryToDirect(Label* if_bailout);
4875
4876 // As above, but flattens in runtime if the string cannot be unpacked
4877 // otherwise.
4879
4880 // Returns a pointer to the beginning of the string data.
4881 // Jumps to if_bailout if the external string cannot be unpacked.
4883 return TryToSequential(PTR_TO_DATA, if_bailout);
4884 }
4885
4886 // Returns a pointer that, offset-wise, looks like a String.
4887 // Jumps to if_bailout if the external string cannot be unpacked.
4889 return TryToSequential(PTR_TO_STRING, if_bailout);
4890 }
4891
4893
4894 TNode<String> string() { return var_string_.value(); }
4895 TNode<IntPtrT> offset() { return var_offset_.value(); }
4897
4898 private:
4900
4902#if V8_STATIC_ROOTS_BOOL
4903 TVariable<Map> var_map_;
4904#else
4906#endif
4907 // TODO(v8:9880): Use UintPtrT here.
4910
4912};
4913
4914// Performs checks on a given prototype (e.g. map identity, property
4915// verification), intended for use in fast path checks.
4917 public:
4925
4926 // A tuple describing a relevant property. It contains the descriptor index of
4927 // the property (within the descriptor array), the property's expected name
4928 // (stored as a root), and the property's expected value (stored on the native
4929 // context).
4935
4938 TNode<Map> initial_prototype_map,
4940
4941 void CheckAndBranch(TNode<HeapObject> prototype, Label* if_unmodified,
4942 Label* if_modified);
4943
4944 private:
4949};
4950
4952
4953#define CLASS_MAP_CONSTANT_ADAPTER(V, rootIndexName, rootAccessorName, \
4954 class_name) \
4955 template <> \
4956 inline bool CodeStubAssembler::ClassHasMapConstant<class_name>() { \
4957 return true; \
4958 } \
4959 template <> \
4960 inline TNode<Map> CodeStubAssembler::GetClassMapConstant<class_name>() { \
4961 return class_name##MapConstant(); \
4962 }
4964#undef CLASS_MAP_CONSTANT_ADAPTER
4965
4967
4968} // namespace internal
4969} // namespace v8
4970
4971#endif // V8_CODEGEN_CODE_STUB_ASSEMBLER_H_
#define DEFINE_OPERATORS_FOR_FLAGS(Type)
Definition flags.h:100
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
Builtins::Kind kind
Definition builtins.cc:40
TNode< JSAny > GetOptionalArgumentValue(int index)
CodeStubArguments(CodeStubAssembler *assembler, TorqueStructArguments torque_arguments)
std::function< void(TNode< JSAny > arg)> ForEachBodyFunction
CodeStubArguments(CodeStubAssembler *assembler, TNode< Int32T > argc)
void ForEach(const ForEachBodyFunction &body, TNode< IntPtrT > first={}, TNode< IntPtrT > last={}) const
CodeStubArguments(CodeStubAssembler *assembler, TNode< IntPtrT > argc)
TorqueStructArguments GetTorqueArguments() const
TNode< JSAny > GetOptionalArgumentValue(TNode< IntPtrT > index)
TNode< Object > LoadObjectField(TNode< HeapObject > object, TNode< IntPtrT > offset)
TNode< IntPtrT > GetFixedArrayAllocationSize(TNode< TIndex > element_count, ElementsKind kind)
void GotoIfStringEqual(TNode< String > lhs, TNode< IntPtrT > lhs_length, TNode< String > rhs, Label *if_true)
TNode< Smi > SelectSmiConstant(TNode< BoolT > condition, int true_value, int false_value)
TNode< Object > LoadProtectedPointerField(TNode< TrustedObject > object, TNode< IntPtrT > offset)
std::function< TNode< T >()> NodeGenerator
bool IsFastPackedElementsKind(ElementsKind kind)
TNode< JSDataView > HeapObjectToJSDataView(TNode< HeapObject > heap_object, Label *fail)
TNode< BoolT > IsElementsKindInRange(TNode< Int32T > target_kind, ElementsKind lower_reference_kind, ElementsKind higher_reference_kind)
void BuildFastArrayForEach(TNode< UnionOf< FixedArray, PropertyArray, HeapObject > > array, ElementsKind kind, TNode< TIndex > first_element_inclusive, TNode< TIndex > last_element_exclusive, const FastArrayForEachBody &body, LoopUnrollingMode loop_unrolling_mode, ForEachDirection direction=ForEachDirection::kReverse)
TNode< HeapObject > MakeTypeError(MessageTemplate message, TNode< Context > context, TArgs... args)
void StoreFixedArrayElement(TNode< FixedArray > array, TNode< TIndex > index, TNode< Smi > value, int additional_offset=0)
TNode< RawPtrT > LoadBufferPointer(TNode< RawPtrT > buffer, int offset)
TNode< MaybeObject > LoadMaybeWeakObjectField(TNode< HeapObject > object, int offset)
intptr_t ConstexprIntegerLiteralToIntptr(const IntegerLiteral &i)
TNode< JSArray > AllocateJSArray(ElementsKind kind, TNode< Map > array_map, TNode< IntPtrT > capacity, TNode< Smi > length, AllocationFlags allocation_flags=AllocationFlag::kNone)
TNode< Object > LoadBufferObject(TNode< RawPtrT > buffer, int offset)
void UnsafeStoreFixedArrayElement(TNode< FixedArray > array, TNode< IntPtrT > index, TNode< Object > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER, int additional_offset=0)
void StoreJSSharedStructPropertyArrayElement(TNode< PropertyArray > array, TNode< IntPtrT > index, TNode< Object > value)
TNode< FixedDoubleArray > HeapObjectToFixedDoubleArray(TNode< HeapObject > base, Label *cast_fail)
TNode< Object > CallApiCallback(TNode< Object > context, TNode< RawPtrT > callback, TNode< Int32T > argc, TNode< Object > data, TNode< Object > holder, TNode< JSAny > receiver, TNode< Object > value)
bool ConstexprUintPtrLessThan(uintptr_t a, uintptr_t b)
TNode< JSProxy > HeapObjectToJSProxy(TNode< HeapObject > heap_object, Label *fail)
void Print(TNode< MaybeObject > tagged_value)
TNode< String > SingleCharacterStringConstant(char const *single_char)
TNode< BoolT > IsScriptContextMutableHeapNumberFlag()
TNode< T > LoadObjectField(TNode< HeapObject > object, TNode< IntPtrT > offset)
TNode< Smi > TaggedToSmi(TNode< Object > value, Label *fail)
TNode< Smi > SmiShl(TNode< Smi > a, int shift)
TNode< BoolT > IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate()
TNode< BoolT > IsEqualInWord32(TNode< Word32T > word32, typename BitField::FieldType value)
TNode< BoolT > IsSetWord(TNode< WordT > word, uint32_t mask)
std::pair< TNode< Object >, const char * > ExtraNode
uintptr_t ConstexprWordNot(uintptr_t a)
TNode< WordT > UpdateWord(TNode< WordT > word, TNode< UintPtrT > value, bool starts_as_zero=false)
TNode< Smi > GetNumberDictionaryNumberOfElements(TNode< NumberDictionary > dictionary)
void StoreSandboxedPointerToObject(TNode< HeapObject > object, int offset, TNode< RawPtrT > pointer)
void FixedArrayBoundsCheck(TNode< FixedArray > array, TNode< Smi > index, int additional_offset)
std::function< void( TNode< JSAnyNotSmi > receiver, TNode< JSAnyNotSmi > holder, TNode< Map > map, TNode< Int32T > instance_type, TNode< IntPtrT > key, Label *next_holder, Label *if_bailout)> LookupElementInHolder
TNode< RawPtr< Uint64T > > Log10OffsetTable()
void BranchIfNumberGreaterThanOrEqual(TNode< Number > left, TNode< Number > right, Label *if_true, Label *if_false)
bool ConstexprInt31Equal(int31_t a, int31_t b)
std::function< void(TNode< TIndex > index)> FastLoopBody
TNode< IntPtrT > ParameterToIntPtr(TNode< Smi > value)
void StoreReference(Reference reference, TNode< T > value)
uint32_t ConstexprIntegerLiteralToUint32(const IntegerLiteral &i)
TNode< UintPtrT > TimesTaggedSize(TNode< UintPtrT > value)
TNode< IntPtrT > ParameterToIntPtr(TNode< UintPtrT > value)
void UnsafeStoreFixedArrayElement(TNode< FixedArray > object, int index, TNode< Smi > value)
TNode< A > SelectConstant(TNode< BoolT > condition, TNode< A > true_value, TNode< A > false_value)
void FillEntireFixedArrayWithSmiZero(ElementsKind kind, TNode< FixedArray > array, TNode< IntPtrT > length)
int32_t ConstexprUint32Sub(uint32_t a, uint32_t b)
void StoreReference(Reference reference, TNode< T > value)
TNode< WordT > UpdateWord32InWord(TNode< WordT > word, TNode< Uint32T > value, bool starts_as_zero=false)
TNode< IntPtrT > FeedbackIteratorHandlerOffset()
TNode< RawPtrT > LoadJSTypedArrayExternalPointerPtr(TNode< JSTypedArray > holder)
void StoreCodePointerField(TNode< HeapObject > object, int offset, TNode< Code > value)
void SetNumberOfDeletedElements(TNode< Dictionary > dictionary, TNode< Smi > num_deleted_smi)
void StoreFixedArrayElement(TNode< FixedArray > object, int index, TNode< Object > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER, CheckBounds check_bounds=CheckBounds::kAlways)
void BuildFastLoop(TVariable< TIndex > &var_index, TNode< TIndex > start_index, TNode< TIndex > end_index, const FastLoopBody< TIndex > &body, int increment, LoopUnrollingMode unrolling_mode, IndexAdvanceMode advance_mode=IndexAdvanceMode::kPre)
TNode< Object > UnsafeLoadFixedArrayElement(TNode< FixedArray > object, TNode< IntPtrT > index, int additional_offset=0)
bool IsFastElementsKind(ElementsKind kind)
TNode< JSReceiver > Construct(TNode< Context > context, TNode< JSReceiver > new_target, TArgs... args)
void FillEntireFixedDoubleArrayWithZero(TNode< FixedDoubleArray > array, TNode< IntPtrT > length)
TNode< IntPtrT > OffsetOfElementAt(TNode< TIndex > index)
void StorePropertyArrayElement(TNode< PropertyArray > array, TNode< IntPtrT > index, TNode< Object > value)
TNode< FixedArray > AllocateUninitializedFixedArray(intptr_t capacity)
TNode< Smi > GetNameDictionaryFlags(TNode< Dictionary > dictionary)
TNode< Smi > SmiFromIntPtr(TNode< IntPtrT > value)
TNode< Object > LoadConstructorOrBackPointer(TNode< Map > map)
TNode< String > HeapObjectToString(TNode< HeapObject > heap_object, Label *fail)
TNode< Smi > SmiSar(TNode< Smi > a, int shift)
TNode< UintPtrT > DecodeWord(TNode< WordT > word)
TNode< UintPtrT > TimesDoubleSize(TNode< UintPtrT > value)
TNode< JSAny > GetProperty(TNode< Context > context, TNode< JSAny > receiver, Handle< Name > name)
TNode< JSStringIterator > HeapObjectToJSStringIterator(TNode< HeapObject > heap_object, Label *fail)
TNode< BoolT > IsNotEqualInWord32(TNode< Word32T > word32, typename BitField::FieldType value)
void SetNameDictionaryFlags(TNode< Dictionary >, TNode< Smi > flags)
TNode< Smi > LoadBufferSmi(TNode< RawPtrT > buffer, int offset)
TNode< Smi > UnsignedSmiShl(TNode< Smi > a, int shift)
void BranchIfNumberLessThanOrEqual(TNode< Number > left, TNode< Number > right, Label *if_true, Label *if_false)
TNode< Simd128T > LoadSimd128(TNode< IntPtrT > ptr)
TNode< BoolT > IsAdditiveSafeIntegerFeedbackEnabled()
void BuildFastLoop(TNode< TIndex > start_index, TNode< TIndex > end_index, const FastLoopBody< TIndex > &body, int increment, LoopUnrollingMode unrolling_mode, IndexAdvanceMode advance_mode=IndexAdvanceMode::kPre)
TNode< FixedDoubleArray > AllocateZeroedFixedDoubleArray(TNode< IntPtrT > capacity)
void SetNextEnumerationIndex(TNode< Dictionary > dictionary, TNode< Smi > next_enum_index_smi)
TNode< Word32T > JSParameterCount(TNode< Word32T > argc_without_receiver)
TNode< Float32T > ChangeFloat16ToFloat32(TNode< Float16RawBitsT > value)
TNode< RawPtrT > LoadExternalStringResourcePtr(TNode< ExternalString > object)
uintptr_t ConstexprUintPtrAdd(uintptr_t a, uintptr_t b)
TNode< Word32T > UpdateWord32(TNode< Word32T > word, TNode< Uint32T > value, bool starts_as_zero=false)
void BranchIfStringEqual(TNode< String > lhs, TNode< String > rhs, Label *if_true, Label *if_false, TVariable< Boolean > *result=nullptr)
TNode< Smi > LoadSmiArrayLength(TNode< Array > array)
void BranchIfSmiLessThanOrEqual(TNode< Smi > a, TNode< Smi > b, Label *if_true, Label *if_false)
TNode< BoolT > TaggedEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< FixedArrayBase > LoadElements(TNode< JSObject > object)
void StoreExternalPointerToObject(TNode< HeapObject > object, int offset, TNode< RawPtrT > pointer, ExternalPointerTag tag)
TNode< T > LoadObjectField(TNode< HeapObject > object, int offset)
int8_t ConstexprIntegerLiteralToInt8(const IntegerLiteral &i)
TNode< Boolean > RelationalComparison(Operation op, TNode< Object > left, TNode< Object > right, TNode< Context > context, TVariable< Smi > *var_type_feedback=nullptr)
TNode< BoolT > IsNotSetWord32(TNode< Word32T > word32)
TNode< BoolT > IsPageFlagReset(TNode< IntPtrT > object, int mask)
TNode< BoolT > TaggedNotEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< Smi > TaggedToPositiveSmi(TNode< Object > value, Label *fail)
TNode< IntPtrT > GetArrayAllocationSize(TNode< TIndex > element_count, ElementsKind kind, int header_size)
bool ConstexprUint32NotEqual(uint32_t a, uint32_t b)
TNode< UintPtrT > LoadBoundedSizeFromObject(TNode< HeapObject > object, int offset)
TNode< BoolT > ElementsKindEqual(TNode< Int32T > a, TNode< Int32T > b)
bool ToParameterConstant(TNode< Smi > node, intptr_t *out)
TNode< IntPtrT > ChangePositiveInt32ToIntPtr(TNode< Int32T > input)
TNode< BoolT > IsInRange(TNode< UintPtrT > value, TNode< UintPtrT > lower_limit, TNode< UintPtrT > higher_limit)
uintptr_t ConstexprIntegerLiteralToUintptr(const IntegerLiteral &i)
TNode< Uint32T > GetSortedKeyIndex(TNode< Array > descriptors, TNode< Uint32T > entry_index)
void UnsafeStoreArrayElement(TNode< Array > object, int index, TNode< typename Array::Shape::ElementT > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER)
void EmitElementStoreTypedArrayUpdateValue(TNode< Object > value, ElementsKind elements_kind, TNode< TValue > converted_value, TVariable< Object > *maybe_converted_value)
TNode< Smi > GetNumberOfDeletedElements(TNode< Dictionary > dictionary)
void Decrement(TVariable< TIndex > *variable, int value=1)
TNode< BoolT > LoadRuntimeFlag(ExternalReference address_of_flag)
void InitializeJSAPIObjectWithEmbedderSlotsCppHeapWrapperPtr(TNode< JSAPIObjectWithEmbedderSlots > holder)
TNode< IntPtrT > ParameterToIntPtr(TNode< IntPtrT > value)
TNode< RawPtrT > LoadExternalPointerFromObject(TNode< HeapObject > object, int offset, ExternalPointerTagRange tag_range)
TNode< JSCallable > HeapObjectToCallable(TNode< HeapObject > heap_object, Label *fail)
void FixedArrayBoundsCheck(TNode< FixedArray > array, TNode< IntPtrT > index, int additional_offset)
TNode< T > LoadReference(Reference reference)
void SetNumberOfElements(TNode< Dictionary > dictionary, TNode< Smi > num_elements_smi)
TNode< BoolT > IsSetWord32(TNode< Word32T > word32)
void StoreFixedArrayElement(TNode< FixedArray > array, TNode< TIndex > index, TNode< Object > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER, int additional_offset=0, CheckBounds check_bounds=CheckBounds::kAlways)
void StoreCodePointerFieldNoWriteBarrier(TNode< HeapObject > object, int offset, TNode< Code > value)
TNode< T > LoadReference(Reference reference)
TNode< BoolT > IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate()
TNode< BoolT > IsNotCleared(TNode< MaybeObject > value)
TNode< BoolT > IsAllSetWord32(TNode< Word32T > word32, uint32_t mask)
TNode< JSReceiver > HeapObjectToConstructor(TNode< HeapObject > heap_object, Label *fail)
void CopyFixedArrayElements(ElementsKind kind, TNode< FixedArrayBase > from_array, TNode< FixedArrayBase > to_array, TNode< TIndex > length, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER)
TNode< FixedArray > AllocateZeroedFixedArray(TNode< IntPtrT > capacity)
TNode< Word32T > UpdateWordInWord32(TNode< Word32T > word, TNode< UintPtrT > value, bool starts_as_zero=false)
TNode< Uint16T > Uint16Constant(uint16_t t)
TNode< BoolT > IsSetWord(TNode< WordT > word)
TNode< TIndex > TaggedToParameter(TNode< Smi > value)
TNode< BoolT > IsSetSmi(TNode< Smi > smi, int untagged_mask)
void FillFixedArrayWithValue(ElementsKind kind, TNode< FixedArray > array, TNode< TIndex > from_index, TNode< TIndex > to_index, RootIndex value_root_index)
void PrintErr(TNode< MaybeObject > tagged_value)
TNode< Object > CallApiCallback(TNode< Object > context, TNode< RawPtrT > callback, TNode< Int32T > argc, TNode< Object > data, TNode< Object > holder, TNode< JSAny > receiver)
TNode< BoolT > IsNotSetWord32(TNode< Word32T > word32, uint32_t mask)
TNode< JSArray > AllocateJSArray(ElementsKind kind, TNode< Map > array_map, TNode< Smi > capacity, TNode< Smi > length, std::optional< TNode< AllocationSite > > allocation_site, AllocationFlags allocation_flags=AllocationFlag::kNone)
TNode< Object > LoadRoot(RootIndex root_index)
TNode< Uint32T > DecodeWord32(TNode< Word32T > word32)
TNode< HeapObject > TaggedToHeapObject(TNode< Object > value, Label *fail)
intptr_t ConstexprIntPtrAdd(intptr_t a, intptr_t b)
TNode< Smi > WordOrSmiShr(TNode< Smi > a, int shift)
TNode< IntPtrT > TimesDoubleSize(TNode< IntPtrT > value)
bool ConstexprInt31NotEqual(int31_t a, int31_t b)
void BranchIfNumberEqual(TNode< Number > left, TNode< Number > right, Label *if_true, Label *if_false)
TNode< Smi > SelectSmiConstant(TNode< BoolT > condition, Tagged< Smi > true_value, int false_value)
uint8_t ConstexprIntegerLiteralToUint8(const IntegerLiteral &i)
uint64_t ConstexprIntegerLiteralToUint64(const IntegerLiteral &i)
void BranchIfSmiLessThan(TNode< Smi > a, TNode< Smi > b, Label *if_true, Label *if_false)
TNode< JSFunction > AllocateRootFunctionWithContext(intptr_t function, TNode< Context > context, TNode< NativeContext > native_context)
void StoreJSTypedArrayExternalPointerPtr(TNode< JSTypedArray > holder, TNode< RawPtrT > value)
int32_t ConstexprWord32Or(int32_t a, int32_t b)
void BuildFastLoop(const VariableList &vars, TNode< TIndex > start_index, TNode< TIndex > end_index, const FastLoopBody< TIndex > &body, int increment, LoopUnrollingMode unrolling_mode, IndexAdvanceMode advance_mode)
bool ConstexprInt32Equal(int32_t a, int32_t b)
TNode< TResult > LoadElementAndPrepareForStore(TNode< FixedArrayBase > array, TNode< IntPtrT > offset, ElementsKind from_kind, ElementsKind to_kind, Label *if_hole)
std::function< void( TNode< JSAnyNotSmi > receiver, TNode< JSAnyNotSmi > holder, TNode< Map > map, TNode< Int32T > instance_type, TNode< Name > key, Label *next_holder, Label *if_bailout)> LookupPropertyInHolder
TNode< Object > LoadProtectedPointerField(TNode< TrustedObject > object, int offset)
TNode< RawPtrT > LoadSandboxedPointerFromObject(TNode< HeapObject > object, int offset)
void GotoIfContextElementEqual(TNode< Object > value, TNode< NativeContext > native_context, int slot_index, Label *if_equal)
TNode< FixedArray > AllocateFixedArrayWithHoles(TNode< IntPtrT > capacity, AllocationFlags flags=AllocationFlag::kNone)
TNode< Object > LoadAccessorPairGetter(TNode< AccessorPair > accessor_pair)
std::function< void(Label *, Label *)> BranchGenerator
TNode< Cell > AllocateSmiCell(int value=0)
std::function< void(TNode< IntPtrT > descriptor_key_index)> ForEachDescriptorBodyFunction
bool IsDoubleElementsKind(ElementsKind kind)
std::function< TNode< T >()> LazyNode
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, int offset, TNode< T > value)
TNode< Smi > ParameterToTagged(TNode< Smi > value)
std::function< void(TNode< HeapObject > array, TNode< IntPtrT > offset)> FastArrayForEachBody
TNode< IntPtrT > SmiToIntPtr(TNode< Smi > value)
TNode< BoolT > IsClearWord32(TNode< Word32T > word32)
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< T > value)
TNode< FixedDoubleArray > AllocateFixedDoubleArrayWithHoles(TNode< IntPtrT > capacity, AllocationFlags flags=AllocationFlag::kNone)
TNode< IntPtrT > TimesTaggedSize(TNode< IntPtrT > value)
TNode< HeapObject > LoadName(TNode< HeapObject > key)
TNode< Object > UnsafeLoadFixedArrayElement(TNode< FixedArray > object, int index, int additional_offset=0)
TNode< RawPtrT > LoadFunctionTemplateInfoJsCallbackPtr(TNode< FunctionTemplateInfo > object)
TNode< T > LoadBufferData(TNode< RawPtrT > buffer, int offset)
TNode< Object > LoadFixedArrayElement(TNode< FixedArray > object, int index, int additional_offset=0)
TNode< IntPtrT > WordOrSmiShr(TNode< IntPtrT > a, int shift)
TNode< IntPtrT > EntryToIndex(TNode< IntPtrT > entry)
TNode< BoolT > IsPageFlagSet(TNode< IntPtrT > object, int mask)
void UnsafeStoreFixedArrayElement(TNode< FixedArray > object, int index, TNode< Object > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER)
TNode< Smi > SmiShr(TNode< Smi > a, int shift)
TNode< Boolean > HasProperty_Inline(TNode< Context > context, TNode< JSReceiver > object, TNode< Object > key)
bool ConstexprInt32NotEqual(int32_t a, int32_t b)
TNode< JSFunction > HeapObjectToJSFunctionWithPrototypeSlot(TNode< HeapObject > heap_object, Label *fail)
TNode< IntPtrT > ParameterToIntPtr(TNode< TaggedIndex > value)
TNode< BoolT > IsClearWord32(TNode< Word32T > word32, uint32_t mask)
TNode< Object > LoadObjectField(TNode< HeapObject > object, int offset)
int31_t ConstexprInt31Mul(int31_t a, int31_t b)
void BranchIfNumberLessThan(TNode< Number > left, TNode< Number > right, Label *if_true, Label *if_false)
TNode< IntPtrT > GetPropertyArrayAllocationSize(TNode< IntPtrT > element_count)
TNode< Object > CreateDataProperty(TNode< Context > context, TNode< JSObject > receiver, TNode< Object > key, TNode< Object > value)
TNode< Smi > ParameterToTagged(TNode< IntPtrT > value)
TNode< RawPtrT > GCUnsafeReferenceToRawPtr(TNode< Object > object, TNode< IntPtrT > offset)
TNode< JSReceiver > ConstructWithTarget(TNode< Context > context, TNode< JSReceiver > target, TNode< JSReceiver > new_target, TArgs... args)
int32_t ConstexprInt32Add(int32_t a, int32_t b)
bool UpdateFeedbackModeEqual(UpdateFeedbackMode a, UpdateFeedbackMode b)
void Bind(compiler::CodeAssemblerParameterizedLabel< T... > *label, TNode< T > *... phis)
TNode< T > RunLazy(LazyNode< T > lazy)
TNode< Boolean > Equal(TNode< Object > lhs, TNode< Object > rhs, TNode< Context > context, TVariable< Smi > *var_type_feedback=nullptr)
TNode< Uint32T > DecodeWord32FromWord(TNode< WordT > word)
TNode< BoolT > IsInRange(TNode< WordT > value, intptr_t lower_limit, intptr_t higher_limit)
constexpr int MaxNumberOfEntries()
int31_t ConstexprInt31Add(int31_t a, int31_t b)
TNode< T > PrepareValueForWriteToTypedArray(TNode< Object > input, ElementsKind elements_kind, TNode< Context > context)
void BranchIfAccessorPair(TNode< Object > value, Label *if_accessor_pair, Label *if_not_accessor_pair)
TNode< T > Select(TNode< BoolT > condition, const NodeGenerator< T > &true_body, const NodeGenerator< T > &false_body, BranchHint branch_hint=BranchHint::kNone)
TNode< RawPtrT > ExternalPointerTableAddress(ExternalPointerTagRange tag_range)
double ConstexprIntegerLiteralToFloat64(const IntegerLiteral &i)
TNode< RawPtrT > LoadForeignForeignAddressPtr(TNode< Foreign > object, ExternalPointerTag tag)
uint32_t ConstexprUint32Add(uint32_t a, uint32_t b)
void StoreBoundedSizeToObject(TNode< HeapObject > object, int offset, TNode< UintPtrT > value)
TNode< BoolT > IsDictionaryElementsKind(TNode< Int32T > elements_kind)
TNode< Object > SetPropertyStrict(TNode< Context > context, TNode< JSAny > receiver, TNode< Object > key, TNode< Object > value)
void CopyFixedArrayElements(ElementsKind from_kind, TNode< FixedArrayBase > from_array, ElementsKind to_kind, TNode< FixedArrayBase > to_array, TNode< TIndex > element_count, TNode< TIndex > capacity, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER)
void BranchIfSmiEqual(TNode< Smi > a, TNode< Smi > b, Label *if_true, Label *if_false)
TNode< Int32T > JSParameterCount(int argc_without_receiver)
TNode< String > ToThisString(TNode< Context > context, TNode< Object > value, char const *method_name)
bool ConstexprUint32Equal(uint32_t a, uint32_t b)
bool ConstexprIntegerLiteralEqual(IntegerLiteral lhs, IntegerLiteral rhs)
TNode< BoolT > IsClearWord(TNode< WordT > word)
TNode< AnyTaggedT > LoadRootMapWord(RootIndex root_index)
void FixedArrayBoundsCheck(TNode< FixedArrayBase > array, TNode< UintPtrT > index, int additional_offset)
int32_t ConstexprInt32Sub(int32_t a, int32_t b)
void BranchIfNumberNotEqual(TNode< Number > left, TNode< Number > right, Label *if_true, Label *if_false)
void UnsafeStoreArrayElement(TNode< Array > object, TNode< Smi > index, TNode< typename Array::Shape::ElementT > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER)
TNode< TIndex > IntPtrOrSmiConstant(int value)
TNode< JSAny > GetProperty(TNode< Context > context, TNode< JSAny > receiver, TNode< Object > name)
TNode< Smi > SelectSmiConstant(TNode< BoolT > condition, int true_value, Tagged< Smi > false_value)
TNode< Float16RawBitsT > TruncateFloat32ToFloat16(TNode< Float32T > value)
TNode< BoolT > IsSetWord32(TNode< Word32T > word32, uint32_t mask)
TNode< IntPtrT > LoadArrayLength(TNode< Array > array)
void BranchIfNumberGreaterThan(TNode< Number > left, TNode< Number > right, Label *if_true, Label *if_false)
void BranchIfToBooleanIsFalse(TNode< Object > value, Label *if_false, Label *if_true)
TNode< Object > LoadAccessorPairSetter(TNode< AccessorPair > accessor_pair)
TNode< typename Array::Shape::ElementT > LoadArrayElement(TNode< Array > array, TNode< TIndex > index, int additional_offset=0)
uintptr_t ConstexprUintPtrShr(uintptr_t a, int32_t b)
uint32_t ConstexprWord32Shl(uint32_t a, int32_t b)
void FixedArrayBoundsCheck(TNode< FixedArray > array, TNode< TaggedIndex > index, int additional_offset)
TNode< Number > SmiToNumber(TNode< Smi > v)
TNode< BoolT > IsScriptContextMutableHeapInt32Flag()
TNode< RawPtrT > LoadExternalStringResourceDataPtr(TNode< ExternalString > object)
TNode< UintPtrT > TimesSystemPointerSize(TNode< UintPtrT > value)
void BranchIfFloat64IsNaN(TNode< Float64T > value, Label *if_true, Label *if_false)
TNode< BoolT > IsBothEqualInWord32(TNode< Word32T > word32, typename BitField1::FieldType value1, typename BitField2::FieldType value2)
TNode< UintPtrT > DecodeWordFromWord32(TNode< Word32T > word32)
TNode< BoolT > IsInRange(TNode< Word32T > value, U lower_limit, U higher_limit)
TNode< HeapNumber > AllocateHeapNumberWithValue(double value)
std::function< void(TNode< Name > key, LazyNode< Object > value)> ForEachKeyValueFunction
int32_t ConstexprIntegerLiteralToInt32(const IntegerLiteral &i)
TNode< Smi > GetCapacity(TNode< Dictionary > dictionary)
bool ToParameterConstant(TNode< IntPtrT > node, intptr_t *out)
void UnsafeStoreFixedArrayElement(TNode< FixedArray > array, TNode< IntPtrT > index, TNode< Smi > value, int additional_offset)
TNode< JSArray > AllocateJSArray(ElementsKind kind, TNode< Map > array_map, TNode< Smi > capacity, TNode< Smi > length, AllocationFlags allocation_flags=AllocationFlag::kNone)
bool ConstexprInt32GreaterThanEqual(int32_t a, int32_t b)
TNode< Uint32T > NumberOfEntries(TNode< Array > array)
TNode< IntPtrT > LoadBufferIntptr(TNode< RawPtrT > buffer, int offset)
int64_t ConstexprIntegerLiteralToInt64(const IntegerLiteral &i)
bool ConstexprInt31GreaterThanEqual(int31_t a, int31_t b)
TNode< IntPtrT > TimesSystemPointerSize(TNode< IntPtrT > value)
TNode< Smi > GetNextEnumerationIndex(TNode< Dictionary > dictionary)
void StoreFixedArrayElement(TNode< FixedArray > object, int index, TNode< Smi > value, CheckBounds check_bounds=CheckBounds::kAlways)
bool ElementsKindEqual(ElementsKind a, ElementsKind b)
TNode< BoolT > IsClearWord(TNode< WordT > word, uint32_t mask)
int31_t ConstexprIntegerLiteralToInt31(const IntegerLiteral &i)
PrototypeCheckAssembler(compiler::CodeAssemblerState *state, Flags flags, TNode< NativeContext > native_context, TNode< Map > initial_prototype_map, base::Vector< DescriptorIndexNameValue > properties)
const TNode< NativeContext > native_context_
void CheckAndBranch(TNode< HeapObject > prototype, Label *if_unmodified, Label *if_modified)
const base::Vector< DescriptorIndexNameValue > properties_
TNode< String > TryToDirect(Label *if_bailout)
TNode< RawPtrT > TryToSequential(StringPointerKind ptr_kind, Label *if_bailout)
ToDirectStringAssembler(compiler::CodeAssemblerState *state, TNode< String > string, Flags flags=Flags())
TNode< RawPtrT > PointerToData(Label *if_bailout)
TNode< RawPtrT > PointerToString(Label *if_bailout)
#define CAST(x)
#define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name)
#define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name)
#define CLASS_MAP_CONSTANT_ADAPTER(V, rootIndexName, rootAccessorName, class_name)
#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName)
#define BINT_COMPARISON_OP(BIntOpName, SmiOpName, IntPtrOpName)
#define SMI_COMPARISON_OP(SmiOpName, IntPtrOpName, Int32OpName)
#define SMI_ARITHMETIC_BINOP(SmiOpName, IntPtrOpName, Int32OpName)
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
int start
int end
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
Label label
BytecodeAssembler & assembler_
Isolate * isolate
#define HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(V)
#define HEAP_IMMOVABLE_OBJECT_LIST(V)
#define HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(V)
#define UNIQUE_INSTANCE_TYPE_MAP_LIST_GENERATOR(V, _)
int32_t offset
TNode< Context > context
TNode< Object > receiver
ArrayReduceDirection direction
TNode< Object > callback
#define _
double increment
ZoneVector< RpoNumber > & result
int y
int x
uint32_t const mask
AllocationFlags
InstructionOperand source
const int length_
Definition mul-fft.cc:473
v8::SourceLocation SourceLocation
PropertiesEnumerationMode
Definition globals.h:2856
constexpr int kTaggedSize
Definition globals.h:542
constexpr int kInt64Size
Definition globals.h:402
@ SKIP_WRITE_BARRIER
Definition objects.h:52
@ UPDATE_WRITE_BARRIER
Definition objects.h:55
@ UNSAFE_SKIP_WRITE_BARRIER
Definition objects.h:53
bool IsNumeric(Tagged< Object > obj)
OrdinaryToPrimitiveHint
Definition globals.h:1860
bool IsSpecialReceiverInstanceType(InstanceType instance_type)
const int kSmiTagSize
Definition v8-internal.h:87
const uint32_t kUncachedExternalStringTag
bool IsGeneratorFunction(FunctionKind kind)
const uint32_t kUncachedExternalStringMask
bool IsSpecialReceiverMap(Tagged< Map > map)
int ToNumber(Register reg)
constexpr uint64_t kMaxSafeIntegerUint64
Definition globals.h:1983
constexpr int kJSArgcReceiverSlots
Definition globals.h:2778
bool IsCustomElementsReceiverInstanceType(InstanceType instance_type)
bool IsNullOrUndefined(Tagged< Object > obj, Isolate *isolate)
constexpr int U
constexpr int kSystemPointerSize
Definition globals.h:410
bool IsFastPackedElementsKind(ElementsKind kind)
bool NeedsBoundsCheck(CheckBounds check_bounds)
constexpr bool SmiValuesAre31Bits()
constexpr bool CanBeTaggedPointer(MachineRepresentation rep)
typename detail::FlattenUnionHelper< Union<>, Ts... >::type UnionOf
Definition union.h:123
constexpr int kInt32Size
Definition globals.h:401
bool IsFastElementsKind(ElementsKind kind)
return ComputeSeededHash(static_cast< uint32_t >(key), HashSeed(isolate))
const int kHeapObjectTag
Definition v8-internal.h:72
Tagged< ClearedWeakValue > ClearedValue(PtrComprCageBase cage_base)
const int kSmiShiftSize
@ kExternalStringResourceTag
@ kExternalStringResourceDataTag
@ kFunctionTemplateInfoCallbackTag
bool IsUniqueName(Tagged< Name > obj)
constexpr bool SmiValuesAre32Bits()
bool ElementsKindEqual(ElementsKind a, ElementsKind b)
constexpr bool Is64()
bool IsStringWrapperElementsKind(ElementsKind kind)
constexpr bool IsDoubleElementsKind(ElementsKind kind)
constexpr intptr_t kDoubleAlignment
Definition globals.h:949
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&a)[N])
i::Address Load(i::Address address)
Definition unwinder.cc:19
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
V8_INLINE A implicit_cast(A x)
Definition macros.h:306
#define V8_EXPORT_PRIVATE
Definition macros.h:460
std::tuple< TNode< Object >, TNode< IntPtrT > > Flatten() const
#define OFFSET_OF_DATA_START(Type)
std::unique_ptr< ValueMirror > value
std::unique_ptr< ValueMirror > key