5 #include "src/code-stub-assembler.h" 7 #include "src/code-factory.h" 8 #include "src/counters.h" 9 #include "src/frames-inl.h" 10 #include "src/frames.h" 11 #include "src/objects/api-callbacks.h" 12 #include "src/objects/descriptor-array.h" 13 #include "src/objects/ordered-hash-table-inl.h" 14 #include "src/wasm/wasm-objects.h" 21 using TNode = compiler::TNode<T>;
23 using SloppyTNode = compiler::SloppyTNode<T>;
25 CodeStubAssembler::CodeStubAssembler(compiler::CodeAssemblerState* state)
27 if (DEBUG_BOOL && FLAG_csa_trap_on_node !=
nullptr) {
32 void CodeStubAssembler::HandleBreakOnNode() {
35 const char* name = state()->name();
36 size_t name_length = strlen(name);
37 if (strncmp(FLAG_csa_trap_on_node, name, name_length) != 0) {
41 size_t option_length = strlen(FLAG_csa_trap_on_node);
42 if (option_length < name_length + 2 ||
43 FLAG_csa_trap_on_node[name_length] !=
',') {
47 const char* start = &FLAG_csa_trap_on_node[name_length + 1];
49 int node_id =
static_cast<int>(strtol(start, &end, 10));
57 void CodeStubAssembler::Assert(
const BranchGenerator& branch,
58 const char* message,
const char* file,
int line,
59 Node* extra_node1,
const char* extra_node1_name,
60 Node* extra_node2,
const char* extra_node2_name,
61 Node* extra_node3,
const char* extra_node3_name,
62 Node* extra_node4,
const char* extra_node4_name,
64 const char* extra_node5_name) {
66 if (FLAG_debug_code) {
67 Check(branch, message, file, line, extra_node1, extra_node1_name,
68 extra_node2, extra_node2_name, extra_node3, extra_node3_name,
69 extra_node4, extra_node4_name, extra_node5, extra_node5_name);
74 void CodeStubAssembler::Assert(
const NodeGenerator& condition_body,
75 const char* message,
const char* file,
int line,
76 Node* extra_node1,
const char* extra_node1_name,
77 Node* extra_node2,
const char* extra_node2_name,
78 Node* extra_node3,
const char* extra_node3_name,
79 Node* extra_node4,
const char* extra_node4_name,
81 const char* extra_node5_name) {
83 if (FLAG_debug_code) {
84 Check(condition_body, message, file, line, extra_node1, extra_node1_name,
85 extra_node2, extra_node2_name, extra_node3, extra_node3_name,
86 extra_node4, extra_node4_name, extra_node5, extra_node5_name);
93 void MaybePrintNodeWithName(CodeStubAssembler* csa, Node* node,
94 const char* node_name) {
95 if (node !=
nullptr) {
96 csa->CallRuntime(Runtime::kPrintWithNameForAssert, csa->SmiConstant(0),
97 csa->StringConstant(node_name), node);
103 void CodeStubAssembler::Check(
const BranchGenerator& branch,
104 const char* message,
const char* file,
int line,
105 Node* extra_node1,
const char* extra_node1_name,
106 Node* extra_node2,
const char* extra_node2_name,
107 Node* extra_node3,
const char* extra_node3_name,
108 Node* extra_node4,
const char* extra_node4_name,
109 Node* extra_node5,
const char* extra_node5_name) {
111 Label not_ok(
this, Label::kDeferred);
112 if (message !=
nullptr && FLAG_code_comments) {
113 Comment(
"[ Assert: %s", message);
117 branch(&ok, ¬_ok);
120 FailAssert(message, file, line, extra_node1, extra_node1_name, extra_node2,
121 extra_node2_name, extra_node3, extra_node3_name, extra_node4,
122 extra_node4_name, extra_node5, extra_node5_name);
128 void CodeStubAssembler::Check(
const NodeGenerator& condition_body,
129 const char* message,
const char* file,
int line,
130 Node* extra_node1,
const char* extra_node1_name,
131 Node* extra_node2,
const char* extra_node2_name,
132 Node* extra_node3,
const char* extra_node3_name,
133 Node* extra_node4,
const char* extra_node4_name,
134 Node* extra_node5,
const char* extra_node5_name) {
135 BranchGenerator branch = [=](Label* ok, Label* not_ok) {
136 Node* condition = condition_body();
137 DCHECK_NOT_NULL(condition);
138 Branch(condition, ok, not_ok);
141 Check(branch, message, file, line, extra_node1, extra_node1_name, extra_node2,
142 extra_node2_name, extra_node3, extra_node3_name, extra_node4,
143 extra_node4_name, extra_node5, extra_node5_name);
146 void CodeStubAssembler::FastCheck(TNode<BoolT> condition) {
148 GotoIf(condition, &ok);
154 void CodeStubAssembler::FailAssert(
155 const char* message,
const char* file,
int line, Node* extra_node1,
156 const char* extra_node1_name, Node* extra_node2,
157 const char* extra_node2_name, Node* extra_node3,
158 const char* extra_node3_name, Node* extra_node4,
159 const char* extra_node4_name, Node* extra_node5,
160 const char* extra_node5_name) {
161 DCHECK_NOT_NULL(message);
163 Vector<char> buffer(chars);
164 if (file !=
nullptr) {
165 SNPrintF(buffer,
"CSA_ASSERT failed: %s [%s:%d]\n", message, file, line);
167 SNPrintF(buffer,
"CSA_ASSERT failed: %s\n", message);
169 Node* message_node = StringConstant(&(buffer[0]));
173 MaybePrintNodeWithName(
this, extra_node1, extra_node1_name);
174 MaybePrintNodeWithName(
this, extra_node2, extra_node2_name);
175 MaybePrintNodeWithName(
this, extra_node3, extra_node3_name);
176 MaybePrintNodeWithName(
this, extra_node4, extra_node4_name);
177 MaybePrintNodeWithName(
this, extra_node5, extra_node5_name);
180 DebugAbort(message_node);
184 Node* CodeStubAssembler::SelectImpl(TNode<BoolT> condition,
185 const NodeGenerator& true_body,
186 const NodeGenerator& false_body,
187 MachineRepresentation rep) {
188 VARIABLE(value, rep);
189 Label vtrue(
this), vfalse(
this), end(
this);
190 Branch(condition, &vtrue, &vfalse);
194 value.Bind(true_body());
199 value.Bind(false_body());
204 return value.value();
207 TNode<Int32T> CodeStubAssembler::SelectInt32Constant(
208 SloppyTNode<BoolT> condition,
int true_value,
int false_value) {
209 return SelectConstant<Int32T>(condition, Int32Constant(true_value),
210 Int32Constant(false_value));
213 TNode<IntPtrT> CodeStubAssembler::SelectIntPtrConstant(
214 SloppyTNode<BoolT> condition,
int true_value,
int false_value) {
215 return SelectConstant<IntPtrT>(condition, IntPtrConstant(true_value),
216 IntPtrConstant(false_value));
219 TNode<Oddball> CodeStubAssembler::SelectBooleanConstant(
220 SloppyTNode<BoolT> condition) {
221 return SelectConstant<Oddball>(condition, TrueConstant(), FalseConstant());
224 TNode<Smi> CodeStubAssembler::SelectSmiConstant(SloppyTNode<BoolT> condition,
227 return SelectConstant<Smi>(condition, SmiConstant(true_value),
228 SmiConstant(false_value));
231 TNode<Object> CodeStubAssembler::NoContextConstant() {
232 return SmiConstant(Context::kNoContext);
235 #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ 236 compiler::TNode<std::remove_pointer<std::remove_reference<decltype( \ 237 std::declval<Heap>().rootAccessorName())>::type>::type> \ 238 CodeStubAssembler::name##Constant() { \ 239 return UncheckedCast<std::remove_pointer<std::remove_reference<decltype( \ 240 std::declval<Heap>().rootAccessorName())>::type>::type>( \ 241 LoadRoot(RootIndex::k##rootIndexName)); \ 243 HEAP_MUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR);
244 #undef HEAP_CONSTANT_ACCESSOR 246 #define HEAP_CONSTANT_ACCESSOR(rootIndexName, rootAccessorName, name) \ 247 compiler::TNode<std::remove_pointer<std::remove_reference<decltype( \ 248 std::declval<ReadOnlyRoots>().rootAccessorName())>::type>::type> \ 249 CodeStubAssembler::name##Constant() { \ 250 return UncheckedCast<std::remove_pointer<std::remove_reference<decltype( \ 251 std::declval<ReadOnlyRoots>().rootAccessorName())>::type>::type>( \ 252 LoadRoot(RootIndex::k##rootIndexName)); \ 254 HEAP_IMMUTABLE_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_ACCESSOR);
255 #undef HEAP_CONSTANT_ACCESSOR 257 #define HEAP_CONSTANT_TEST(rootIndexName, rootAccessorName, name) \ 258 compiler::TNode<BoolT> CodeStubAssembler::Is##name( \ 259 SloppyTNode<Object> value) { \ 260 return WordEqual(value, name##Constant()); \ 262 compiler::TNode<BoolT> CodeStubAssembler::IsNot##name( \ 263 SloppyTNode<Object> value) { \ 264 return WordNotEqual(value, name##Constant()); \ 266 HEAP_IMMOVABLE_OBJECT_LIST(HEAP_CONSTANT_TEST);
267 #undef HEAP_CONSTANT_TEST 269 Node* CodeStubAssembler::IntPtrOrSmiConstant(
int value, ParameterMode mode) {
270 if (mode == SMI_PARAMETERS) {
271 return SmiConstant(value);
273 DCHECK_EQ(INTPTR_PARAMETERS, mode);
274 return IntPtrConstant(value);
278 bool CodeStubAssembler::IsIntPtrOrSmiConstantZero(Node* test,
279 ParameterMode mode) {
280 int32_t constant_test;
282 if (mode == INTPTR_PARAMETERS) {
283 if (ToInt32Constant(test, constant_test) && constant_test == 0) {
287 DCHECK_EQ(mode, SMI_PARAMETERS);
288 if (ToSmiConstant(test, &smi_test) && smi_test->value() == 0) {
295 bool CodeStubAssembler::TryGetIntPtrOrSmiConstantValue(Node* maybe_constant,
297 ParameterMode mode) {
298 int32_t int32_constant;
299 if (mode == INTPTR_PARAMETERS) {
300 if (ToInt32Constant(maybe_constant, int32_constant)) {
301 *value = int32_constant;
305 DCHECK_EQ(mode, SMI_PARAMETERS);
307 if (ToSmiConstant(maybe_constant, &smi_constant)) {
308 *value = Smi::ToInt(smi_constant);
315 TNode<IntPtrT> CodeStubAssembler::IntPtrRoundUpToPowerOfTwo32(
316 TNode<IntPtrT> value) {
317 Comment(
"IntPtrRoundUpToPowerOfTwo32");
318 CSA_ASSERT(
this, UintPtrLessThanOrEqual(value, IntPtrConstant(0x80000000u)));
319 value = Signed(IntPtrSub(value, IntPtrConstant(1)));
320 for (
int i = 1;
i <= 16;
i *= 2) {
321 value = Signed(WordOr(value, WordShr(value, IntPtrConstant(
i))));
323 return Signed(IntPtrAdd(value, IntPtrConstant(1)));
326 Node* CodeStubAssembler::MatchesParameterMode(Node* value, ParameterMode mode) {
327 if (mode == SMI_PARAMETERS) {
328 return TaggedIsSmi(value);
330 return Int32Constant(1);
334 TNode<BoolT> CodeStubAssembler::WordIsPowerOfTwo(SloppyTNode<IntPtrT> value) {
338 WordEqual(value, IntPtrConstant(0)),
339 [=] {
return IntPtrConstant(1); },
340 [=] {
return WordAnd(value, IntPtrSub(value, IntPtrConstant(1))); }),
344 TNode<Float64T> CodeStubAssembler::Float64Round(SloppyTNode<Float64T> x) {
345 Node* one = Float64Constant(1.0);
346 Node* one_half = Float64Constant(0.5);
348 Label return_x(
this);
351 VARIABLE(var_x, MachineRepresentation::kFloat64, Float64Ceil(x));
353 GotoIf(Float64LessThanOrEqual(Float64Sub(var_x.value(), one_half), x),
355 var_x.Bind(Float64Sub(var_x.value(), one));
359 return TNode<Float64T>::UncheckedCast(var_x.value());
362 TNode<Float64T> CodeStubAssembler::Float64Ceil(SloppyTNode<Float64T> x) {
363 if (IsFloat64RoundUpSupported()) {
364 return Float64RoundUp(x);
367 Node* one = Float64Constant(1.0);
368 Node* zero = Float64Constant(0.0);
369 Node* two_52 = Float64Constant(4503599627370496.0E0);
370 Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
372 VARIABLE(var_x, MachineRepresentation::kFloat64, x);
373 Label return_x(
this), return_minus_x(
this);
376 Label if_xgreaterthanzero(
this), if_xnotgreaterthanzero(
this);
377 Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
378 &if_xnotgreaterthanzero);
380 BIND(&if_xgreaterthanzero);
383 GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
386 var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
387 GotoIfNot(Float64LessThan(var_x.value(), x), &return_x);
388 var_x.Bind(Float64Add(var_x.value(), one));
392 BIND(&if_xnotgreaterthanzero);
395 GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
396 GotoIfNot(Float64LessThan(x, zero), &return_x);
399 Node* minus_x = Float64Neg(x);
400 var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
401 GotoIfNot(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
402 var_x.Bind(Float64Sub(var_x.value(), one));
403 Goto(&return_minus_x);
406 BIND(&return_minus_x);
407 var_x.Bind(Float64Neg(var_x.value()));
411 return TNode<Float64T>::UncheckedCast(var_x.value());
414 TNode<Float64T> CodeStubAssembler::Float64Floor(SloppyTNode<Float64T> x) {
415 if (IsFloat64RoundDownSupported()) {
416 return Float64RoundDown(x);
419 Node* one = Float64Constant(1.0);
420 Node* zero = Float64Constant(0.0);
421 Node* two_52 = Float64Constant(4503599627370496.0E0);
422 Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
424 VARIABLE(var_x, MachineRepresentation::kFloat64, x);
425 Label return_x(
this), return_minus_x(
this);
428 Label if_xgreaterthanzero(
this), if_xnotgreaterthanzero(
this);
429 Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
430 &if_xnotgreaterthanzero);
432 BIND(&if_xgreaterthanzero);
435 GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
438 var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
439 GotoIfNot(Float64GreaterThan(var_x.value(), x), &return_x);
440 var_x.Bind(Float64Sub(var_x.value(), one));
444 BIND(&if_xnotgreaterthanzero);
447 GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
448 GotoIfNot(Float64LessThan(x, zero), &return_x);
451 Node* minus_x = Float64Neg(x);
452 var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
453 GotoIfNot(Float64LessThan(var_x.value(), minus_x), &return_minus_x);
454 var_x.Bind(Float64Add(var_x.value(), one));
455 Goto(&return_minus_x);
458 BIND(&return_minus_x);
459 var_x.Bind(Float64Neg(var_x.value()));
463 return TNode<Float64T>::UncheckedCast(var_x.value());
466 TNode<Float64T> CodeStubAssembler::Float64RoundToEven(SloppyTNode<Float64T> x) {
467 if (IsFloat64RoundTiesEvenSupported()) {
468 return Float64RoundTiesEven(x);
471 Node* f = Float64Floor(x);
472 Node* f_and_half = Float64Add(f, Float64Constant(0.5));
474 VARIABLE(var_result, MachineRepresentation::kFloat64);
475 Label return_f(
this), return_f_plus_one(
this), done(
this);
477 GotoIf(Float64LessThan(f_and_half, x), &return_f_plus_one);
478 GotoIf(Float64LessThan(x, f_and_half), &return_f);
480 Node* f_mod_2 = Float64Mod(f, Float64Constant(2.0));
481 Branch(Float64Equal(f_mod_2, Float64Constant(0.0)), &return_f,
489 BIND(&return_f_plus_one);
490 var_result.Bind(Float64Add(f, Float64Constant(1.0)));
494 return TNode<Float64T>::UncheckedCast(var_result.value());
497 TNode<Float64T> CodeStubAssembler::Float64Trunc(SloppyTNode<Float64T> x) {
498 if (IsFloat64RoundTruncateSupported()) {
499 return Float64RoundTruncate(x);
502 Node* one = Float64Constant(1.0);
503 Node* zero = Float64Constant(0.0);
504 Node* two_52 = Float64Constant(4503599627370496.0E0);
505 Node* minus_two_52 = Float64Constant(-4503599627370496.0E0);
507 VARIABLE(var_x, MachineRepresentation::kFloat64, x);
508 Label return_x(
this), return_minus_x(
this);
511 Label if_xgreaterthanzero(
this), if_xnotgreaterthanzero(
this);
512 Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero,
513 &if_xnotgreaterthanzero);
515 BIND(&if_xgreaterthanzero);
517 if (IsFloat64RoundDownSupported()) {
518 var_x.Bind(Float64RoundDown(x));
521 GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x);
524 var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52));
525 GotoIfNot(Float64GreaterThan(var_x.value(), x), &return_x);
526 var_x.Bind(Float64Sub(var_x.value(), one));
531 BIND(&if_xnotgreaterthanzero);
533 if (IsFloat64RoundUpSupported()) {
534 var_x.Bind(Float64RoundUp(x));
538 GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x);
539 GotoIfNot(Float64LessThan(x, zero), &return_x);
542 Node* minus_x = Float64Neg(x);
543 var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52));
544 GotoIfNot(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x);
545 var_x.Bind(Float64Sub(var_x.value(), one));
546 Goto(&return_minus_x);
550 BIND(&return_minus_x);
551 var_x.Bind(Float64Neg(var_x.value()));
555 return TNode<Float64T>::UncheckedCast(var_x.value());
558 TNode<BoolT> CodeStubAssembler::IsValidSmi(TNode<Smi> smi) {
559 if (SmiValuesAre31Bits() && kPointerSize == kInt64Size) {
561 TNode<IntPtrT> value = Signed(BitcastTaggedToWord(smi));
562 return WordEqual(value, ChangeInt32ToIntPtr(TruncateIntPtrToInt32(value)));
564 return Int32TrueConstant();
567 Node* CodeStubAssembler::SmiShiftBitsConstant() {
568 return IntPtrConstant(kSmiShiftSize + kSmiTagSize);
571 TNode<Smi> CodeStubAssembler::SmiFromInt32(SloppyTNode<Int32T> value) {
572 TNode<IntPtrT> value_intptr = ChangeInt32ToIntPtr(value);
574 BitcastWordToTaggedSigned(WordShl(value_intptr, SmiShiftBitsConstant()));
578 TNode<BoolT> CodeStubAssembler::IsValidPositiveSmi(TNode<IntPtrT> value) {
579 intptr_t constant_value;
580 if (ToIntPtrConstant(value, constant_value)) {
581 return (static_cast<uintptr_t>(constant_value) <=
582 static_cast<uintptr_t>(Smi::kMaxValue))
583 ? Int32TrueConstant()
584 : Int32FalseConstant();
587 return UintPtrLessThanOrEqual(value, IntPtrConstant(Smi::kMaxValue));
590 TNode<Smi> CodeStubAssembler::SmiTag(SloppyTNode<IntPtrT> value) {
591 int32_t constant_value;
592 if (ToInt32Constant(value, constant_value) && Smi::IsValid(constant_value)) {
593 return SmiConstant(constant_value);
596 BitcastWordToTaggedSigned(WordShl(value, SmiShiftBitsConstant()));
600 TNode<IntPtrT> CodeStubAssembler::SmiUntag(SloppyTNode<Smi> value) {
601 intptr_t constant_value;
602 if (ToIntPtrConstant(value, constant_value)) {
603 return IntPtrConstant(constant_value >> (kSmiShiftSize + kSmiTagSize));
605 return Signed(WordSar(BitcastTaggedToWord(value), SmiShiftBitsConstant()));
608 TNode<Int32T> CodeStubAssembler::SmiToInt32(SloppyTNode<Smi> value) {
609 TNode<IntPtrT> result = SmiUntag(value);
610 return TruncateIntPtrToInt32(result);
613 TNode<Float64T> CodeStubAssembler::SmiToFloat64(SloppyTNode<Smi> value) {
614 return ChangeInt32ToFloat64(SmiToInt32(value));
617 TNode<Smi> CodeStubAssembler::SmiMax(TNode<Smi> a, TNode<Smi> b) {
618 return SelectConstant<Smi>(SmiLessThan(a, b), b, a);
621 TNode<Smi> CodeStubAssembler::SmiMin(TNode<Smi> a, TNode<Smi> b) {
622 return SelectConstant<Smi>(SmiLessThan(a, b), a, b);
625 TNode<IntPtrT> CodeStubAssembler::TryIntPtrAdd(TNode<IntPtrT> a,
627 Label* if_overflow) {
628 TNode<PairT<IntPtrT, BoolT>> pair = IntPtrAddWithOverflow(a, b);
629 TNode<BoolT> overflow = Projection<1>(pair);
630 GotoIf(overflow, if_overflow);
631 return Projection<0>(pair);
634 TNode<Smi> CodeStubAssembler::TrySmiAdd(TNode<Smi> lhs, TNode<Smi> rhs,
635 Label* if_overflow) {
636 if (SmiValuesAre32Bits()) {
637 return BitcastWordToTaggedSigned(TryIntPtrAdd(
638 BitcastTaggedToWord(lhs), BitcastTaggedToWord(rhs), if_overflow));
640 DCHECK(SmiValuesAre31Bits());
641 TNode<PairT<Int32T, BoolT>> pair =
642 Int32AddWithOverflow(TruncateIntPtrToInt32(BitcastTaggedToWord(lhs)),
643 TruncateIntPtrToInt32(BitcastTaggedToWord(rhs)));
644 TNode<BoolT> overflow = Projection<1>(pair);
645 GotoIf(overflow, if_overflow);
646 TNode<Int32T> result = Projection<0>(pair);
647 return BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(result));
651 TNode<Smi> CodeStubAssembler::TrySmiSub(TNode<Smi> lhs, TNode<Smi> rhs,
652 Label* if_overflow) {
653 if (SmiValuesAre32Bits()) {
654 TNode<PairT<IntPtrT, BoolT>> pair = IntPtrSubWithOverflow(
655 BitcastTaggedToWord(lhs), BitcastTaggedToWord(rhs));
656 TNode<BoolT> overflow = Projection<1>(pair);
657 GotoIf(overflow, if_overflow);
658 TNode<IntPtrT> result = Projection<0>(pair);
659 return BitcastWordToTaggedSigned(result);
661 DCHECK(SmiValuesAre31Bits());
662 TNode<PairT<Int32T, BoolT>> pair =
663 Int32SubWithOverflow(TruncateIntPtrToInt32(BitcastTaggedToWord(lhs)),
664 TruncateIntPtrToInt32(BitcastTaggedToWord(rhs)));
665 TNode<BoolT> overflow = Projection<1>(pair);
666 GotoIf(overflow, if_overflow);
667 TNode<Int32T> result = Projection<0>(pair);
668 return BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(result));
672 TNode<Number> CodeStubAssembler::NumberMax(SloppyTNode<Number> a,
673 SloppyTNode<Number> b) {
675 TVARIABLE(Number, result);
676 Label done(
this), greater_than_equal_a(
this), greater_than_equal_b(
this);
677 GotoIfNumberGreaterThanOrEqual(a, b, &greater_than_equal_a);
678 GotoIfNumberGreaterThanOrEqual(b, a, &greater_than_equal_b);
679 result = NanConstant();
681 BIND(&greater_than_equal_a);
684 BIND(&greater_than_equal_b);
688 return result.value();
691 TNode<Number> CodeStubAssembler::NumberMin(SloppyTNode<Number> a,
692 SloppyTNode<Number> b) {
694 TVARIABLE(Number, result);
695 Label done(
this), greater_than_equal_a(
this), greater_than_equal_b(
this);
696 GotoIfNumberGreaterThanOrEqual(a, b, &greater_than_equal_a);
697 GotoIfNumberGreaterThanOrEqual(b, a, &greater_than_equal_b);
698 result = NanConstant();
700 BIND(&greater_than_equal_a);
703 BIND(&greater_than_equal_b);
707 return result.value();
710 TNode<IntPtrT> CodeStubAssembler::ConvertToRelativeIndex(
711 TNode<Context> context, TNode<Object> index, TNode<IntPtrT> length) {
712 TVARIABLE(IntPtrT, result);
714 TNode<Number>
const index_int =
715 ToInteger_Inline(context, index, CodeStubAssembler::kTruncateMinusZero);
716 TNode<IntPtrT> zero = IntPtrConstant(0);
719 Label if_issmi(
this), if_isheapnumber(
this, Label::kDeferred);
720 Branch(TaggedIsSmi(index_int), &if_issmi, &if_isheapnumber);
724 TNode<Smi>
const index_smi = CAST(index_int);
725 result = Select<IntPtrT>(
726 IntPtrLessThan(SmiUntag(index_smi), zero),
727 [=] {
return IntPtrMax(IntPtrAdd(length, SmiUntag(index_smi)), zero); },
728 [=] {
return IntPtrMin(SmiUntag(index_smi), length); });
732 BIND(&if_isheapnumber);
737 TNode<HeapNumber>
const index_hn = CAST(index_int);
738 TNode<Float64T>
const float_zero = Float64Constant(0.);
739 TNode<Float64T>
const index_float = LoadHeapNumberValue(index_hn);
740 result = SelectConstant<IntPtrT>(Float64LessThan(index_float, float_zero),
745 return result.value();
748 TNode<Number> CodeStubAssembler::SmiMod(TNode<Smi> a, TNode<Smi> b) {
749 TVARIABLE(Number, var_result);
750 Label return_result(
this, &var_result),
751 return_minuszero(
this, Label::kDeferred),
752 return_nan(
this, Label::kDeferred);
755 TNode<Int32T> int_a = SmiToInt32(a);
756 TNode<Int32T> int_b = SmiToInt32(b);
759 GotoIf(Word32Equal(int_b, Int32Constant(0)), &return_nan);
762 Label if_aisnotnegative(
this), if_aisnegative(
this, Label::kDeferred);
763 Branch(Int32LessThanOrEqual(Int32Constant(0), int_a), &if_aisnotnegative,
766 BIND(&if_aisnotnegative);
769 TNode<Int32T> r = Int32Mod(int_a, int_b);
770 var_result = SmiFromInt32(r);
771 Goto(&return_result);
774 BIND(&if_aisnegative);
776 if (SmiValuesAre32Bits()) {
780 GotoIfNot(Word32Equal(int_a, Int32Constant(kMinInt)), &join);
781 GotoIf(Word32Equal(int_b, Int32Constant(-1)), &return_minuszero);
787 TNode<Int32T> r = Int32Mod(int_a, int_b);
791 GotoIf(Word32Equal(r, Int32Constant(0)), &return_minuszero);
795 var_result = ChangeInt32ToTagged(r);
796 Goto(&return_result);
799 BIND(&return_minuszero);
800 var_result = MinusZeroConstant();
801 Goto(&return_result);
804 var_result = NanConstant();
805 Goto(&return_result);
807 BIND(&return_result);
808 return var_result.value();
811 TNode<Number> CodeStubAssembler::SmiMul(TNode<Smi> a, TNode<Smi> b) {
812 TVARIABLE(Number, var_result);
813 VARIABLE(var_lhs_float64, MachineRepresentation::kFloat64);
814 VARIABLE(var_rhs_float64, MachineRepresentation::kFloat64);
815 Label return_result(
this, &var_result);
818 Node* lhs32 = SmiToInt32(a);
819 Node* rhs32 = SmiToInt32(b);
820 Node* pair = Int32MulWithOverflow(lhs32, rhs32);
822 Node* overflow = Projection(1, pair);
825 Label if_overflow(
this, Label::kDeferred), if_notoverflow(
this);
826 Branch(overflow, &if_overflow, &if_notoverflow);
827 BIND(&if_notoverflow);
831 Label answer_zero(
this), answer_not_zero(
this);
832 Node* answer = Projection(0, pair);
833 Node* zero = Int32Constant(0);
834 Branch(Word32Equal(answer, zero), &answer_zero, &answer_not_zero);
835 BIND(&answer_not_zero);
837 var_result = ChangeInt32ToTagged(answer);
838 Goto(&return_result);
842 Node* or_result = Word32Or(lhs32, rhs32);
843 Label if_should_be_negative_zero(
this), if_should_be_zero(
this);
844 Branch(Int32LessThan(or_result, zero), &if_should_be_negative_zero,
846 BIND(&if_should_be_negative_zero);
848 var_result = MinusZeroConstant();
849 Goto(&return_result);
851 BIND(&if_should_be_zero);
853 var_result = SmiConstant(0);
854 Goto(&return_result);
860 var_lhs_float64.Bind(SmiToFloat64(a));
861 var_rhs_float64.Bind(SmiToFloat64(b));
862 Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
863 var_result = AllocateHeapNumberWithValue(value);
864 Goto(&return_result);
867 BIND(&return_result);
868 return var_result.value();
871 TNode<Smi> CodeStubAssembler::TrySmiDiv(TNode<Smi> dividend, TNode<Smi> divisor,
875 GotoIf(WordEqual(divisor, SmiConstant(0)), bailout);
879 Label dividend_is_zero(
this), dividend_is_not_zero(
this);
880 Branch(WordEqual(dividend, SmiConstant(0)), ÷nd_is_zero,
881 ÷nd_is_not_zero);
883 BIND(÷nd_is_zero);
885 GotoIf(SmiLessThan(divisor, SmiConstant(0)), bailout);
886 Goto(÷nd_is_not_zero);
888 BIND(÷nd_is_not_zero);
890 TNode<Int32T> untagged_divisor = SmiToInt32(divisor);
891 TNode<Int32T> untagged_dividend = SmiToInt32(dividend);
895 Label divisor_is_minus_one(
this), divisor_is_not_minus_one(
this);
896 Branch(Word32Equal(untagged_divisor, Int32Constant(-1)),
897 &divisor_is_minus_one, &divisor_is_not_minus_one);
899 BIND(&divisor_is_minus_one);
903 Int32Constant(kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))),
905 Goto(&divisor_is_not_minus_one);
907 BIND(&divisor_is_not_minus_one);
909 TNode<Int32T> untagged_result = Int32Div(untagged_dividend, untagged_divisor);
910 TNode<Int32T> truncated = Signed(Int32Mul(untagged_result, untagged_divisor));
913 GotoIf(Word32NotEqual(untagged_dividend, truncated), bailout);
915 return SmiFromInt32(untagged_result);
918 TNode<Smi> CodeStubAssembler::SmiLexicographicCompare(TNode<Smi> x,
920 TNode<ExternalReference> smi_lexicographic_compare =
921 ExternalConstant(ExternalReference::smi_lexicographic_compare_function());
922 TNode<ExternalReference> isolate_ptr =
923 ExternalConstant(ExternalReference::isolate_address(isolate()));
924 return CAST(CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
925 MachineType::AnyTagged(), MachineType::AnyTagged(),
926 smi_lexicographic_compare, isolate_ptr, x, y));
929 TNode<Int32T> CodeStubAssembler::TruncateIntPtrToInt32(
930 SloppyTNode<IntPtrT> value) {
932 return TruncateInt64ToInt32(ReinterpretCast<Int64T>(value));
934 return ReinterpretCast<Int32T>(value);
937 TNode<BoolT> CodeStubAssembler::TaggedIsSmi(SloppyTNode<Object> a) {
938 return WordEqual(WordAnd(BitcastTaggedToWord(a), IntPtrConstant(kSmiTagMask)),
942 TNode<BoolT> CodeStubAssembler::TaggedIsSmi(TNode<MaybeObject> a) {
944 WordAnd(BitcastMaybeObjectToWord(a), IntPtrConstant(kSmiTagMask)),
948 TNode<BoolT> CodeStubAssembler::TaggedIsNotSmi(SloppyTNode<Object> a) {
950 WordAnd(BitcastTaggedToWord(a), IntPtrConstant(kSmiTagMask)),
954 TNode<BoolT> CodeStubAssembler::TaggedIsPositiveSmi(SloppyTNode<Object> a) {
955 return WordEqual(WordAnd(BitcastTaggedToWord(a),
956 IntPtrConstant(kSmiTagMask | kSmiSignMask)),
960 TNode<BoolT> CodeStubAssembler::WordIsWordAligned(SloppyTNode<WordT> word) {
961 return WordEqual(IntPtrConstant(0),
962 WordAnd(word, IntPtrConstant(kPointerSize - 1)));
966 void CodeStubAssembler::Bind(Label* label, AssemblerDebugInfo debug_info) {
967 CodeAssembler::Bind(label, debug_info);
971 void CodeStubAssembler::Bind(Label* label) { CodeAssembler::Bind(label); }
973 TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck(
974 TNode<FixedDoubleArray> array, TNode<Smi> index, Label* if_hole) {
975 return LoadFixedDoubleArrayElement(array, index, MachineType::Float64(), 0,
976 SMI_PARAMETERS, if_hole);
979 TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck(
980 TNode<FixedDoubleArray> array, TNode<IntPtrT> index, Label* if_hole) {
981 return LoadFixedDoubleArrayElement(array, index, MachineType::Float64(), 0,
982 INTPTR_PARAMETERS, if_hole);
985 void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
986 Node* receiver_map, Label* definitely_no_elements,
987 Label* possibly_elements) {
988 CSA_SLOW_ASSERT(
this, IsMap(receiver_map));
989 VARIABLE(var_map, MachineRepresentation::kTagged, receiver_map);
990 Label loop_body(
this, &var_map);
991 Node* empty_fixed_array = LoadRoot(RootIndex::kEmptyFixedArray);
992 Node* empty_slow_element_dictionary =
993 LoadRoot(RootIndex::kEmptySlowElementDictionary);
998 Node* map = var_map.value();
999 Node* prototype = LoadMapPrototype(map);
1000 GotoIf(IsNull(prototype), definitely_no_elements);
1001 Node* prototype_map = LoadMap(prototype);
1002 TNode<Int32T> prototype_instance_type = LoadMapInstanceType(prototype_map);
1008 Label if_custom(
this, Label::kDeferred), if_notcustom(
this);
1009 Branch(IsCustomElementsReceiverInstanceType(prototype_instance_type),
1010 &if_custom, &if_notcustom);
1016 GotoIfNot(InstanceTypeEqual(prototype_instance_type, JS_VALUE_TYPE),
1018 Node* prototype_value = LoadJSValueValue(prototype);
1019 Branch(IsEmptyString(prototype_value), &if_notcustom, possibly_elements);
1022 BIND(&if_notcustom);
1024 Node* prototype_elements = LoadElements(prototype);
1025 var_map.Bind(prototype_map);
1026 GotoIf(WordEqual(prototype_elements, empty_fixed_array), &loop_body);
1027 Branch(WordEqual(prototype_elements, empty_slow_element_dictionary),
1028 &loop_body, possibly_elements);
1033 void CodeStubAssembler::BranchIfJSReceiver(Node*
object, Label* if_true,
1035 GotoIf(TaggedIsSmi(
object), if_false);
1036 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
1037 Branch(IsJSReceiver(
object), if_true, if_false);
1040 void CodeStubAssembler::GotoIfForceSlowPath(Label* if_true) {
1041 #ifdef V8_ENABLE_FORCE_SLOW_PATH 1042 Node*
const force_slow_path_addr =
1043 ExternalConstant(ExternalReference::force_slow_path(isolate()));
1044 Node*
const force_slow = Load(MachineType::Uint8(), force_slow_path_addr);
1046 GotoIf(force_slow, if_true);
1050 void CodeStubAssembler::GotoIfDebugExecutionModeChecksSideEffects(
1052 STATIC_ASSERT(
sizeof(DebugInfo::ExecutionMode) >=
sizeof(int32_t));
1054 TNode<ExternalReference> execution_mode_address = ExternalConstant(
1055 ExternalReference::debug_execution_mode_address(isolate()));
1056 TNode<Int32T> execution_mode =
1057 UncheckedCast<Int32T>(Load(MachineType::Int32(), execution_mode_address));
1059 GotoIf(Word32Equal(execution_mode, Int32Constant(DebugInfo::kSideEffects)),
1063 TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes,
1064 AllocationFlags flags,
1065 TNode<RawPtrT> top_address,
1066 TNode<RawPtrT> limit_address) {
1069 intptr_t constant_value;
1070 if (ToIntPtrConstant(size_in_bytes, constant_value)) {
1071 CHECK(Internals::IsValidSmi(constant_value));
1072 CHECK_GT(constant_value, 0);
1074 CSA_CHECK(
this, IsValidPositiveSmi(size_in_bytes));
1078 TNode<RawPtrT> top =
1079 UncheckedCast<RawPtrT>(Load(MachineType::Pointer(), top_address));
1080 TNode<RawPtrT> limit =
1081 UncheckedCast<RawPtrT>(Load(MachineType::Pointer(), limit_address));
1084 TVARIABLE(Object, result);
1085 Label runtime_call(
this, Label::kDeferred), no_runtime_call(
this), out(
this);
1087 bool needs_double_alignment = flags & kDoubleAlignment;
1089 if (flags & kAllowLargeObjectAllocation) {
1091 GotoIf(IsRegularHeapObjectSize(size_in_bytes), &next);
1093 TNode<Smi> runtime_flags = SmiConstant(
1094 Smi::FromInt(AllocateDoubleAlignFlag::encode(needs_double_alignment) |
1095 AllocateTargetSpace::encode(AllocationSpace::LO_SPACE)));
1096 result = CallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(),
1097 SmiTag(size_in_bytes), runtime_flags);
1103 TVARIABLE(IntPtrT, adjusted_size, size_in_bytes);
1105 if (needs_double_alignment) {
1107 GotoIfNot(WordAnd(top, IntPtrConstant(kDoubleAlignmentMask)), &next);
1109 adjusted_size = IntPtrAdd(size_in_bytes, IntPtrConstant(4));
1115 TNode<IntPtrT> new_top =
1116 IntPtrAdd(UncheckedCast<IntPtrT>(top), adjusted_size.value());
1118 Branch(UintPtrGreaterThanOrEqual(new_top, limit), &runtime_call,
1121 BIND(&runtime_call);
1123 if (flags & kPretenured) {
1124 TNode<Smi> runtime_flags = SmiConstant(Smi::FromInt(
1125 AllocateDoubleAlignFlag::encode(needs_double_alignment) |
1126 AllocateTargetSpace::encode(AllocationSpace::OLD_SPACE)));
1127 result = CallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(),
1128 SmiTag(size_in_bytes), runtime_flags);
1130 result = CallRuntime(Runtime::kAllocateInNewSpace, NoContextConstant(),
1131 SmiTag(size_in_bytes));
1137 BIND(&no_runtime_call);
1139 StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address,
1142 TVARIABLE(IntPtrT, address, UncheckedCast<IntPtrT>(top));
1144 if (needs_double_alignment) {
1146 GotoIf(IntPtrEqual(adjusted_size.value(), size_in_bytes), &next);
1149 StoreNoWriteBarrier(MachineRepresentation::kTagged, top,
1150 LoadRoot(RootIndex::kOnePointerFillerMap));
1151 address = IntPtrAdd(UncheckedCast<IntPtrT>(top), IntPtrConstant(4));
1157 result = BitcastWordToTagged(
1158 IntPtrAdd(address.value(), IntPtrConstant(kHeapObjectTag)));
1163 return UncheckedCast<HeapObject>(result.value());
1166 TNode<HeapObject> CodeStubAssembler::AllocateRawUnaligned(
1167 TNode<IntPtrT> size_in_bytes, AllocationFlags flags,
1168 TNode<RawPtrT> top_address, TNode<RawPtrT> limit_address) {
1169 DCHECK_EQ(flags & kDoubleAlignment, 0);
1170 return AllocateRaw(size_in_bytes, flags, top_address, limit_address);
1173 TNode<HeapObject> CodeStubAssembler::AllocateRawDoubleAligned(
1174 TNode<IntPtrT> size_in_bytes, AllocationFlags flags,
1175 TNode<RawPtrT> top_address, TNode<RawPtrT> limit_address) {
1176 #if defined(V8_HOST_ARCH_32_BIT) 1177 return AllocateRaw(size_in_bytes, flags | kDoubleAlignment, top_address,
1179 #elif defined(V8_HOST_ARCH_64_BIT) 1181 return AllocateRaw(size_in_bytes, flags & ~kDoubleAlignment, top_address,
1184 #error Architecture not supported 1188 TNode<HeapObject> CodeStubAssembler::AllocateInNewSpace(
1189 TNode<IntPtrT> size_in_bytes, AllocationFlags flags) {
1190 DCHECK(flags == kNone || flags == kDoubleAlignment);
1191 CSA_ASSERT(
this, IsRegularHeapObjectSize(size_in_bytes));
1192 return Allocate(size_in_bytes, flags);
1195 TNode<HeapObject> CodeStubAssembler::Allocate(TNode<IntPtrT> size_in_bytes,
1196 AllocationFlags flags) {
1197 Comment(
"Allocate");
1198 bool const new_space = !(flags & kPretenured);
1199 TNode<ExternalReference> top_address = ExternalConstant(
1201 ? ExternalReference::new_space_allocation_top_address(isolate())
1202 : ExternalReference::old_space_allocation_top_address(isolate()));
1203 DCHECK_EQ(kPointerSize,
1204 ExternalReference::new_space_allocation_limit_address(isolate())
1206 ExternalReference::new_space_allocation_top_address(isolate())
1208 DCHECK_EQ(kPointerSize,
1209 ExternalReference::old_space_allocation_limit_address(isolate())
1211 ExternalReference::old_space_allocation_top_address(isolate())
1213 TNode<IntPtrT> limit_address = IntPtrAdd(
1214 ReinterpretCast<IntPtrT>(top_address), IntPtrConstant(kPointerSize));
1216 if (flags & kDoubleAlignment) {
1217 return AllocateRawDoubleAligned(size_in_bytes, flags,
1218 ReinterpretCast<RawPtrT>(top_address),
1219 ReinterpretCast<RawPtrT>(limit_address));
1221 return AllocateRawUnaligned(size_in_bytes, flags,
1222 ReinterpretCast<RawPtrT>(top_address),
1223 ReinterpretCast<RawPtrT>(limit_address));
1227 TNode<HeapObject> CodeStubAssembler::AllocateInNewSpace(
int size_in_bytes,
1228 AllocationFlags flags) {
1229 CHECK(flags == kNone || flags == kDoubleAlignment);
1230 DCHECK_LE(size_in_bytes, kMaxRegularHeapObjectSize);
1231 return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags);
1234 TNode<HeapObject> CodeStubAssembler::Allocate(
int size_in_bytes,
1235 AllocationFlags flags) {
1236 return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags);
1239 TNode<HeapObject> CodeStubAssembler::InnerAllocate(TNode<HeapObject> previous,
1240 TNode<IntPtrT> offset) {
1241 return UncheckedCast<HeapObject>(
1242 BitcastWordToTagged(IntPtrAdd(BitcastTaggedToWord(previous), offset)));
1245 TNode<HeapObject> CodeStubAssembler::InnerAllocate(TNode<HeapObject> previous,
1247 return InnerAllocate(previous, IntPtrConstant(offset));
1250 TNode<BoolT> CodeStubAssembler::IsRegularHeapObjectSize(TNode<IntPtrT> size) {
1251 return UintPtrLessThanOrEqual(size,
1252 IntPtrConstant(kMaxRegularHeapObjectSize));
1255 void CodeStubAssembler::BranchIfToBooleanIsTrue(Node* value, Label* if_true,
1257 Label if_smi(
this), if_notsmi(
this), if_heapnumber(
this, Label::kDeferred),
1258 if_bigint(
this, Label::kDeferred);
1260 GotoIf(WordEqual(value, FalseConstant()), if_false);
1263 Branch(TaggedIsSmi(value), &if_smi, &if_notsmi);
1268 BranchIfSmiEqual(CAST(value), SmiConstant(0), if_false, if_true);
1274 GotoIf(IsEmptyString(value), if_false);
1277 Node* value_map = LoadMap(value);
1281 GotoIf(IsUndetectableMap(value_map), if_false);
1285 GotoIf(IsHeapNumberMap(value_map), &if_heapnumber);
1286 Branch(IsBigInt(value), &if_bigint, if_true);
1288 BIND(&if_heapnumber);
1291 Node* value_value = LoadObjectField(value, HeapNumber::kValueOffset,
1292 MachineType::Float64());
1295 Branch(Float64LessThan(Float64Constant(0.0), Float64Abs(value_value)),
1302 CallRuntime(Runtime::kBigIntToBoolean, NoContextConstant(), value);
1303 CSA_ASSERT(
this, IsBoolean(result));
1304 Branch(WordEqual(result, TrueConstant()), if_true, if_false);
1309 Node* CodeStubAssembler::LoadFromFrame(
int offset, MachineType rep) {
1310 Node* frame_pointer = LoadFramePointer();
1311 return Load(rep, frame_pointer, IntPtrConstant(offset));
1314 Node* CodeStubAssembler::LoadFromParentFrame(
int offset, MachineType rep) {
1315 Node* frame_pointer = LoadParentFramePointer();
1316 return Load(rep, frame_pointer, IntPtrConstant(offset));
1319 TNode<JSFunction> CodeStubAssembler::LoadTargetFromFrame() {
1320 DCHECK(IsJSFunctionCall());
1321 return CAST(LoadFromFrame(StandardFrameConstants::kFunctionOffset,
1322 MachineType::TaggedPointer()));
1325 Node* CodeStubAssembler::LoadBufferObject(Node* buffer,
int offset,
1327 return Load(rep, buffer, IntPtrConstant(offset));
1330 Node* CodeStubAssembler::LoadObjectField(SloppyTNode<HeapObject>
object,
1331 int offset, MachineType rep) {
1332 CSA_ASSERT(
this, IsStrong(
object));
1333 return Load(rep,
object, IntPtrConstant(offset - kHeapObjectTag));
1336 Node* CodeStubAssembler::LoadObjectField(SloppyTNode<HeapObject>
object,
1337 SloppyTNode<IntPtrT> offset,
1339 CSA_ASSERT(
this, IsStrong(
object));
1340 return Load(rep,
object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)));
1343 TNode<IntPtrT> CodeStubAssembler::LoadAndUntagObjectField(
1344 SloppyTNode<HeapObject>
object,
int offset) {
1345 if (SmiValuesAre32Bits()) {
1346 #if V8_TARGET_LITTLE_ENDIAN 1347 offset += kPointerSize / 2;
1349 return ChangeInt32ToIntPtr(
1350 LoadObjectField(
object, offset, MachineType::Int32()));
1353 LoadObjectField(
object, offset, MachineType::AnyTagged()));
1357 TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ObjectField(Node*
object,
1359 if (SmiValuesAre32Bits()) {
1360 #if V8_TARGET_LITTLE_ENDIAN 1361 offset += kPointerSize / 2;
1363 return UncheckedCast<Int32T>(
1364 LoadObjectField(
object, offset, MachineType::Int32()));
1367 LoadObjectField(
object, offset, MachineType::AnyTagged()));
1371 TNode<IntPtrT> CodeStubAssembler::LoadAndUntagSmi(Node* base,
int index) {
1372 if (SmiValuesAre32Bits()) {
1373 #if V8_TARGET_LITTLE_ENDIAN 1374 index += kPointerSize / 2;
1376 return ChangeInt32ToIntPtr(
1377 Load(MachineType::Int32(), base, IntPtrConstant(index)));
1380 Load(MachineType::AnyTagged(), base, IntPtrConstant(index)));
1384 TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32Root(
1385 RootIndex root_index) {
1386 Node* isolate_root =
1387 ExternalConstant(ExternalReference::isolate_root(isolate()));
1388 int offset = IsolateData::root_slot_offset(root_index);
1389 if (SmiValuesAre32Bits()) {
1390 #if V8_TARGET_LITTLE_ENDIAN 1391 offset += kPointerSize / 2;
1393 return UncheckedCast<Int32T>(
1394 Load(MachineType::Int32(), isolate_root, IntPtrConstant(offset)));
1397 Load(MachineType::AnyTagged(), isolate_root, IntPtrConstant(offset)));
1401 Node* CodeStubAssembler::StoreAndTagSmi(Node* base,
int offset, Node* value) {
1402 if (SmiValuesAre32Bits()) {
1403 int zero_offset = offset + kPointerSize / 2;
1404 int payload_offset = offset;
1405 #if V8_TARGET_LITTLE_ENDIAN 1406 std::swap(zero_offset, payload_offset);
1408 StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
1409 IntPtrConstant(zero_offset), Int32Constant(0));
1410 return StoreNoWriteBarrier(MachineRepresentation::kWord32, base,
1411 IntPtrConstant(payload_offset),
1412 TruncateInt64ToInt32(value));
1414 return StoreNoWriteBarrier(MachineRepresentation::kTaggedSigned, base,
1415 IntPtrConstant(offset), SmiTag(value));
1419 TNode<Float64T> CodeStubAssembler::LoadHeapNumberValue(
1420 SloppyTNode<HeapNumber>
object) {
1421 return TNode<Float64T>::UncheckedCast(LoadObjectField(
1422 object, HeapNumber::kValueOffset, MachineType::Float64()));
1425 TNode<Map> CodeStubAssembler::LoadMap(SloppyTNode<HeapObject>
object) {
1426 return UncheckedCast<Map>(LoadObjectField(
object, HeapObject::kMapOffset));
1429 TNode<Int32T> CodeStubAssembler::LoadInstanceType(
1430 SloppyTNode<HeapObject>
object) {
1431 return LoadMapInstanceType(LoadMap(
object));
1434 TNode<BoolT> CodeStubAssembler::HasInstanceType(SloppyTNode<HeapObject>
object,
1435 InstanceType instance_type) {
1436 return InstanceTypeEqual(LoadInstanceType(
object), instance_type);
1439 TNode<BoolT> CodeStubAssembler::DoesntHaveInstanceType(
1440 SloppyTNode<HeapObject>
object, InstanceType instance_type) {
1441 return Word32NotEqual(LoadInstanceType(
object), Int32Constant(instance_type));
1444 TNode<BoolT> CodeStubAssembler::TaggedDoesntHaveInstanceType(
1445 SloppyTNode<HeapObject> any_tagged, InstanceType type) {
1447 TNode<BoolT> tagged_is_smi = TaggedIsSmi(any_tagged);
1448 return Select<BoolT>(
1449 tagged_is_smi, [=]() {
return tagged_is_smi; },
1450 [=]() {
return DoesntHaveInstanceType(any_tagged, type); });
1453 TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
1454 SloppyTNode<JSObject>
object) {
1455 CSA_SLOW_ASSERT(
this, Word32BinaryNot(IsDictionaryMap(LoadMap(
object))));
1456 TNode<Object> properties =
1457 LoadObjectField(
object, JSObject::kPropertiesOrHashOffset);
1458 return Select<HeapObject>(TaggedIsSmi(properties),
1459 [=] {
return EmptyFixedArrayConstant(); },
1460 [=] {
return CAST(properties); });
1463 TNode<HeapObject> CodeStubAssembler::LoadSlowProperties(
1464 SloppyTNode<JSObject>
object) {
1465 CSA_SLOW_ASSERT(
this, IsDictionaryMap(LoadMap(
object)));
1466 TNode<Object> properties =
1467 LoadObjectField(
object, JSObject::kPropertiesOrHashOffset);
1468 return Select<HeapObject>(TaggedIsSmi(properties),
1469 [=] {
return EmptyPropertyDictionaryConstant(); },
1470 [=] {
return CAST(properties); });
1473 TNode<FixedArrayBase> CodeStubAssembler::LoadElements(
1474 SloppyTNode<JSObject>
object) {
1475 return CAST(LoadObjectField(
object, JSObject::kElementsOffset));
1478 TNode<Number> CodeStubAssembler::LoadJSArrayLength(SloppyTNode<JSArray> array) {
1479 CSA_ASSERT(
this, IsJSArray(array));
1480 return CAST(LoadObjectField(array, JSArray::kLengthOffset));
1483 TNode<Object> CodeStubAssembler::LoadJSArgumentsObjectWithLength(
1484 SloppyTNode<JSArgumentsObjectWithLength> array) {
1485 return LoadObjectField(array, JSArgumentsObjectWithLength::kLengthOffset);
1488 TNode<Smi> CodeStubAssembler::LoadFastJSArrayLength(
1489 SloppyTNode<JSArray> array) {
1490 TNode<Object> length = LoadJSArrayLength(array);
1491 CSA_ASSERT(
this, IsFastElementsKind(LoadElementsKind(array)));
1493 CSA_SLOW_ASSERT(
this, TaggedIsPositiveSmi(length));
1494 return UncheckedCast<Smi>(length);
1497 TNode<Smi> CodeStubAssembler::LoadFixedArrayBaseLength(
1498 SloppyTNode<FixedArrayBase> array) {
1499 CSA_SLOW_ASSERT(
this, IsNotWeakFixedArraySubclass(array));
1500 return CAST(LoadObjectField(array, FixedArrayBase::kLengthOffset));
1503 TNode<IntPtrT> CodeStubAssembler::LoadAndUntagFixedArrayBaseLength(
1504 SloppyTNode<FixedArrayBase> array) {
1505 return LoadAndUntagObjectField(array, FixedArrayBase::kLengthOffset);
1508 TNode<IntPtrT> CodeStubAssembler::LoadFeedbackVectorLength(
1509 TNode<FeedbackVector> vector) {
1510 return ChangeInt32ToIntPtr(
1511 LoadObjectField<Int32T>(vector, FeedbackVector::kLengthOffset));
1514 TNode<Smi> CodeStubAssembler::LoadWeakFixedArrayLength(
1515 TNode<WeakFixedArray> array) {
1516 return CAST(LoadObjectField(array, WeakFixedArray::kLengthOffset));
1519 TNode<IntPtrT> CodeStubAssembler::LoadAndUntagWeakFixedArrayLength(
1520 SloppyTNode<WeakFixedArray> array) {
1521 return LoadAndUntagObjectField(array, WeakFixedArray::kLengthOffset);
1524 TNode<Int32T> CodeStubAssembler::LoadNumberOfDescriptors(
1525 TNode<DescriptorArray> array) {
1526 return UncheckedCast<Int32T>(
1527 LoadObjectField(array, DescriptorArray::kNumberOfDescriptorsOffset,
1528 MachineType::Int16()));
1531 TNode<Int32T> CodeStubAssembler::LoadMapBitField(SloppyTNode<Map> map) {
1532 CSA_SLOW_ASSERT(
this, IsMap(map));
1533 return UncheckedCast<Int32T>(
1534 LoadObjectField(map, Map::kBitFieldOffset, MachineType::Uint8()));
1537 TNode<Int32T> CodeStubAssembler::LoadMapBitField2(SloppyTNode<Map> map) {
1538 CSA_SLOW_ASSERT(
this, IsMap(map));
1539 return UncheckedCast<Int32T>(
1540 LoadObjectField(map, Map::kBitField2Offset, MachineType::Uint8()));
1543 TNode<Uint32T> CodeStubAssembler::LoadMapBitField3(SloppyTNode<Map> map) {
1544 CSA_SLOW_ASSERT(
this, IsMap(map));
1545 return UncheckedCast<Uint32T>(
1546 LoadObjectField(map, Map::kBitField3Offset, MachineType::Uint32()));
1549 TNode<Int32T> CodeStubAssembler::LoadMapInstanceType(SloppyTNode<Map> map) {
1550 return UncheckedCast<Int32T>(
1551 LoadObjectField(map, Map::kInstanceTypeOffset, MachineType::Uint16()));
1554 TNode<Int32T> CodeStubAssembler::LoadMapElementsKind(SloppyTNode<Map> map) {
1555 CSA_SLOW_ASSERT(
this, IsMap(map));
1556 Node* bit_field2 = LoadMapBitField2(map);
1557 return Signed(DecodeWord32<Map::ElementsKindBits>(bit_field2));
1560 TNode<Int32T> CodeStubAssembler::LoadElementsKind(
1561 SloppyTNode<HeapObject>
object) {
1562 return LoadMapElementsKind(LoadMap(
object));
1565 TNode<DescriptorArray> CodeStubAssembler::LoadMapDescriptors(
1566 SloppyTNode<Map> map) {
1567 CSA_SLOW_ASSERT(
this, IsMap(map));
1568 return CAST(LoadObjectField(map, Map::kDescriptorsOffset));
1571 TNode<HeapObject> CodeStubAssembler::LoadMapPrototype(SloppyTNode<Map> map) {
1572 CSA_SLOW_ASSERT(
this, IsMap(map));
1573 return CAST(LoadObjectField(map, Map::kPrototypeOffset));
1576 TNode<PrototypeInfo> CodeStubAssembler::LoadMapPrototypeInfo(
1577 SloppyTNode<Map> map, Label* if_no_proto_info) {
1578 Label if_strong_heap_object(
this);
1579 CSA_ASSERT(
this, IsMap(map));
1580 TNode<MaybeObject> maybe_prototype_info =
1581 LoadMaybeWeakObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
1582 TVARIABLE(Object, prototype_info);
1583 DispatchMaybeObject(maybe_prototype_info, if_no_proto_info, if_no_proto_info,
1584 if_no_proto_info, &if_strong_heap_object,
1587 BIND(&if_strong_heap_object);
1588 GotoIfNot(WordEqual(LoadMap(CAST(prototype_info.value())),
1589 LoadRoot(RootIndex::kPrototypeInfoMap)),
1591 return CAST(prototype_info.value());
1594 TNode<IntPtrT> CodeStubAssembler::LoadMapInstanceSizeInWords(
1595 SloppyTNode<Map> map) {
1596 CSA_SLOW_ASSERT(
this, IsMap(map));
1597 return ChangeInt32ToIntPtr(LoadObjectField(
1598 map, Map::kInstanceSizeInWordsOffset, MachineType::Uint8()));
1601 TNode<IntPtrT> CodeStubAssembler::LoadMapInobjectPropertiesStartInWords(
1602 SloppyTNode<Map> map) {
1603 CSA_SLOW_ASSERT(
this, IsMap(map));
1605 CSA_ASSERT(
this, IsJSObjectMap(map));
1606 return ChangeInt32ToIntPtr(LoadObjectField(
1607 map, Map::kInObjectPropertiesStartOrConstructorFunctionIndexOffset,
1608 MachineType::Uint8()));
1611 TNode<IntPtrT> CodeStubAssembler::LoadMapConstructorFunctionIndex(
1612 SloppyTNode<Map> map) {
1613 CSA_SLOW_ASSERT(
this, IsMap(map));
1615 CSA_ASSERT(
this, IsPrimitiveInstanceType(LoadMapInstanceType(map)));
1616 return ChangeInt32ToIntPtr(LoadObjectField(
1617 map, Map::kInObjectPropertiesStartOrConstructorFunctionIndexOffset,
1618 MachineType::Uint8()));
1621 TNode<Object> CodeStubAssembler::LoadMapConstructor(SloppyTNode<Map> map) {
1622 CSA_SLOW_ASSERT(
this, IsMap(map));
1623 TVARIABLE(Object, result,
1624 LoadObjectField(map, Map::kConstructorOrBackPointerOffset));
1626 Label done(
this), loop(
this, &result);
1630 GotoIf(TaggedIsSmi(result.value()), &done);
1632 InstanceTypeEqual(LoadInstanceType(CAST(result.value())), MAP_TYPE);
1633 GotoIfNot(is_map_type, &done);
1634 result = LoadObjectField(CAST(result.value()),
1635 Map::kConstructorOrBackPointerOffset);
1639 return result.value();
1642 Node* CodeStubAssembler::LoadMapEnumLength(SloppyTNode<Map> map) {
1643 CSA_SLOW_ASSERT(
this, IsMap(map));
1644 Node* bit_field3 = LoadMapBitField3(map);
1645 return DecodeWordFromWord32<Map::EnumLengthBits>(bit_field3);
1648 TNode<Object> CodeStubAssembler::LoadMapBackPointer(SloppyTNode<Map> map) {
1649 TNode<HeapObject>
object =
1650 CAST(LoadObjectField(map, Map::kConstructorOrBackPointerOffset));
1651 return Select<Object>(IsMap(
object), [=] {
return object; },
1652 [=] {
return UndefinedConstant(); });
1655 TNode<Uint32T> CodeStubAssembler::EnsureOnlyHasSimpleProperties(
1656 TNode<Map> map, TNode<Int32T> instance_type, Label* bailout) {
1658 GotoIf(IsCustomElementsReceiverInstanceType(instance_type), bailout);
1660 TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
1661 GotoIf(IsSetWord32(bit_field3, Map::IsDictionaryMapBit::kMask |
1662 Map::HasHiddenPrototypeBit::kMask),
1668 TNode<IntPtrT> CodeStubAssembler::LoadJSReceiverIdentityHash(
1669 SloppyTNode<Object> receiver, Label* if_no_hash) {
1670 TVARIABLE(IntPtrT, var_hash);
1671 Label done(
this), if_smi(
this), if_property_array(
this),
1672 if_property_dictionary(
this), if_fixed_array(
this);
1674 TNode<Object> properties_or_hash =
1675 LoadObjectField(TNode<HeapObject>::UncheckedCast(receiver),
1676 JSReceiver::kPropertiesOrHashOffset);
1677 GotoIf(TaggedIsSmi(properties_or_hash), &if_smi);
1679 TNode<HeapObject> properties =
1680 TNode<HeapObject>::UncheckedCast(properties_or_hash);
1681 TNode<Int32T> properties_instance_type = LoadInstanceType(properties);
1683 GotoIf(InstanceTypeEqual(properties_instance_type, PROPERTY_ARRAY_TYPE),
1684 &if_property_array);
1685 Branch(InstanceTypeEqual(properties_instance_type, NAME_DICTIONARY_TYPE),
1686 &if_property_dictionary, &if_fixed_array);
1688 BIND(&if_fixed_array);
1690 var_hash = IntPtrConstant(PropertyArray::kNoHashSentinel);
1696 var_hash = SmiUntag(TNode<Smi>::UncheckedCast(properties_or_hash));
1700 BIND(&if_property_array);
1702 TNode<IntPtrT> length_and_hash = LoadAndUntagObjectField(
1703 properties, PropertyArray::kLengthAndHashOffset);
1704 var_hash = TNode<IntPtrT>::UncheckedCast(
1705 DecodeWord<PropertyArray::HashField>(length_and_hash));
1709 BIND(&if_property_dictionary);
1711 var_hash = SmiUntag(CAST(LoadFixedArrayElement(
1712 CAST(properties), NameDictionary::kObjectHashIndex)));
1717 if (if_no_hash !=
nullptr) {
1718 GotoIf(IntPtrEqual(var_hash.value(),
1719 IntPtrConstant(PropertyArray::kNoHashSentinel)),
1722 return var_hash.value();
1725 TNode<Uint32T> CodeStubAssembler::LoadNameHashField(SloppyTNode<Name> name) {
1726 CSA_ASSERT(
this, IsName(name));
1727 return LoadObjectField<Uint32T>(name, Name::kHashFieldOffset);
1730 TNode<Uint32T> CodeStubAssembler::LoadNameHash(SloppyTNode<Name> name,
1731 Label* if_hash_not_computed) {
1732 TNode<Uint32T> hash_field = LoadNameHashField(name);
1733 if (if_hash_not_computed !=
nullptr) {
1734 GotoIf(IsSetWord32(hash_field, Name::kHashNotComputedMask),
1735 if_hash_not_computed);
1737 return Unsigned(Word32Shr(hash_field, Int32Constant(Name::kHashShift)));
1740 TNode<Smi> CodeStubAssembler::LoadStringLengthAsSmi(
1741 SloppyTNode<String>
string) {
1742 return SmiFromIntPtr(LoadStringLengthAsWord(
string));
1745 TNode<IntPtrT> CodeStubAssembler::LoadStringLengthAsWord(
1746 SloppyTNode<String>
string) {
1747 return Signed(ChangeUint32ToWord(LoadStringLengthAsWord32(
string)));
1750 TNode<Uint32T> CodeStubAssembler::LoadStringLengthAsWord32(
1751 SloppyTNode<String>
string) {
1752 CSA_ASSERT(
this, IsString(
string));
1753 return LoadObjectField<Uint32T>(string, String::kLengthOffset);
1756 Node* CodeStubAssembler::PointerToSeqStringData(Node* seq_string) {
1757 CSA_ASSERT(
this, IsString(seq_string));
1759 IsSequentialStringInstanceType(LoadInstanceType(seq_string)));
1760 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
1762 BitcastTaggedToWord(seq_string),
1763 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
1766 Node* CodeStubAssembler::LoadJSValueValue(Node*
object) {
1767 CSA_ASSERT(
this, IsJSValue(
object));
1768 return LoadObjectField(
object, JSValue::kValueOffset);
1771 void CodeStubAssembler::DispatchMaybeObject(TNode<MaybeObject> maybe_object,
1772 Label* if_smi, Label* if_cleared,
1773 Label* if_weak, Label* if_strong,
1774 TVariable<Object>* extracted) {
1775 Label inner_if_smi(
this), inner_if_strong(
this);
1777 GotoIf(TaggedIsSmi(maybe_object), &inner_if_smi);
1779 GotoIf(IsCleared(maybe_object), if_cleared);
1781 GotoIf(Word32Equal(Word32And(TruncateIntPtrToInt32(
1782 BitcastMaybeObjectToWord(maybe_object)),
1783 Int32Constant(kHeapObjectTagMask)),
1784 Int32Constant(kHeapObjectTag)),
1788 BitcastWordToTagged(WordAnd(BitcastMaybeObjectToWord(maybe_object),
1789 IntPtrConstant(~kWeakHeapObjectMask)));
1792 BIND(&inner_if_smi);
1793 *extracted = CAST(maybe_object);
1796 BIND(&inner_if_strong);
1797 *extracted = CAST(maybe_object);
1801 TNode<BoolT> CodeStubAssembler::IsStrong(TNode<MaybeObject> value) {
1802 return WordEqual(WordAnd(BitcastMaybeObjectToWord(value),
1803 IntPtrConstant(kHeapObjectTagMask)),
1804 IntPtrConstant(kHeapObjectTag));
1807 TNode<HeapObject> CodeStubAssembler::GetHeapObjectIfStrong(
1808 TNode<MaybeObject> value, Label* if_not_strong) {
1809 GotoIfNot(IsStrong(value), if_not_strong);
1813 TNode<BoolT> CodeStubAssembler::IsWeakOrCleared(TNode<MaybeObject> value) {
1815 Word32And(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)),
1816 Int32Constant(kHeapObjectTagMask)),
1817 Int32Constant(kWeakHeapObjectTag));
1820 TNode<BoolT> CodeStubAssembler::IsCleared(TNode<MaybeObject> value) {
1821 return Word32Equal(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)),
1822 Int32Constant(kClearedWeakHeapObjectLower32));
1825 TNode<BoolT> CodeStubAssembler::IsNotCleared(TNode<MaybeObject> value) {
1826 return Word32NotEqual(TruncateIntPtrToInt32(BitcastMaybeObjectToWord(value)),
1827 Int32Constant(kClearedWeakHeapObjectLower32));
1830 TNode<HeapObject> CodeStubAssembler::GetHeapObjectAssumeWeak(
1831 TNode<MaybeObject> value) {
1832 CSA_ASSERT(
this, IsWeakOrCleared(value));
1833 CSA_ASSERT(
this, IsNotCleared(value));
1834 return UncheckedCast<HeapObject>(BitcastWordToTagged(WordAnd(
1835 BitcastMaybeObjectToWord(value), IntPtrConstant(~kWeakHeapObjectMask))));
1838 TNode<HeapObject> CodeStubAssembler::GetHeapObjectAssumeWeak(
1839 TNode<MaybeObject> value, Label* if_cleared) {
1840 GotoIf(IsCleared(value), if_cleared);
1841 return GetHeapObjectAssumeWeak(value);
1844 TNode<BoolT> CodeStubAssembler::IsWeakReferenceTo(TNode<MaybeObject>
object,
1845 TNode<Object> value) {
1846 return WordEqual(WordAnd(BitcastMaybeObjectToWord(
object),
1847 IntPtrConstant(~kWeakHeapObjectMask)),
1848 BitcastTaggedToWord(value));
1851 TNode<BoolT> CodeStubAssembler::IsStrongReferenceTo(TNode<MaybeObject>
object,
1852 TNode<Object> value) {
1853 return WordEqual(BitcastMaybeObjectToWord(
object),
1854 BitcastTaggedToWord(value));
1857 TNode<BoolT> CodeStubAssembler::IsNotWeakReferenceTo(TNode<MaybeObject>
object,
1858 TNode<Object> value) {
1859 return WordNotEqual(WordAnd(BitcastMaybeObjectToWord(
object),
1860 IntPtrConstant(~kWeakHeapObjectMask)),
1861 BitcastTaggedToWord(value));
1864 TNode<MaybeObject> CodeStubAssembler::MakeWeak(TNode<HeapObject> value) {
1865 return ReinterpretCast<MaybeObject>(BitcastWordToTagged(
1866 WordOr(BitcastTaggedToWord(value), IntPtrConstant(kWeakHeapObjectTag))));
1870 TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(TNode<FixedArray> array) {
1871 return LoadAndUntagFixedArrayBaseLength(array);
1875 TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(TNode<WeakFixedArray> array) {
1876 return LoadAndUntagWeakFixedArrayLength(array);
1880 TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(TNode<PropertyArray> array) {
1881 return LoadPropertyArrayLength(array);
1885 TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(
1886 TNode<DescriptorArray> array) {
1887 return IntPtrMul(ChangeInt32ToIntPtr(LoadNumberOfDescriptors(array)),
1888 IntPtrConstant(DescriptorArray::kEntrySize));
1892 TNode<IntPtrT> CodeStubAssembler::LoadArrayLength(
1893 TNode<TransitionArray> array) {
1894 return LoadAndUntagWeakFixedArrayLength(array);
1897 template <
typename Array>
1898 TNode<MaybeObject> CodeStubAssembler::LoadArrayElement(
1899 TNode<Array> array,
int array_header_size, Node* index_node,
1900 int additional_offset, ParameterMode parameter_mode,
1901 LoadSensitivity needs_poisoning) {
1902 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(
1903 ParameterToIntPtr(index_node, parameter_mode),
1904 IntPtrConstant(0)));
1905 DCHECK_EQ(additional_offset % kPointerSize, 0);
1906 int32_t header_size = array_header_size + additional_offset - kHeapObjectTag;
1907 TNode<IntPtrT> offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
1908 parameter_mode, header_size);
1909 CSA_ASSERT(
this, IsOffsetInBounds(offset, LoadArrayLength(array),
1910 array_header_size));
1911 return UncheckedCast<MaybeObject>(
1912 Load(MachineType::AnyTagged(), array, offset, needs_poisoning));
1915 template TNode<MaybeObject>
1916 CodeStubAssembler::LoadArrayElement<TransitionArray>(TNode<TransitionArray>,
1921 template TNode<MaybeObject>
1922 CodeStubAssembler::LoadArrayElement<DescriptorArray>(TNode<DescriptorArray>,
1927 void CodeStubAssembler::FixedArrayBoundsCheck(TNode<FixedArrayBase> array,
1929 int additional_offset,
1930 ParameterMode parameter_mode) {
1931 if (!FLAG_fixed_array_bounds_checks)
return;
1932 DCHECK_EQ(0, additional_offset % kPointerSize);
1933 if (parameter_mode == ParameterMode::SMI_PARAMETERS) {
1934 TNode<Smi> effective_index;
1936 bool index_is_constant = ToSmiConstant(index, &constant_index);
1937 if (index_is_constant) {
1938 effective_index = SmiConstant(Smi::ToInt(constant_index) +
1939 additional_offset / kPointerSize);
1940 }
else if (additional_offset != 0) {
1942 SmiAdd(CAST(index), SmiConstant(additional_offset / kPointerSize));
1944 effective_index = CAST(index);
1946 CSA_CHECK(
this, SmiBelow(effective_index, LoadFixedArrayBaseLength(array)));
1949 TNode<IntPtrT> effective_index =
1950 IntPtrAdd(UncheckedCast<IntPtrT>(index),
1951 IntPtrConstant(additional_offset / kPointerSize));
1952 CSA_CHECK(
this, UintPtrLessThan(effective_index,
1953 LoadAndUntagFixedArrayBaseLength(array)));
1957 TNode<Object> CodeStubAssembler::LoadFixedArrayElement(
1958 TNode<FixedArray>
object, Node* index_node,
int additional_offset,
1959 ParameterMode parameter_mode, LoadSensitivity needs_poisoning) {
1960 CSA_ASSERT(
this, IsFixedArraySubclass(
object));
1961 CSA_ASSERT(
this, IsNotWeakFixedArraySubclass(
object));
1962 FixedArrayBoundsCheck(
object, index_node, additional_offset, parameter_mode);
1963 TNode<MaybeObject> element =
1964 LoadArrayElement(
object, FixedArray::kHeaderSize, index_node,
1965 additional_offset, parameter_mode, needs_poisoning);
1966 return CAST(element);
1969 TNode<Object> CodeStubAssembler::LoadPropertyArrayElement(
1970 TNode<PropertyArray>
object, SloppyTNode<IntPtrT> index) {
1971 int additional_offset = 0;
1972 ParameterMode parameter_mode = INTPTR_PARAMETERS;
1973 LoadSensitivity needs_poisoning = LoadSensitivity::kSafe;
1974 return CAST(LoadArrayElement(
object, PropertyArray::kHeaderSize, index,
1975 additional_offset, parameter_mode,
1979 TNode<IntPtrT> CodeStubAssembler::LoadPropertyArrayLength(
1980 TNode<PropertyArray>
object) {
1981 TNode<IntPtrT> value =
1982 LoadAndUntagObjectField(
object, PropertyArray::kLengthAndHashOffset);
1983 return Signed(DecodeWord<PropertyArray::LengthField>(value));
1986 TNode<RawPtrT> CodeStubAssembler::LoadFixedTypedArrayBackingStore(
1987 TNode<FixedTypedArrayBase> typed_array) {
1989 Node* external_pointer =
1990 LoadObjectField(typed_array, FixedTypedArrayBase::kExternalPointerOffset,
1991 MachineType::Pointer());
1992 Node* base_pointer =
1993 LoadObjectField(typed_array, FixedTypedArrayBase::kBasePointerOffset);
1994 return UncheckedCast<RawPtrT>(
1995 IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer)));
1998 Node* CodeStubAssembler::LoadFixedBigInt64ArrayElementAsTagged(
1999 Node* data_pointer, Node* offset) {
2001 TNode<IntPtrT> value = UncheckedCast<IntPtrT>(
2002 Load(MachineType::IntPtr(), data_pointer, offset));
2003 return BigIntFromInt64(value);
2006 #if defined(V8_TARGET_BIG_ENDIAN) 2007 TNode<IntPtrT> high = UncheckedCast<IntPtrT>(
2008 Load(MachineType::UintPtr(), data_pointer, offset));
2009 TNode<IntPtrT> low = UncheckedCast<IntPtrT>(
2010 Load(MachineType::UintPtr(), data_pointer,
2011 Int32Add(offset, Int32Constant(kPointerSize))));
2013 TNode<IntPtrT> low = UncheckedCast<IntPtrT>(
2014 Load(MachineType::UintPtr(), data_pointer, offset));
2015 TNode<IntPtrT> high = UncheckedCast<IntPtrT>(
2016 Load(MachineType::UintPtr(), data_pointer,
2017 Int32Add(offset, Int32Constant(kPointerSize))));
2019 return BigIntFromInt32Pair(low, high);
2023 TNode<BigInt> CodeStubAssembler::BigIntFromInt32Pair(TNode<IntPtrT> low,
2024 TNode<IntPtrT> high) {
2026 TVARIABLE(BigInt, var_result);
2027 TVARIABLE(WordT, var_sign, IntPtrConstant(BigInt::SignBits::encode(
false)));
2028 TVARIABLE(IntPtrT, var_high, high);
2029 TVARIABLE(IntPtrT, var_low, low);
2030 Label high_zero(
this), negative(
this), allocate_one_digit(
this),
2031 allocate_two_digits(
this), if_zero(
this), done(
this);
2033 GotoIf(WordEqual(var_high.value(), IntPtrConstant(0)), &high_zero);
2034 Branch(IntPtrLessThan(var_high.value(), IntPtrConstant(0)), &negative,
2035 &allocate_two_digits);
2038 Branch(WordEqual(var_low.value(), IntPtrConstant(0)), &if_zero,
2039 &allocate_one_digit);
2043 var_sign = IntPtrConstant(BigInt::SignBits::encode(
true));
2047 var_high = IntPtrSub(IntPtrConstant(0), var_high.value());
2048 Label carry(
this), no_carry(
this);
2049 Branch(WordEqual(var_low.value(), IntPtrConstant(0)), &no_carry, &carry);
2051 var_high = IntPtrSub(var_high.value(), IntPtrConstant(1));
2054 var_low = IntPtrSub(IntPtrConstant(0), var_low.value());
2057 Branch(WordEqual(var_high.value(), IntPtrConstant(0)), &allocate_one_digit,
2058 &allocate_two_digits);
2061 BIND(&allocate_one_digit);
2063 var_result = AllocateRawBigInt(IntPtrConstant(1));
2064 StoreBigIntBitfield(var_result.value(),
2065 WordOr(var_sign.value(),
2066 IntPtrConstant(BigInt::LengthBits::encode(1))));
2067 StoreBigIntDigit(var_result.value(), 0, Unsigned(var_low.value()));
2071 BIND(&allocate_two_digits);
2073 var_result = AllocateRawBigInt(IntPtrConstant(2));
2074 StoreBigIntBitfield(var_result.value(),
2075 WordOr(var_sign.value(),
2076 IntPtrConstant(BigInt::LengthBits::encode(2))));
2077 StoreBigIntDigit(var_result.value(), 0, Unsigned(var_low.value()));
2078 StoreBigIntDigit(var_result.value(), 1, Unsigned(var_high.value()));
2083 var_result = AllocateBigInt(IntPtrConstant(0));
2087 return var_result.value();
2090 TNode<BigInt> CodeStubAssembler::BigIntFromInt64(TNode<IntPtrT> value) {
2092 TVARIABLE(BigInt, var_result);
2093 Label done(
this), if_positive(
this), if_negative(
this), if_zero(
this);
2094 GotoIf(WordEqual(value, IntPtrConstant(0)), &if_zero);
2095 var_result = AllocateRawBigInt(IntPtrConstant(1));
2096 Branch(IntPtrGreaterThan(value, IntPtrConstant(0)), &if_positive,
2101 StoreBigIntBitfield(var_result.value(),
2102 IntPtrConstant(BigInt::SignBits::encode(
false) |
2103 BigInt::LengthBits::encode(1)));
2104 StoreBigIntDigit(var_result.value(), 0, Unsigned(value));
2110 StoreBigIntBitfield(var_result.value(),
2111 IntPtrConstant(BigInt::SignBits::encode(
true) |
2112 BigInt::LengthBits::encode(1)));
2113 StoreBigIntDigit(var_result.value(), 0,
2114 Unsigned(IntPtrSub(IntPtrConstant(0), value)));
2120 var_result = AllocateBigInt(IntPtrConstant(0));
2125 return var_result.value();
2128 Node* CodeStubAssembler::LoadFixedBigUint64ArrayElementAsTagged(
2129 Node* data_pointer, Node* offset) {
2130 Label if_zero(
this), done(
this);
2132 TNode<UintPtrT> value = UncheckedCast<UintPtrT>(
2133 Load(MachineType::UintPtr(), data_pointer, offset));
2134 return BigIntFromUint64(value);
2137 #if defined(V8_TARGET_BIG_ENDIAN) 2138 TNode<UintPtrT> high = UncheckedCast<UintPtrT>(
2139 Load(MachineType::UintPtr(), data_pointer, offset));
2140 TNode<UintPtrT> low = UncheckedCast<UintPtrT>(
2141 Load(MachineType::UintPtr(), data_pointer,
2142 Int32Add(offset, Int32Constant(kPointerSize))));
2144 TNode<UintPtrT> low = UncheckedCast<UintPtrT>(
2145 Load(MachineType::UintPtr(), data_pointer, offset));
2146 TNode<UintPtrT> high = UncheckedCast<UintPtrT>(
2147 Load(MachineType::UintPtr(), data_pointer,
2148 Int32Add(offset, Int32Constant(kPointerSize))));
2150 return BigIntFromUint32Pair(low, high);
2154 TNode<BigInt> CodeStubAssembler::BigIntFromUint32Pair(TNode<UintPtrT> low,
2155 TNode<UintPtrT> high) {
2157 TVARIABLE(BigInt, var_result);
2158 Label high_zero(
this), if_zero(
this), done(
this);
2160 GotoIf(WordEqual(high, IntPtrConstant(0)), &high_zero);
2161 var_result = AllocateBigInt(IntPtrConstant(2));
2162 StoreBigIntDigit(var_result.value(), 0, low);
2163 StoreBigIntDigit(var_result.value(), 1, high);
2167 GotoIf(WordEqual(low, IntPtrConstant(0)), &if_zero);
2168 var_result = AllocateBigInt(IntPtrConstant(1));
2169 StoreBigIntDigit(var_result.value(), 0, low);
2173 var_result = AllocateBigInt(IntPtrConstant(0));
2177 return var_result.value();
2180 TNode<BigInt> CodeStubAssembler::BigIntFromUint64(TNode<UintPtrT> value) {
2182 TVARIABLE(BigInt, var_result);
2183 Label done(
this), if_zero(
this);
2184 GotoIf(WordEqual(value, IntPtrConstant(0)), &if_zero);
2185 var_result = AllocateBigInt(IntPtrConstant(1));
2186 StoreBigIntDigit(var_result.value(), 0, value);
2190 var_result = AllocateBigInt(IntPtrConstant(0));
2193 return var_result.value();
2196 Node* CodeStubAssembler::LoadFixedTypedArrayElementAsTagged(
2197 Node* data_pointer, Node* index_node, ElementsKind elements_kind,
2198 ParameterMode parameter_mode) {
2200 ElementOffsetFromIndex(index_node, elements_kind, parameter_mode, 0);
2201 switch (elements_kind) {
2202 case UINT8_ELEMENTS:
2203 case UINT8_CLAMPED_ELEMENTS:
2204 return SmiFromInt32(Load(MachineType::Uint8(), data_pointer, offset));
2206 return SmiFromInt32(Load(MachineType::Int8(), data_pointer, offset));
2207 case UINT16_ELEMENTS:
2208 return SmiFromInt32(Load(MachineType::Uint16(), data_pointer, offset));
2209 case INT16_ELEMENTS:
2210 return SmiFromInt32(Load(MachineType::Int16(), data_pointer, offset));
2211 case UINT32_ELEMENTS:
2212 return ChangeUint32ToTagged(
2213 Load(MachineType::Uint32(), data_pointer, offset));
2214 case INT32_ELEMENTS:
2215 return ChangeInt32ToTagged(
2216 Load(MachineType::Int32(), data_pointer, offset));
2217 case FLOAT32_ELEMENTS:
2218 return AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(
2219 Load(MachineType::Float32(), data_pointer, offset)));
2220 case FLOAT64_ELEMENTS:
2221 return AllocateHeapNumberWithValue(
2222 Load(MachineType::Float64(), data_pointer, offset));
2223 case BIGINT64_ELEMENTS:
2224 return LoadFixedBigInt64ArrayElementAsTagged(data_pointer, offset);
2225 case BIGUINT64_ELEMENTS:
2226 return LoadFixedBigUint64ArrayElementAsTagged(data_pointer, offset);
2232 TNode<Numeric> CodeStubAssembler::LoadFixedTypedArrayElementAsTagged(
2233 TNode<WordT> data_pointer, TNode<Smi> index, TNode<Int32T> elements_kind) {
2234 TVARIABLE(Numeric, var_result);
2235 Label done(
this), if_unknown_type(
this, Label::kDeferred);
2236 int32_t elements_kinds[] = {
2237 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) TYPE##_ELEMENTS, 2238 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2239 #undef TYPED_ARRAY_CASE 2242 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) Label if_##type##array(this); 2243 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2244 #undef TYPED_ARRAY_CASE 2246 Label* elements_kind_labels[] = {
2247 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) &if_##type##array, 2248 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2249 #undef TYPED_ARRAY_CASE 2251 STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
2253 Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
2254 arraysize(elements_kinds));
2256 BIND(&if_unknown_type);
2259 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 2260 BIND(&if_##type##array); \ 2262 var_result = CAST(LoadFixedTypedArrayElementAsTagged( \ 2263 data_pointer, index, TYPE##_ELEMENTS, SMI_PARAMETERS)); \ 2266 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2267 #undef TYPED_ARRAY_CASE 2270 return var_result.value();
2273 void CodeStubAssembler::StoreFixedTypedArrayElementFromTagged(
2274 TNode<Context> context, TNode<FixedTypedArrayBase> elements,
2275 TNode<Object> index_node, TNode<Object> value, ElementsKind elements_kind,
2276 ParameterMode parameter_mode) {
2277 TNode<RawPtrT> data_pointer = LoadFixedTypedArrayBackingStore(elements);
2278 switch (elements_kind) {
2279 case UINT8_ELEMENTS:
2280 case UINT8_CLAMPED_ELEMENTS:
2282 case UINT16_ELEMENTS:
2283 case INT16_ELEMENTS:
2284 StoreElement(data_pointer, elements_kind, index_node,
2285 SmiToInt32(CAST(value)), parameter_mode);
2287 case UINT32_ELEMENTS:
2288 case INT32_ELEMENTS:
2289 StoreElement(data_pointer, elements_kind, index_node,
2290 TruncateTaggedToWord32(context, value), parameter_mode);
2292 case FLOAT32_ELEMENTS:
2293 StoreElement(data_pointer, elements_kind, index_node,
2294 TruncateFloat64ToFloat32(LoadHeapNumberValue(CAST(value))),
2297 case FLOAT64_ELEMENTS:
2298 StoreElement(data_pointer, elements_kind, index_node,
2299 LoadHeapNumberValue(CAST(value)), parameter_mode);
2301 case BIGUINT64_ELEMENTS:
2302 case BIGINT64_ELEMENTS: {
2303 TNode<IntPtrT> offset =
2304 ElementOffsetFromIndex(index_node, elements_kind, parameter_mode, 0);
2305 EmitBigTypedArrayElementStore(elements, data_pointer, offset,
2314 TNode<MaybeObject> CodeStubAssembler::LoadFeedbackVectorSlot(
2315 Node*
object, Node* slot_index_node,
int additional_offset,
2316 ParameterMode parameter_mode) {
2317 CSA_SLOW_ASSERT(
this, IsFeedbackVector(
object));
2318 CSA_SLOW_ASSERT(
this, MatchesParameterMode(slot_index_node, parameter_mode));
2319 int32_t header_size =
2320 FeedbackVector::kFeedbackSlotsOffset + additional_offset - kHeapObjectTag;
2321 Node* offset = ElementOffsetFromIndex(slot_index_node, HOLEY_ELEMENTS,
2322 parameter_mode, header_size);
2324 this, IsOffsetInBounds(offset, LoadFeedbackVectorLength(CAST(
object)),
2325 FeedbackVector::kHeaderSize));
2326 return UncheckedCast<MaybeObject>(
2327 Load(MachineType::AnyTagged(),
object, offset));
2330 template <
typename Array>
2331 TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32ArrayElement(
2332 TNode<Array>
object,
int array_header_size, Node* index_node,
2333 int additional_offset, ParameterMode parameter_mode) {
2334 CSA_SLOW_ASSERT(
this, MatchesParameterMode(index_node, parameter_mode));
2335 DCHECK_EQ(additional_offset % kPointerSize, 0);
2336 int endian_correction = 0;
2337 #if V8_TARGET_LITTLE_ENDIAN 2338 if (SmiValuesAre32Bits()) endian_correction = kPointerSize / 2;
2340 int32_t header_size = array_header_size + additional_offset - kHeapObjectTag +
2342 Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
2343 parameter_mode, header_size);
2344 CSA_ASSERT(
this, IsOffsetInBounds(offset, LoadArrayLength(
object),
2345 array_header_size + endian_correction));
2346 if (SmiValuesAre32Bits()) {
2347 return UncheckedCast<Int32T>(Load(MachineType::Int32(),
object, offset));
2349 return SmiToInt32(Load(MachineType::AnyTagged(),
object, offset));
2353 TNode<Int32T> CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement(
2354 TNode<FixedArray>
object, Node* index_node,
int additional_offset,
2355 ParameterMode parameter_mode) {
2356 CSA_SLOW_ASSERT(
this, IsFixedArraySubclass(
object));
2357 return LoadAndUntagToWord32ArrayElement(
object, FixedArray::kHeaderSize,
2358 index_node, additional_offset,
2362 TNode<MaybeObject> CodeStubAssembler::LoadWeakFixedArrayElement(
2363 TNode<WeakFixedArray>
object, Node* index,
int additional_offset,
2364 ParameterMode parameter_mode, LoadSensitivity needs_poisoning) {
2365 return LoadArrayElement(
object, WeakFixedArray::kHeaderSize, index,
2366 additional_offset, parameter_mode, needs_poisoning);
2369 TNode<Float64T> CodeStubAssembler::LoadFixedDoubleArrayElement(
2370 SloppyTNode<FixedDoubleArray>
object, Node* index_node,
2371 MachineType machine_type,
int additional_offset,
2372 ParameterMode parameter_mode, Label* if_hole) {
2373 CSA_ASSERT(
this, IsFixedDoubleArray(
object));
2374 DCHECK_EQ(additional_offset % kPointerSize, 0);
2375 CSA_SLOW_ASSERT(
this, MatchesParameterMode(index_node, parameter_mode));
2376 int32_t header_size =
2377 FixedDoubleArray::kHeaderSize + additional_offset - kHeapObjectTag;
2378 TNode<IntPtrT> offset = ElementOffsetFromIndex(
2379 index_node, HOLEY_DOUBLE_ELEMENTS, parameter_mode, header_size);
2380 CSA_ASSERT(
this, IsOffsetInBounds(
2381 offset, LoadAndUntagFixedArrayBaseLength(
object),
2382 FixedDoubleArray::kHeaderSize, HOLEY_DOUBLE_ELEMENTS));
2383 return LoadDoubleWithHoleCheck(
object, offset, if_hole, machine_type);
2386 TNode<Object> CodeStubAssembler::LoadFixedArrayBaseElementAsTagged(
2387 TNode<FixedArrayBase> elements, TNode<IntPtrT> index,
2388 TNode<Int32T> elements_kind, Label* if_accessor, Label* if_hole) {
2389 TVARIABLE(Object, var_result);
2390 Label done(
this), if_packed(
this), if_holey(
this), if_packed_double(
this),
2391 if_holey_double(
this), if_dictionary(
this, Label::kDeferred);
2394 PACKED_SMI_ELEMENTS, PACKED_ELEMENTS,
2396 HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS,
2398 PACKED_DOUBLE_ELEMENTS,
2400 HOLEY_DOUBLE_ELEMENTS};
2402 &if_packed, &if_packed,
2404 &if_holey, &if_holey,
2409 Switch(elements_kind, &if_dictionary, kinds, labels, arraysize(kinds));
2413 var_result = LoadFixedArrayElement(CAST(elements), index, 0);
2419 var_result = LoadFixedArrayElement(CAST(elements), index);
2420 Branch(WordEqual(var_result.value(), TheHoleConstant()), if_hole, &done);
2423 BIND(&if_packed_double);
2425 var_result = AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
2426 CAST(elements), index, MachineType::Float64()));
2430 BIND(&if_holey_double);
2432 var_result = AllocateHeapNumberWithValue(LoadFixedDoubleArrayElement(
2433 CAST(elements), index, MachineType::Float64(), 0, INTPTR_PARAMETERS,
2438 BIND(&if_dictionary);
2440 CSA_ASSERT(
this, IsDictionaryElementsKind(elements_kind));
2441 var_result = BasicLoadNumberDictionaryElement(CAST(elements), index,
2442 if_accessor, if_hole);
2447 return var_result.value();
2450 TNode<Float64T> CodeStubAssembler::LoadDoubleWithHoleCheck(
2451 SloppyTNode<Object> base, SloppyTNode<IntPtrT> offset, Label* if_hole,
2452 MachineType machine_type) {
2458 Node* element = Load(MachineType::Uint64(), base, offset);
2459 GotoIf(Word64Equal(element, Int64Constant(kHoleNanInt64)), if_hole);
2461 Node* element_upper = Load(
2462 MachineType::Uint32(), base,
2463 IntPtrAdd(offset, IntPtrConstant(kIeeeDoubleExponentWordOffset)));
2464 GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
2468 if (machine_type.IsNone()) {
2470 return TNode<Float64T>();
2472 return UncheckedCast<Float64T>(Load(machine_type, base, offset));
2475 TNode<Object> CodeStubAssembler::LoadContextElement(
2476 SloppyTNode<Context> context,
int slot_index) {
2477 int offset = Context::SlotOffset(slot_index);
2478 return UncheckedCast<Object>(
2479 Load(MachineType::AnyTagged(), context, IntPtrConstant(offset)));
2482 TNode<Object> CodeStubAssembler::LoadContextElement(
2483 SloppyTNode<Context> context, SloppyTNode<IntPtrT> slot_index) {
2484 Node* offset = ElementOffsetFromIndex(
2485 slot_index, PACKED_ELEMENTS, INTPTR_PARAMETERS, Context::SlotOffset(0));
2486 return UncheckedCast<Object>(Load(MachineType::AnyTagged(), context, offset));
2489 TNode<Object> CodeStubAssembler::LoadContextElement(TNode<Context> context,
2490 TNode<Smi> slot_index) {
2491 Node* offset = ElementOffsetFromIndex(slot_index, PACKED_ELEMENTS,
2492 SMI_PARAMETERS, Context::SlotOffset(0));
2493 return UncheckedCast<Object>(Load(MachineType::AnyTagged(), context, offset));
2496 void CodeStubAssembler::StoreContextElement(SloppyTNode<Context> context,
2498 SloppyTNode<Object> value) {
2499 int offset = Context::SlotOffset(slot_index);
2500 Store(context, IntPtrConstant(offset), value);
2503 void CodeStubAssembler::StoreContextElement(SloppyTNode<Context> context,
2504 SloppyTNode<IntPtrT> slot_index,
2505 SloppyTNode<Object> value) {
2506 Node* offset = IntPtrAdd(TimesPointerSize(slot_index),
2507 IntPtrConstant(Context::SlotOffset(0)));
2508 Store(context, offset, value);
2511 void CodeStubAssembler::StoreContextElementNoWriteBarrier(
2512 SloppyTNode<Context> context,
int slot_index, SloppyTNode<Object> value) {
2513 int offset = Context::SlotOffset(slot_index);
2514 StoreNoWriteBarrier(MachineRepresentation::kTagged, context,
2515 IntPtrConstant(offset), value);
2518 TNode<Context> CodeStubAssembler::LoadNativeContext(
2519 SloppyTNode<Context> context) {
2520 return UncheckedCast<Context>(
2521 LoadContextElement(context, Context::NATIVE_CONTEXT_INDEX));
2524 TNode<Context> CodeStubAssembler::LoadModuleContext(
2525 SloppyTNode<Context> context) {
2526 Node* module_map = LoadRoot(RootIndex::kModuleContextMap);
2527 Variable cur_context(
this, MachineRepresentation::kTaggedPointer);
2528 cur_context.Bind(context);
2530 Label context_found(
this);
2532 Variable* context_search_loop_variables[1] = {&cur_context};
2533 Label context_search(
this, 1, context_search_loop_variables);
2536 Goto(&context_search);
2537 BIND(&context_search);
2539 CSA_ASSERT(
this, Word32BinaryNot(IsNativeContext(cur_context.value())));
2540 GotoIf(WordEqual(LoadMap(cur_context.value()), module_map), &context_found);
2543 LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX));
2544 Goto(&context_search);
2547 BIND(&context_found);
2548 return UncheckedCast<Context>(cur_context.value());
2551 TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
2552 SloppyTNode<Int32T> kind, SloppyTNode<Context> native_context) {
2553 CSA_ASSERT(
this, IsFastElementsKind(kind));
2554 CSA_ASSERT(
this, IsNativeContext(native_context));
2555 Node* offset = IntPtrAdd(IntPtrConstant(Context::FIRST_JS_ARRAY_MAP_SLOT),
2556 ChangeInt32ToIntPtr(kind));
2557 return UncheckedCast<Map>(LoadContextElement(native_context, offset));
2560 TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
2561 ElementsKind kind, SloppyTNode<Context> native_context) {
2562 CSA_ASSERT(
this, IsNativeContext(native_context));
2563 return UncheckedCast<Map>(
2564 LoadContextElement(native_context, Context::ArrayMapIndex(kind)));
2567 TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
2568 TNode<JSFunction>
function) {
2569 TNode<SharedFunctionInfo>
const shared_function_info =
2570 CAST(LoadObjectField(
function, JSFunction::kSharedFunctionInfoOffset));
2572 TNode<Uint32T>
const function_kind =
2573 DecodeWord32<SharedFunctionInfo::FunctionKindBits>(LoadObjectField(
2574 shared_function_info, SharedFunctionInfo::kFlagsOffset,
2575 MachineType::Uint32()));
2577 return TNode<BoolT>::UncheckedCast(Word32Or(
2580 Word32Equal(function_kind,
2581 Int32Constant(FunctionKind::kAsyncGeneratorFunction)),
2584 Int32Constant(FunctionKind::kAsyncConciseGeneratorMethod))),
2585 Word32Equal(function_kind,
2586 Int32Constant(FunctionKind::kGeneratorFunction))),
2587 Word32Equal(function_kind,
2588 Int32Constant(FunctionKind::kConciseGeneratorMethod))));
2591 TNode<BoolT> CodeStubAssembler::HasPrototypeProperty(TNode<JSFunction>
function,
2596 Map::HasPrototypeSlotBit::kMask | Map::IsConstructorBit::kMask;
2597 return TNode<BoolT>::UncheckedCast(
2598 Word32Or(IsAllSetWord32(LoadMapBitField(map), mask),
2599 IsGeneratorFunction(
function)));
2602 void CodeStubAssembler::GotoIfPrototypeRequiresRuntimeLookup(
2603 TNode<JSFunction>
function, TNode<Map> map, Label* runtime) {
2605 GotoIfNot(HasPrototypeProperty(
function, map), runtime);
2606 GotoIf(IsSetWord32<Map::HasNonInstancePrototypeBit>(LoadMapBitField(map)),
2610 Node* CodeStubAssembler::LoadJSFunctionPrototype(Node*
function,
2611 Label* if_bailout) {
2612 CSA_ASSERT(
this, TaggedIsNotSmi(
function));
2613 CSA_ASSERT(
this, IsJSFunction(
function));
2614 CSA_ASSERT(
this, IsFunctionWithPrototypeSlotMap(LoadMap(
function)));
2615 CSA_ASSERT(
this, IsClearWord32<Map::HasNonInstancePrototypeBit>(
2616 LoadMapBitField(LoadMap(
function))));
2617 Node* proto_or_map =
2618 LoadObjectField(
function, JSFunction::kPrototypeOrInitialMapOffset);
2619 GotoIf(IsTheHole(proto_or_map), if_bailout);
2621 VARIABLE(var_result, MachineRepresentation::kTagged, proto_or_map);
2622 Label done(
this, &var_result);
2623 GotoIfNot(IsMap(proto_or_map), &done);
2625 var_result.Bind(LoadMapPrototype(proto_or_map));
2629 return var_result.value();
2632 TNode<BytecodeArray> CodeStubAssembler::LoadSharedFunctionInfoBytecodeArray(
2633 SloppyTNode<SharedFunctionInfo> shared) {
2634 Node* function_data =
2635 LoadObjectField(shared, SharedFunctionInfo::kFunctionDataOffset);
2637 VARIABLE(var_result, MachineRepresentation::kTagged, function_data);
2638 Label done(
this, &var_result);
2640 GotoIfNot(HasInstanceType(function_data, INTERPRETER_DATA_TYPE), &done);
2641 Node* bytecode_array =
2642 LoadObjectField(function_data, InterpreterData::kBytecodeArrayOffset);
2643 var_result.Bind(bytecode_array);
2647 return CAST(var_result.value());
2650 void CodeStubAssembler::StoreObjectByteNoWriteBarrier(TNode<HeapObject>
object,
2652 TNode<Word32T> value) {
2653 StoreNoWriteBarrier(MachineRepresentation::kWord8,
object,
2654 IntPtrConstant(offset - kHeapObjectTag), value);
2657 void CodeStubAssembler::StoreHeapNumberValue(SloppyTNode<HeapNumber>
object,
2658 SloppyTNode<Float64T> value) {
2659 StoreObjectFieldNoWriteBarrier(
object, HeapNumber::kValueOffset, value,
2660 MachineRepresentation::kFloat64);
2663 void CodeStubAssembler::StoreMutableHeapNumberValue(
2664 SloppyTNode<MutableHeapNumber>
object, SloppyTNode<Float64T> value) {
2665 StoreObjectFieldNoWriteBarrier(
object, MutableHeapNumber::kValueOffset, value,
2666 MachineRepresentation::kFloat64);
2669 Node* CodeStubAssembler::StoreObjectField(
2670 Node*
object,
int offset, Node* value) {
2671 DCHECK_NE(HeapObject::kMapOffset, offset);
2672 return Store(
object, IntPtrConstant(offset - kHeapObjectTag), value);
2675 Node* CodeStubAssembler::StoreObjectField(Node*
object, Node* offset,
2678 if (ToInt32Constant(offset, const_offset)) {
2679 return StoreObjectField(
object, const_offset, value);
2681 return Store(
object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)),
2685 Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
2686 Node*
object,
int offset, Node* value, MachineRepresentation rep) {
2687 return StoreNoWriteBarrier(rep,
object,
2688 IntPtrConstant(offset - kHeapObjectTag), value);
2691 Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier(
2692 Node*
object, Node* offset, Node* value, MachineRepresentation rep) {
2694 if (ToInt32Constant(offset, const_offset)) {
2695 return StoreObjectFieldNoWriteBarrier(
object, const_offset, value, rep);
2697 return StoreNoWriteBarrier(
2698 rep,
object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag)), value);
2701 Node* CodeStubAssembler::StoreMap(Node*
object, Node* map) {
2702 CSA_SLOW_ASSERT(
this, IsMap(map));
2703 return StoreWithMapWriteBarrier(
2704 object, IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), map);
2707 Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node*
object,
2708 RootIndex map_root_index) {
2709 return StoreMapNoWriteBarrier(
object, LoadRoot(map_root_index));
2712 Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node*
object, Node* map) {
2713 CSA_SLOW_ASSERT(
this, IsMap(map));
2714 return StoreNoWriteBarrier(
2715 MachineRepresentation::kTagged,
object,
2716 IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag), map);
2719 Node* CodeStubAssembler::StoreObjectFieldRoot(Node*
object,
int offset,
2720 RootIndex root_index) {
2721 if (RootsTable::IsImmortalImmovable(root_index)) {
2722 return StoreObjectFieldNoWriteBarrier(
object, offset, LoadRoot(root_index));
2724 return StoreObjectField(
object, offset, LoadRoot(root_index));
2728 Node* CodeStubAssembler::StoreJSArrayLength(TNode<JSArray> array,
2729 TNode<Smi> length) {
2730 return StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
2733 Node* CodeStubAssembler::StoreElements(TNode<Object>
object,
2734 TNode<FixedArrayBase> elements) {
2735 return StoreObjectField(
object, JSObject::kElementsOffset, elements);
2738 void CodeStubAssembler::StoreFixedArrayOrPropertyArrayElement(
2739 Node*
object, Node* index_node, Node* value, WriteBarrierMode barrier_mode,
2740 int additional_offset, ParameterMode parameter_mode) {
2742 this, Word32Or(IsFixedArraySubclass(
object), IsPropertyArray(
object)));
2743 CSA_SLOW_ASSERT(
this, MatchesParameterMode(index_node, parameter_mode));
2744 DCHECK(barrier_mode == SKIP_WRITE_BARRIER ||
2745 barrier_mode == UPDATE_WRITE_BARRIER);
2746 DCHECK_EQ(additional_offset % kPointerSize, 0);
2747 STATIC_ASSERT(FixedArray::kHeaderSize == PropertyArray::kHeaderSize);
2749 FixedArray::kHeaderSize + additional_offset - kHeapObjectTag;
2750 Node* offset = ElementOffsetFromIndex(index_node, HOLEY_ELEMENTS,
2751 parameter_mode, header_size);
2752 STATIC_ASSERT(static_cast<int>(FixedArrayBase::kLengthOffset) ==
2753 static_cast<int>(WeakFixedArray::kLengthOffset));
2754 STATIC_ASSERT(static_cast<int>(FixedArrayBase::kLengthOffset) ==
2755 static_cast<int>(PropertyArray::kLengthAndHashOffset));
2763 IsPropertyArray(
object),
2765 TNode<IntPtrT> length_and_hash = LoadAndUntagObjectField(
2766 object, PropertyArray::kLengthAndHashOffset);
2767 return TNode<IntPtrT>::UncheckedCast(
2768 DecodeWord<PropertyArray::LengthField>(length_and_hash));
2771 return LoadAndUntagObjectField(
object,
2772 FixedArrayBase::kLengthOffset);
2774 FixedArray::kHeaderSize));
2775 if (barrier_mode == SKIP_WRITE_BARRIER) {
2776 StoreNoWriteBarrier(MachineRepresentation::kTagged,
object, offset, value);
2778 Store(
object, offset, value);
2782 void CodeStubAssembler::StoreFixedDoubleArrayElement(
2783 TNode<FixedDoubleArray>
object, Node* index_node, TNode<Float64T> value,
2784 ParameterMode parameter_mode) {
2785 CSA_ASSERT(
this, IsFixedDoubleArray(
object));
2786 CSA_SLOW_ASSERT(
this, MatchesParameterMode(index_node, parameter_mode));
2787 FixedArrayBoundsCheck(
object, index_node, 0, parameter_mode);
2789 ElementOffsetFromIndex(index_node, PACKED_DOUBLE_ELEMENTS, parameter_mode,
2790 FixedArray::kHeaderSize - kHeapObjectTag);
2791 MachineRepresentation rep = MachineRepresentation::kFloat64;
2792 StoreNoWriteBarrier(rep,
object, offset, value);
2795 Node* CodeStubAssembler::StoreFeedbackVectorSlot(Node*
object,
2796 Node* slot_index_node,
2798 WriteBarrierMode barrier_mode,
2799 int additional_offset,
2800 ParameterMode parameter_mode) {
2801 CSA_SLOW_ASSERT(
this, IsFeedbackVector(
object));
2802 CSA_SLOW_ASSERT(
this, MatchesParameterMode(slot_index_node, parameter_mode));
2803 DCHECK_EQ(additional_offset % kPointerSize, 0);
2804 DCHECK(barrier_mode == SKIP_WRITE_BARRIER ||
2805 barrier_mode == UPDATE_WRITE_BARRIER);
2807 FeedbackVector::kFeedbackSlotsOffset + additional_offset - kHeapObjectTag;
2808 Node* offset = ElementOffsetFromIndex(slot_index_node, HOLEY_ELEMENTS,
2809 parameter_mode, header_size);
2812 IsOffsetInBounds(offset, LoadFeedbackVectorLength(CAST(
object)),
2813 FeedbackVector::kHeaderSize));
2814 if (barrier_mode == SKIP_WRITE_BARRIER) {
2815 return StoreNoWriteBarrier(MachineRepresentation::kTagged,
object, offset,
2818 return Store(
object, offset, value);
2822 void CodeStubAssembler::EnsureArrayLengthWritable(TNode<Map> map,
2825 GotoIf(IsDictionaryMap(map), bailout);
2830 TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
2832 int length_index = JSArray::kLengthDescriptorIndex;
2834 TNode<Name> maybe_length =
2835 LoadKeyByDescriptorEntry(descriptors, length_index);
2837 WordEqual(maybe_length, LoadRoot(RootIndex::klength_string)));
2840 TNode<Uint32T> details =
2841 LoadDetailsByDescriptorEntry(descriptors, length_index);
2842 GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
2846 TNode<Int32T> CodeStubAssembler::EnsureArrayPushable(TNode<Map> map,
2850 Comment(
"Disallow pushing onto prototypes");
2851 Node* bit_field2 = LoadMapBitField2(map);
2852 int mask = Map::IsPrototypeMapBit::kMask | Map::IsExtensibleBit::kMask;
2853 Node* test = Word32And(bit_field2, Int32Constant(mask));
2854 GotoIf(Word32NotEqual(test, Int32Constant(Map::IsExtensibleBit::kMask)),
2857 EnsureArrayLengthWritable(map, bailout);
2859 TNode<Uint32T> kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
2860 return Signed(kind);
2863 void CodeStubAssembler::PossiblyGrowElementsCapacity(
2864 ParameterMode mode, ElementsKind kind, Node* array, Node* length,
2865 Variable* var_elements, Node* growth, Label* bailout) {
2866 Label fits(
this, var_elements);
2868 TaggedToParameter(LoadFixedArrayBaseLength(var_elements->value()), mode);
2871 Node* new_length = IntPtrOrSmiAdd(growth, length, mode);
2872 GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), &fits);
2873 Node* new_capacity = CalculateNewElementsCapacity(new_length, mode);
2874 var_elements->Bind(GrowElementsCapacity(array, var_elements->value(), kind,
2875 kind, capacity, new_capacity, mode,
2881 TNode<Smi> CodeStubAssembler::BuildAppendJSArray(ElementsKind kind,
2882 SloppyTNode<JSArray> array,
2883 CodeStubArguments* args,
2884 TVariable<IntPtrT>* arg_index,
2886 CSA_SLOW_ASSERT(
this, IsJSArray(array));
2887 Comment(
"BuildAppendJSArray: %s", ElementsKindToString(kind));
2888 Label pre_bailout(
this);
2889 Label success(
this);
2890 TVARIABLE(Smi, var_tagged_length);
2891 ParameterMode mode = OptimalParameterMode();
2892 VARIABLE(var_length, OptimalParameterRepresentation(),
2893 TaggedToParameter(LoadFastJSArrayLength(array), mode));
2894 VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array));
2897 TNode<IntPtrT> first = arg_index->value();
2898 Node* growth = IntPtrToParameter(
2899 IntPtrSub(UncheckedCast<IntPtrT>(args->GetLength(INTPTR_PARAMETERS)),
2902 PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(),
2903 &var_elements, growth, &pre_bailout);
2907 CodeStubAssembler::VariableList push_vars({&var_length}, zone());
2908 Node* elements = var_elements.value();
2911 [
this, kind, mode, elements, &var_length, &pre_bailout](Node* arg) {
2912 TryStoreArrayElement(kind, mode, &pre_bailout, elements,
2913 var_length.value(), arg);
2914 Increment(&var_length, 1, mode);
2918 TNode<Smi> length = ParameterToTagged(var_length.value(), mode);
2919 var_tagged_length = length;
2920 StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
2926 TNode<Smi> length = ParameterToTagged(var_length.value(), mode);
2927 var_tagged_length = length;
2928 Node* diff = SmiSub(length, LoadFastJSArrayLength(array));
2929 StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
2930 *arg_index = IntPtrAdd(arg_index->value(), SmiUntag(diff));
2935 return var_tagged_length.value();
2938 void CodeStubAssembler::TryStoreArrayElement(ElementsKind kind,
2939 ParameterMode mode, Label* bailout,
2940 Node* elements, Node* index,
2942 if (IsSmiElementsKind(kind)) {
2943 GotoIf(TaggedIsNotSmi(value), bailout);
2944 }
else if (IsDoubleElementsKind(kind)) {
2945 GotoIfNotNumber(value, bailout);
2947 if (IsDoubleElementsKind(kind)) value = ChangeNumberToFloat64(value);
2948 StoreElement(elements, kind, index, value, mode);
2951 void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array,
2952 Node* value, Label* bailout) {
2953 CSA_SLOW_ASSERT(
this, IsJSArray(array));
2954 Comment(
"BuildAppendJSArray: %s", ElementsKindToString(kind));
2955 ParameterMode mode = OptimalParameterMode();
2956 VARIABLE(var_length, OptimalParameterRepresentation(),
2957 TaggedToParameter(LoadFastJSArrayLength(array), mode));
2958 VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array));
2961 Node* growth = IntPtrOrSmiConstant(1, mode);
2962 PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(),
2963 &var_elements, growth, bailout);
2967 TryStoreArrayElement(kind, mode, bailout, var_elements.value(),
2968 var_length.value(), value);
2969 Increment(&var_length, 1, mode);
2971 Node* length = ParameterToTagged(var_length.value(), mode);
2972 StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
2975 Node* CodeStubAssembler::AllocateCellWithValue(Node* value,
2976 WriteBarrierMode mode) {
2977 Node* result = Allocate(Cell::kSize, kNone);
2978 StoreMapNoWriteBarrier(result, RootIndex::kCellMap);
2979 StoreCellValue(result, value, mode);
2983 Node* CodeStubAssembler::LoadCellValue(Node* cell) {
2984 CSA_SLOW_ASSERT(
this, HasInstanceType(cell, CELL_TYPE));
2985 return LoadObjectField(cell, Cell::kValueOffset);
2988 Node* CodeStubAssembler::StoreCellValue(Node* cell, Node* value,
2989 WriteBarrierMode mode) {
2990 CSA_SLOW_ASSERT(
this, HasInstanceType(cell, CELL_TYPE));
2991 DCHECK(mode == SKIP_WRITE_BARRIER || mode == UPDATE_WRITE_BARRIER);
2993 if (mode == UPDATE_WRITE_BARRIER) {
2994 return StoreObjectField(cell, Cell::kValueOffset, value);
2996 return StoreObjectFieldNoWriteBarrier(cell, Cell::kValueOffset, value);
3000 TNode<HeapNumber> CodeStubAssembler::AllocateHeapNumber() {
3001 Node* result = Allocate(HeapNumber::kSize, kNone);
3002 RootIndex heap_map_index = RootIndex::kHeapNumberMap;
3003 StoreMapNoWriteBarrier(result, heap_map_index);
3004 return UncheckedCast<HeapNumber>(result);
3007 TNode<HeapNumber> CodeStubAssembler::AllocateHeapNumberWithValue(
3008 SloppyTNode<Float64T> value) {
3009 TNode<HeapNumber> result = AllocateHeapNumber();
3010 StoreHeapNumberValue(result, value);
3014 TNode<MutableHeapNumber> CodeStubAssembler::AllocateMutableHeapNumber() {
3015 Node* result = Allocate(MutableHeapNumber::kSize, kNone);
3016 RootIndex heap_map_index = RootIndex::kMutableHeapNumberMap;
3017 StoreMapNoWriteBarrier(result, heap_map_index);
3018 return UncheckedCast<MutableHeapNumber>(result);
3021 TNode<Object> CodeStubAssembler::CloneIfMutablePrimitive(TNode<Object>
object) {
3022 TVARIABLE(Object, result,
object);
3025 GotoIf(TaggedIsSmi(
object), &done);
3026 GotoIfNot(IsMutableHeapNumber(UncheckedCast<HeapObject>(
object)), &done);
3029 TNode<Float64T> value =
3030 LoadHeapNumberValue(UncheckedCast<HeapNumber>(
object));
3031 result = AllocateMutableHeapNumberWithValue(value);
3036 return result.value();
3039 TNode<MutableHeapNumber> CodeStubAssembler::AllocateMutableHeapNumberWithValue(
3040 SloppyTNode<Float64T> value) {
3041 TNode<MutableHeapNumber> result = AllocateMutableHeapNumber();
3042 StoreMutableHeapNumberValue(result, value);
3046 TNode<BigInt> CodeStubAssembler::AllocateBigInt(TNode<IntPtrT> length) {
3047 TNode<BigInt> result = AllocateRawBigInt(length);
3048 StoreBigIntBitfield(result, WordShl(length, BigInt::LengthBits::kShift));
3052 TNode<BigInt> CodeStubAssembler::AllocateRawBigInt(TNode<IntPtrT> length) {
3055 CSA_ASSERT(
this, UintPtrLessThan(length, IntPtrConstant(3)));
3057 TNode<IntPtrT> size = IntPtrAdd(IntPtrConstant(BigInt::kHeaderSize),
3058 Signed(WordShl(length, kPointerSizeLog2)));
3059 Node* raw_result = Allocate(size, kNone);
3060 StoreMapNoWriteBarrier(raw_result, RootIndex::kBigIntMap);
3061 return UncheckedCast<BigInt>(raw_result);
3064 void CodeStubAssembler::StoreBigIntBitfield(TNode<BigInt> bigint,
3065 TNode<WordT> bitfield) {
3066 StoreObjectFieldNoWriteBarrier(bigint, BigInt::kBitfieldOffset, bitfield,
3067 MachineType::PointerRepresentation());
3070 void CodeStubAssembler::StoreBigIntDigit(TNode<BigInt> bigint,
int digit_index,
3071 TNode<UintPtrT> digit) {
3072 StoreObjectFieldNoWriteBarrier(
3073 bigint, BigInt::kDigitsOffset + digit_index * kPointerSize, digit,
3074 UintPtrT::kMachineRepresentation);
3077 TNode<WordT> CodeStubAssembler::LoadBigIntBitfield(TNode<BigInt> bigint) {
3078 return UncheckedCast<WordT>(
3079 LoadObjectField(bigint, BigInt::kBitfieldOffset, MachineType::UintPtr()));
3082 TNode<UintPtrT> CodeStubAssembler::LoadBigIntDigit(TNode<BigInt> bigint,
3084 return UncheckedCast<UintPtrT>(LoadObjectField(
3085 bigint, BigInt::kDigitsOffset + digit_index * kPointerSize,
3086 MachineType::UintPtr()));
3089 TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
3090 uint32_t length, AllocationFlags flags) {
3091 Comment(
"AllocateSeqOneByteString");
3093 return CAST(LoadRoot(RootIndex::kempty_string));
3095 Node* result = Allocate(SeqOneByteString::SizeFor(length), flags);
3096 DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kOneByteStringMap));
3097 StoreMapNoWriteBarrier(result, RootIndex::kOneByteStringMap);
3098 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
3099 Uint32Constant(length),
3100 MachineRepresentation::kWord32);
3101 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset,
3102 Int32Constant(String::kEmptyHashField),
3103 MachineRepresentation::kWord32);
3104 return CAST(result);
3107 TNode<BoolT> CodeStubAssembler::IsZeroOrContext(SloppyTNode<Object>
object) {
3108 return Select<BoolT>(WordEqual(
object, SmiConstant(0)),
3109 [=] {
return Int32TrueConstant(); },
3110 [=] {
return IsContext(CAST(
object)); });
3113 TNode<String> CodeStubAssembler::AllocateSeqOneByteString(
3114 Node* context, TNode<Uint32T> length, AllocationFlags flags) {
3115 Comment(
"AllocateSeqOneByteString");
3116 CSA_SLOW_ASSERT(
this, IsZeroOrContext(context));
3117 VARIABLE(var_result, MachineRepresentation::kTagged);
3120 Label if_lengthiszero(
this), if_sizeissmall(
this),
3121 if_notsizeissmall(
this, Label::kDeferred), if_join(
this);
3122 GotoIf(Word32Equal(length, Uint32Constant(0)), &if_lengthiszero);
3124 Node* raw_size = GetArrayAllocationSize(
3125 Signed(ChangeUint32ToWord(length)), UINT8_ELEMENTS, INTPTR_PARAMETERS,
3126 SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
3127 TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
3128 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)),
3129 &if_sizeissmall, &if_notsizeissmall);
3131 BIND(&if_sizeissmall);
3134 TNode<Object> result =
3135 AllocateInNewSpace(UncheckedCast<IntPtrT>(size), flags);
3136 DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kOneByteStringMap));
3137 StoreMapNoWriteBarrier(result, RootIndex::kOneByteStringMap);
3138 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset,
3139 length, MachineRepresentation::kWord32);
3140 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset,
3141 Int32Constant(String::kEmptyHashField),
3142 MachineRepresentation::kWord32);
3143 var_result.Bind(result);
3147 BIND(&if_notsizeissmall);
3150 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context,
3151 ChangeUint32ToTagged(length));
3152 var_result.Bind(result);
3156 BIND(&if_lengthiszero);
3158 var_result.Bind(LoadRoot(RootIndex::kempty_string));
3163 return CAST(var_result.value());
3166 TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
3167 uint32_t length, AllocationFlags flags) {
3168 Comment(
"AllocateSeqTwoByteString");
3170 return CAST(LoadRoot(RootIndex::kempty_string));
3172 Node* result = Allocate(SeqTwoByteString::SizeFor(length), flags);
3173 DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kStringMap));
3174 StoreMapNoWriteBarrier(result, RootIndex::kStringMap);
3175 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
3176 Uint32Constant(length),
3177 MachineRepresentation::kWord32);
3178 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset,
3179 Int32Constant(String::kEmptyHashField),
3180 MachineRepresentation::kWord32);
3181 return CAST(result);
3184 TNode<String> CodeStubAssembler::AllocateSeqTwoByteString(
3185 Node* context, TNode<Uint32T> length, AllocationFlags flags) {
3186 CSA_SLOW_ASSERT(
this, IsZeroOrContext(context));
3187 Comment(
"AllocateSeqTwoByteString");
3188 VARIABLE(var_result, MachineRepresentation::kTagged);
3191 Label if_lengthiszero(
this), if_sizeissmall(
this),
3192 if_notsizeissmall(
this, Label::kDeferred), if_join(
this);
3193 GotoIf(Word32Equal(length, Uint32Constant(0)), &if_lengthiszero);
3195 Node* raw_size = GetArrayAllocationSize(
3196 Signed(ChangeUint32ToWord(length)), UINT16_ELEMENTS, INTPTR_PARAMETERS,
3197 SeqOneByteString::kHeaderSize + kObjectAlignmentMask);
3198 TNode<WordT> size = WordAnd(raw_size, IntPtrConstant(~kObjectAlignmentMask));
3199 Branch(IntPtrLessThanOrEqual(size, IntPtrConstant(kMaxRegularHeapObjectSize)),
3200 &if_sizeissmall, &if_notsizeissmall);
3202 BIND(&if_sizeissmall);
3205 TNode<Object> result =
3206 AllocateInNewSpace(UncheckedCast<IntPtrT>(size), flags);
3207 DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kStringMap));
3208 StoreMapNoWriteBarrier(result, RootIndex::kStringMap);
3209 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset,
3210 length, MachineRepresentation::kWord32);
3211 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset,
3212 Int32Constant(String::kEmptyHashField),
3213 MachineRepresentation::kWord32);
3214 var_result.Bind(result);
3218 BIND(&if_notsizeissmall);
3221 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context,
3222 ChangeUint32ToTagged(length));
3223 var_result.Bind(result);
3227 BIND(&if_lengthiszero);
3229 var_result.Bind(LoadRoot(RootIndex::kempty_string));
3234 return CAST(var_result.value());
3237 TNode<String> CodeStubAssembler::AllocateSlicedString(RootIndex map_root_index,
3238 TNode<Uint32T> length,
3239 TNode<String> parent,
3240 TNode<Smi> offset) {
3241 DCHECK(map_root_index == RootIndex::kSlicedOneByteStringMap ||
3242 map_root_index == RootIndex::kSlicedStringMap);
3243 Node* result = Allocate(SlicedString::kSize);
3244 DCHECK(RootsTable::IsImmortalImmovable(map_root_index));
3245 StoreMapNoWriteBarrier(result, map_root_index);
3246 StoreObjectFieldNoWriteBarrier(result, SlicedString::kHashFieldOffset,
3247 Int32Constant(String::kEmptyHashField),
3248 MachineRepresentation::kWord32);
3249 StoreObjectFieldNoWriteBarrier(result, SlicedString::kLengthOffset, length,
3250 MachineRepresentation::kWord32);
3251 StoreObjectFieldNoWriteBarrier(result, SlicedString::kParentOffset, parent,
3252 MachineRepresentation::kTagged);
3253 StoreObjectFieldNoWriteBarrier(result, SlicedString::kOffsetOffset, offset,
3254 MachineRepresentation::kTagged);
3255 return CAST(result);
3258 TNode<String> CodeStubAssembler::AllocateSlicedOneByteString(
3259 TNode<Uint32T> length, TNode<String> parent, TNode<Smi> offset) {
3260 return AllocateSlicedString(RootIndex::kSlicedOneByteStringMap, length,
3264 TNode<String> CodeStubAssembler::AllocateSlicedTwoByteString(
3265 TNode<Uint32T> length, TNode<String> parent, TNode<Smi> offset) {
3266 return AllocateSlicedString(RootIndex::kSlicedStringMap, length, parent,
3270 TNode<String> CodeStubAssembler::AllocateConsString(RootIndex map_root_index,
3271 TNode<Uint32T> length,
3272 TNode<String> first,
3273 TNode<String> second,
3274 AllocationFlags flags) {
3275 DCHECK(map_root_index == RootIndex::kConsOneByteStringMap ||
3276 map_root_index == RootIndex::kConsStringMap);
3277 Node* result = Allocate(ConsString::kSize, flags);
3278 DCHECK(RootsTable::IsImmortalImmovable(map_root_index));
3279 StoreMapNoWriteBarrier(result, map_root_index);
3280 StoreObjectFieldNoWriteBarrier(result, ConsString::kLengthOffset, length,
3281 MachineRepresentation::kWord32);
3282 StoreObjectFieldNoWriteBarrier(result, ConsString::kHashFieldOffset,
3283 Int32Constant(String::kEmptyHashField),
3284 MachineRepresentation::kWord32);
3285 bool const new_space = !(flags & kPretenured);
3287 StoreObjectFieldNoWriteBarrier(result, ConsString::kFirstOffset, first,
3288 MachineRepresentation::kTagged);
3289 StoreObjectFieldNoWriteBarrier(result, ConsString::kSecondOffset, second,
3290 MachineRepresentation::kTagged);
3292 StoreObjectField(result, ConsString::kFirstOffset, first);
3293 StoreObjectField(result, ConsString::kSecondOffset, second);
3295 return CAST(result);
3298 TNode<String> CodeStubAssembler::AllocateOneByteConsString(
3299 TNode<Uint32T> length, TNode<String> first, TNode<String> second,
3300 AllocationFlags flags) {
3301 return AllocateConsString(RootIndex::kConsOneByteStringMap, length, first,
3305 TNode<String> CodeStubAssembler::AllocateTwoByteConsString(
3306 TNode<Uint32T> length, TNode<String> first, TNode<String> second,
3307 AllocationFlags flags) {
3308 return AllocateConsString(RootIndex::kConsStringMap, length, first, second,
3312 TNode<String> CodeStubAssembler::NewConsString(TNode<Uint32T> length,
3314 TNode<String> right,
3315 AllocationFlags flags) {
3317 Comment(
"Allocating ConsString");
3318 Node* left_instance_type = LoadInstanceType(left);
3319 Node* right_instance_type = LoadInstanceType(right);
3322 Node* anded_instance_types =
3323 Word32And(left_instance_type, right_instance_type);
3324 Node* xored_instance_types =
3325 Word32Xor(left_instance_type, right_instance_type);
3336 STATIC_ASSERT(kOneByteStringTag != 0);
3337 STATIC_ASSERT(kOneByteDataHintTag != 0);
3338 Label one_byte_map(
this);
3339 Label two_byte_map(
this);
3340 TVARIABLE(String, result);
3341 Label done(
this, &result);
3342 GotoIf(IsSetWord32(anded_instance_types,
3343 kStringEncodingMask | kOneByteDataHintTag),
3345 Branch(Word32NotEqual(Word32And(xored_instance_types,
3346 Int32Constant(kStringEncodingMask |
3347 kOneByteDataHintMask)),
3348 Int32Constant(kOneByteStringTag | kOneByteDataHintTag)),
3349 &two_byte_map, &one_byte_map);
3351 BIND(&one_byte_map);
3352 Comment(
"One-byte ConsString");
3353 result = AllocateOneByteConsString(length, left, right, flags);
3356 BIND(&two_byte_map);
3357 Comment(
"Two-byte ConsString");
3358 result = AllocateTwoByteConsString(length, left, right, flags);
3363 return result.value();
3366 TNode<NameDictionary> CodeStubAssembler::AllocateNameDictionary(
3367 int at_least_space_for) {
3368 return AllocateNameDictionary(IntPtrConstant(at_least_space_for));
3371 TNode<NameDictionary> CodeStubAssembler::AllocateNameDictionary(
3372 TNode<IntPtrT> at_least_space_for) {
3373 CSA_ASSERT(
this, UintPtrLessThanOrEqual(
3375 IntPtrConstant(NameDictionary::kMaxCapacity)));
3376 TNode<IntPtrT> capacity = HashTableComputeCapacity(at_least_space_for);
3377 return AllocateNameDictionaryWithCapacity(capacity);
3380 TNode<NameDictionary> CodeStubAssembler::AllocateNameDictionaryWithCapacity(
3381 TNode<IntPtrT> capacity) {
3382 CSA_ASSERT(
this, WordIsPowerOfTwo(capacity));
3383 CSA_ASSERT(
this, IntPtrGreaterThan(capacity, IntPtrConstant(0)));
3384 TNode<IntPtrT> length = EntryToIndex<NameDictionary>(capacity);
3385 TNode<IntPtrT> store_size = IntPtrAdd(
3386 TimesPointerSize(length), IntPtrConstant(NameDictionary::kHeaderSize));
3388 TNode<NameDictionary> result =
3389 UncheckedCast<NameDictionary>(AllocateInNewSpace(store_size));
3390 Comment(
"Initialize NameDictionary");
3392 DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kNameDictionaryMap));
3393 StoreMapNoWriteBarrier(result, RootIndex::kNameDictionaryMap);
3394 StoreObjectFieldNoWriteBarrier(result, FixedArray::kLengthOffset,
3395 SmiFromIntPtr(length));
3397 TNode<Smi> zero = SmiConstant(0);
3398 StoreFixedArrayElement(result, NameDictionary::kNumberOfElementsIndex, zero,
3399 SKIP_WRITE_BARRIER);
3400 StoreFixedArrayElement(result, NameDictionary::kNumberOfDeletedElementsIndex,
3401 zero, SKIP_WRITE_BARRIER);
3402 StoreFixedArrayElement(result, NameDictionary::kCapacityIndex,
3403 SmiTag(capacity), SKIP_WRITE_BARRIER);
3405 TNode<HeapObject> filler = UndefinedConstant();
3406 StoreFixedArrayElement(result, NameDictionary::kNextEnumerationIndexIndex,
3407 SmiConstant(PropertyDetails::kInitialIndex),
3408 SKIP_WRITE_BARRIER);
3409 StoreFixedArrayElement(result, NameDictionary::kObjectHashIndex,
3410 SmiConstant(PropertyArray::kNoHashSentinel),
3411 SKIP_WRITE_BARRIER);
3414 TNode<WordT> result_word = BitcastTaggedToWord(result);
3415 TNode<WordT> start_address = IntPtrAdd(
3416 result_word, IntPtrConstant(NameDictionary::OffsetOfElementAt(
3417 NameDictionary::kElementsStartIndex) -
3419 TNode<WordT> end_address = IntPtrAdd(
3420 result_word, IntPtrSub(store_size, IntPtrConstant(kHeapObjectTag)));
3421 StoreFieldsNoWriteBarrier(start_address, end_address, filler);
3425 TNode<NameDictionary> CodeStubAssembler::CopyNameDictionary(
3426 TNode<NameDictionary> dictionary, Label* large_object_fallback) {
3427 Comment(
"Copy boilerplate property dict");
3428 TNode<IntPtrT> capacity = SmiUntag(GetCapacity<NameDictionary>(dictionary));
3429 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(capacity, IntPtrConstant(0)));
3430 GotoIf(UintPtrGreaterThan(
3431 capacity, IntPtrConstant(NameDictionary::kMaxRegularCapacity)),
3432 large_object_fallback);
3433 TNode<NameDictionary> properties =
3434 AllocateNameDictionaryWithCapacity(capacity);
3435 TNode<IntPtrT> length = SmiUntag(LoadFixedArrayBaseLength(dictionary));
3436 CopyFixedArrayElements(PACKED_ELEMENTS, dictionary, properties, length,
3437 SKIP_WRITE_BARRIER, INTPTR_PARAMETERS);
3441 template <
typename CollectionType>
3442 Node* CodeStubAssembler::AllocateOrderedHashTable() {
3443 static const int kCapacity = CollectionType::kMinCapacity;
3444 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor;
3445 static const int kDataTableLength = kCapacity * CollectionType::kEntrySize;
3446 static const int kFixedArrayLength =
3447 CollectionType::kHashTableStartIndex + kBucketCount + kDataTableLength;
3448 static const int kDataTableStartIndex =
3449 CollectionType::kHashTableStartIndex + kBucketCount;
3451 STATIC_ASSERT(base::bits::IsPowerOfTwo(kCapacity));
3452 STATIC_ASSERT(kCapacity <= CollectionType::kMaxCapacity);
3455 const ElementsKind elements_kind = HOLEY_ELEMENTS;
3456 TNode<IntPtrT> length_intptr = IntPtrConstant(kFixedArrayLength);
3457 TNode<Map> fixed_array_map =
3458 CAST(LoadRoot(CollectionType::GetMapRootIndex()));
3459 TNode<FixedArray> table =
3460 CAST(AllocateFixedArray(elements_kind, length_intptr,
3461 kAllowLargeObjectAllocation, fixed_array_map));
3464 const WriteBarrierMode barrier_mode = SKIP_WRITE_BARRIER;
3465 StoreFixedArrayElement(table, CollectionType::kNumberOfElementsIndex,
3466 SmiConstant(0), barrier_mode);
3467 StoreFixedArrayElement(table, CollectionType::kNumberOfDeletedElementsIndex,
3468 SmiConstant(0), barrier_mode);
3469 StoreFixedArrayElement(table, CollectionType::kNumberOfBucketsIndex,
3470 SmiConstant(kBucketCount), barrier_mode);
3473 TNode<Smi> not_found = SmiConstant(CollectionType::kNotFound);
3474 STATIC_ASSERT(CollectionType::kHashTableStartIndex ==
3475 CollectionType::kNumberOfBucketsIndex + 1);
3476 STATIC_ASSERT((CollectionType::kHashTableStartIndex + kBucketCount) ==
3477 kDataTableStartIndex);
3478 for (
int i = 0;
i < kBucketCount;
i++) {
3479 StoreFixedArrayElement(table, CollectionType::kHashTableStartIndex +
i,
3480 not_found, barrier_mode);
3484 STATIC_ASSERT(kDataTableStartIndex + kDataTableLength == kFixedArrayLength);
3485 for (
int i = 0;
i < kDataTableLength;
i++) {
3486 StoreFixedArrayElement(table, kDataTableStartIndex +
i, UndefinedConstant(),
3493 template Node* CodeStubAssembler::AllocateOrderedHashTable<OrderedHashMap>();
3494 template Node* CodeStubAssembler::AllocateOrderedHashTable<OrderedHashSet>();
3496 template <
typename CollectionType>
3497 TNode<CollectionType> CodeStubAssembler::AllocateSmallOrderedHashTable(
3498 TNode<IntPtrT> capacity) {
3499 CSA_ASSERT(
this, WordIsPowerOfTwo(capacity));
3500 CSA_ASSERT(
this, IntPtrLessThan(
3501 capacity, IntPtrConstant(CollectionType::kMaxCapacity)));
3503 TNode<IntPtrT> data_table_start_offset =
3504 IntPtrConstant(CollectionType::kDataTableStartOffset);
3506 TNode<IntPtrT> data_table_size = IntPtrMul(
3507 capacity, IntPtrConstant(CollectionType::kEntrySize * kPointerSize));
3509 TNode<Int32T> hash_table_size =
3510 Int32Div(TruncateIntPtrToInt32(capacity),
3511 Int32Constant(CollectionType::kLoadFactor));
3513 TNode<IntPtrT> hash_table_start_offset =
3514 IntPtrAdd(data_table_start_offset, data_table_size);
3516 TNode<IntPtrT> hash_table_and_chain_table_size =
3517 IntPtrAdd(ChangeInt32ToIntPtr(hash_table_size), capacity);
3519 TNode<IntPtrT> total_size =
3520 IntPtrAdd(hash_table_start_offset, hash_table_and_chain_table_size);
3522 TNode<IntPtrT> total_size_word_aligned =
3523 IntPtrAdd(total_size, IntPtrConstant(kPointerSize - 1));
3524 total_size_word_aligned = ChangeInt32ToIntPtr(
3525 Int32Div(TruncateIntPtrToInt32(total_size_word_aligned),
3526 Int32Constant(kPointerSize)));
3527 total_size_word_aligned =
3528 UncheckedCast<IntPtrT>(TimesPointerSize(total_size_word_aligned));
3531 TNode<Map> small_ordered_hash_map =
3532 CAST(LoadRoot(CollectionType::GetMapRootIndex()));
3533 TNode<Object> table_obj = AllocateInNewSpace(total_size_word_aligned);
3534 StoreMapNoWriteBarrier(table_obj, small_ordered_hash_map);
3535 TNode<CollectionType> table = UncheckedCast<CollectionType>(table_obj);
3538 StoreObjectByteNoWriteBarrier(
3539 table, CollectionType::kNumberOfBucketsOffset,
3540 Word32And(Int32Constant(0xFF), hash_table_size));
3541 StoreObjectByteNoWriteBarrier(table, CollectionType::kNumberOfElementsOffset,
3543 StoreObjectByteNoWriteBarrier(
3544 table, CollectionType::kNumberOfDeletedElementsOffset, Int32Constant(0));
3546 TNode<IntPtrT> table_address =
3547 IntPtrSub(BitcastTaggedToWord(table), IntPtrConstant(kHeapObjectTag));
3548 TNode<IntPtrT> hash_table_start_address =
3549 IntPtrAdd(table_address, hash_table_start_offset);
3552 Node* memset = ExternalConstant(ExternalReference::libc_memset_function());
3553 CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
3554 MachineType::IntPtr(), MachineType::UintPtr(), memset,
3555 hash_table_start_address, IntPtrConstant(0xFF),
3556 hash_table_and_chain_table_size);
3559 TNode<HeapObject> filler = TheHoleConstant();
3560 TNode<WordT> data_table_start_address =
3561 IntPtrAdd(table_address, data_table_start_offset);
3562 TNode<WordT> data_table_end_address =
3563 IntPtrAdd(data_table_start_address, data_table_size);
3564 StoreFieldsNoWriteBarrier(data_table_start_address, data_table_end_address,
3570 template TNode<SmallOrderedHashMap>
3571 CodeStubAssembler::AllocateSmallOrderedHashTable<SmallOrderedHashMap>(
3572 TNode<IntPtrT> capacity);
3573 template TNode<SmallOrderedHashSet>
3574 CodeStubAssembler::AllocateSmallOrderedHashTable<SmallOrderedHashSet>(
3575 TNode<IntPtrT> capacity);
3577 template <
typename CollectionType>
3578 void CodeStubAssembler::FindOrderedHashTableEntry(
3579 Node* table, Node* hash,
3580 const std::function<
void(Node*, Label*, Label*)>& key_compare,
3581 Variable* entry_start_position, Label* entry_found, Label* not_found) {
3583 Node*
const number_of_buckets = SmiUntag(CAST(LoadFixedArrayElement(
3584 CAST(table), CollectionType::kNumberOfBucketsIndex)));
3585 Node*
const bucket =
3586 WordAnd(hash, IntPtrSub(number_of_buckets, IntPtrConstant(1)));
3587 Node*
const first_entry = SmiUntag(CAST(LoadFixedArrayElement(
3588 CAST(table), bucket,
3589 CollectionType::kHashTableStartIndex * kPointerSize)));
3593 Label if_key_found(
this);
3595 VARIABLE(var_entry, MachineType::PointerRepresentation(), first_entry);
3596 Label loop(
this, {&var_entry, entry_start_position}),
3597 continue_next_entry(
this);
3603 WordEqual(var_entry.value(), IntPtrConstant(CollectionType::kNotFound)),
3608 this, UintPtrLessThan(
3611 CAST(LoadFixedArrayElement(
3612 CAST(table), CollectionType::kNumberOfElementsIndex)),
3613 CAST(LoadFixedArrayElement(
3615 CollectionType::kNumberOfDeletedElementsIndex))))));
3619 IntPtrAdd(IntPtrMul(var_entry.value(),
3620 IntPtrConstant(CollectionType::kEntrySize)),
3624 Node*
const candidate_key = LoadFixedArrayElement(
3625 CAST(table), entry_start,
3626 CollectionType::kHashTableStartIndex * kPointerSize);
3628 key_compare(candidate_key, &if_key_found, &continue_next_entry);
3630 BIND(&continue_next_entry);
3632 var_entry.Bind(SmiUntag(CAST(LoadFixedArrayElement(
3633 CAST(table), entry_start,
3634 (CollectionType::kHashTableStartIndex + CollectionType::kChainOffset) *
3640 BIND(&if_key_found);
3641 entry_start_position->Bind(entry_start);
3645 template void CodeStubAssembler::FindOrderedHashTableEntry<OrderedHashMap>(
3646 Node* table, Node* hash,
3647 const std::function<void(Node*, Label*, Label*)>& key_compare,
3648 Variable* entry_start_position, Label* entry_found, Label* not_found);
3649 template void CodeStubAssembler::FindOrderedHashTableEntry<OrderedHashSet>(
3650 Node* table, Node* hash,
3651 const std::function<void(Node*, Label*, Label*)>& key_compare,
3652 Variable* entry_start_position, Label* entry_found, Label* not_found);
3654 Node* CodeStubAssembler::AllocateStruct(Node* map, AllocationFlags flags) {
3655 Comment(
"AllocateStruct");
3656 CSA_ASSERT(
this, IsMap(map));
3657 TNode<IntPtrT> size = TimesPointerSize(LoadMapInstanceSizeInWords(map));
3658 TNode<Object>
object = Allocate(size, flags);
3659 StoreMapNoWriteBarrier(
object, map);
3660 InitializeStructBody(
object, map, size, Struct::kHeaderSize);
3664 void CodeStubAssembler::InitializeStructBody(Node*
object, Node* map,
3665 Node* size,
int start_offset) {
3666 CSA_SLOW_ASSERT(
this, IsMap(map));
3667 Comment(
"InitializeStructBody");
3668 Node* filler = UndefinedConstant();
3670 object = BitcastTaggedToWord(
object);
3671 Node* start_address =
3672 IntPtrAdd(
object, IntPtrConstant(start_offset - kHeapObjectTag));
3674 IntPtrSub(IntPtrAdd(
object, size), IntPtrConstant(kHeapObjectTag));
3675 StoreFieldsNoWriteBarrier(start_address, end_address, filler);
3678 Node* CodeStubAssembler::AllocateJSObjectFromMap(
3679 Node* map, Node* properties, Node* elements, AllocationFlags flags,
3680 SlackTrackingMode slack_tracking_mode) {
3681 CSA_ASSERT(
this, IsMap(map));
3682 CSA_ASSERT(
this, Word32BinaryNot(IsJSFunctionMap(map)));
3683 CSA_ASSERT(
this, Word32BinaryNot(InstanceTypeEqual(LoadMapInstanceType(map),
3684 JS_GLOBAL_OBJECT_TYPE)));
3685 TNode<IntPtrT> instance_size =
3686 TimesPointerSize(LoadMapInstanceSizeInWords(map));
3687 TNode<Object>
object = AllocateInNewSpace(instance_size, flags);
3688 StoreMapNoWriteBarrier(
object, map);
3689 InitializeJSObjectFromMap(
object, map, instance_size, properties, elements,
3690 slack_tracking_mode);
3694 void CodeStubAssembler::InitializeJSObjectFromMap(
3695 Node*
object, Node* map, Node* instance_size, Node* properties,
3696 Node* elements, SlackTrackingMode slack_tracking_mode) {
3697 CSA_SLOW_ASSERT(
this, IsMap(map));
3700 if (properties ==
nullptr) {
3701 CSA_ASSERT(
this, Word32BinaryNot(IsDictionaryMap((map))));
3702 StoreObjectFieldRoot(
object, JSObject::kPropertiesOrHashOffset,
3703 RootIndex::kEmptyFixedArray);
3705 CSA_ASSERT(
this, Word32Or(Word32Or(IsPropertyArray(properties),
3706 IsNameDictionary(properties)),
3707 IsEmptyFixedArray(properties)));
3708 StoreObjectFieldNoWriteBarrier(
object, JSObject::kPropertiesOrHashOffset,
3711 if (elements ==
nullptr) {
3712 StoreObjectFieldRoot(
object, JSObject::kElementsOffset,
3713 RootIndex::kEmptyFixedArray);
3715 CSA_ASSERT(
this, IsFixedArray(elements));
3716 StoreObjectFieldNoWriteBarrier(
object, JSObject::kElementsOffset, elements);
3718 if (slack_tracking_mode == kNoSlackTracking) {
3719 InitializeJSObjectBodyNoSlackTracking(
object, map, instance_size);
3721 DCHECK_EQ(slack_tracking_mode, kWithSlackTracking);
3722 InitializeJSObjectBodyWithSlackTracking(
object, map, instance_size);
3726 void CodeStubAssembler::InitializeJSObjectBodyNoSlackTracking(
3727 Node*
object, Node* map, Node* instance_size,
int start_offset) {
3728 STATIC_ASSERT(Map::kNoSlackTracking == 0);
3730 this, IsClearWord32<Map::ConstructionCounterBits>(LoadMapBitField3(map)));
3731 InitializeFieldsWithRoot(
object, IntPtrConstant(start_offset), instance_size,
3732 RootIndex::kUndefinedValue);
3735 void CodeStubAssembler::InitializeJSObjectBodyWithSlackTracking(
3736 Node*
object, Node* map, Node* instance_size) {
3737 CSA_SLOW_ASSERT(
this, IsMap(map));
3738 Comment(
"InitializeJSObjectBodyNoSlackTracking");
3741 int start_offset = JSObject::kHeaderSize;
3742 Node* bit_field3 = LoadMapBitField3(map);
3743 Label end(
this), slack_tracking(
this), complete(
this, Label::kDeferred);
3744 STATIC_ASSERT(Map::kNoSlackTracking == 0);
3745 GotoIf(IsSetWord32<Map::ConstructionCounterBits>(bit_field3),
3747 Comment(
"No slack tracking");
3748 InitializeJSObjectBodyNoSlackTracking(
object, map, instance_size);
3751 BIND(&slack_tracking);
3753 Comment(
"Decrease construction counter");
3755 CSA_ASSERT(
this, IsUndefined(LoadMapBackPointer(map)));
3756 STATIC_ASSERT(Map::ConstructionCounterBits::kNext == 32);
3757 Node* new_bit_field3 = Int32Sub(
3758 bit_field3, Int32Constant(1 << Map::ConstructionCounterBits::kShift));
3759 StoreObjectFieldNoWriteBarrier(map, Map::kBitField3Offset, new_bit_field3,
3760 MachineRepresentation::kWord32);
3761 STATIC_ASSERT(Map::kSlackTrackingCounterEnd == 1);
3765 Node* used_size = TimesPointerSize(ChangeUint32ToWord(
3766 LoadObjectField(map, Map::kUsedOrUnusedInstanceSizeInWordsOffset,
3767 MachineType::Uint8())));
3769 Comment(
"iInitialize filler fields");
3770 InitializeFieldsWithRoot(
object, used_size, instance_size,
3771 RootIndex::kOnePointerFillerMap);
3773 Comment(
"Initialize undefined fields");
3774 InitializeFieldsWithRoot(
object, IntPtrConstant(start_offset), used_size,
3775 RootIndex::kUndefinedValue);
3777 STATIC_ASSERT(Map::kNoSlackTracking == 0);
3778 GotoIf(IsClearWord32<Map::ConstructionCounterBits>(new_bit_field3),
3788 CallRuntime(Runtime::kCompleteInobjectSlackTrackingForMap,
3789 NoContextConstant(), map);
3796 void CodeStubAssembler::StoreFieldsNoWriteBarrier(Node* start_address,
3799 Comment(
"StoreFieldsNoWriteBarrier");
3800 CSA_ASSERT(
this, WordIsWordAligned(start_address));
3801 CSA_ASSERT(
this, WordIsWordAligned(end_address));
3802 BuildFastLoop(start_address, end_address,
3803 [
this, value](Node* current) {
3804 StoreNoWriteBarrier(MachineRepresentation::kTagged, current,
3807 kPointerSize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
3810 TNode<BoolT> CodeStubAssembler::IsValidFastJSArrayCapacity(
3811 Node* capacity, ParameterMode capacity_mode) {
3812 return UncheckedCast<BoolT>(
3813 UintPtrLessThanOrEqual(ParameterToIntPtr(capacity, capacity_mode),
3814 IntPtrConstant(JSArray::kMaxFastArrayLength)));
3817 TNode<JSArray> CodeStubAssembler::AllocateUninitializedJSArrayWithoutElements(
3818 TNode<Map> array_map, TNode<Smi> length, Node* allocation_site) {
3819 Comment(
"begin allocation of JSArray without elements");
3820 CSA_SLOW_ASSERT(
this, TaggedIsPositiveSmi(length));
3822 int base_size = JSArray::kSize;
3823 if (allocation_site !=
nullptr) {
3824 base_size += AllocationMemento::kSize;
3827 TNode<IntPtrT> size = IntPtrConstant(base_size);
3828 return AllocateUninitializedJSArray(array_map, length, allocation_site, size);
3831 std::pair<TNode<JSArray>, TNode<FixedArrayBase>>
3832 CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
3833 ElementsKind kind, TNode<Map> array_map, TNode<Smi> length,
3834 Node* allocation_site, Node* capacity, ParameterMode capacity_mode,
3835 AllocationFlags allocation_flags) {
3836 Comment(
"begin allocation of JSArray with elements");
3837 CHECK_EQ(allocation_flags & ~kAllowLargeObjectAllocation, 0);
3838 CSA_SLOW_ASSERT(
this, TaggedIsPositiveSmi(length));
3840 int base_size = JSArray::kSize;
3841 if (allocation_site !=
nullptr) base_size += AllocationMemento::kSize;
3843 const int elements_offset = base_size;
3846 base_size += FixedArray::kHeaderSize;
3847 TNode<IntPtrT> size =
3848 ElementOffsetFromIndex(capacity, kind, capacity_mode, base_size);
3850 TVARIABLE(JSArray, array);
3851 TVARIABLE(FixedArrayBase, elements);
3860 if (allocation_flags & kAllowLargeObjectAllocation) {
3862 GotoIf(IsRegularHeapObjectSize(size), &next);
3864 CSA_CHECK(
this, IsValidFastJSArrayCapacity(capacity, capacity_mode));
3869 AllocateFixedArray(kind, capacity, capacity_mode, allocation_flags);
3871 if (IsDoubleElementsKind(kind)) {
3872 FillFixedDoubleArrayWithZero(CAST(elements.value()),
3873 ParameterToIntPtr(capacity, capacity_mode));
3875 FillFixedArrayWithSmiZero(CAST(elements.value()),
3876 ParameterToIntPtr(capacity, capacity_mode));
3882 array = AllocateUninitializedJSArrayWithoutElements(array_map, length,
3884 StoreObjectFieldNoWriteBarrier(array.value(), JSObject::kElementsOffset,
3894 AllocateUninitializedJSArray(array_map, length, allocation_site, size);
3895 elements = UncheckedCast<FixedArrayBase>(
3896 InnerAllocate(array.value(), elements_offset));
3898 StoreObjectFieldNoWriteBarrier(array.value(), JSObject::kElementsOffset,
3902 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
3903 RootIndex elements_map_index = IsDoubleElementsKind(kind)
3904 ? RootIndex::kFixedDoubleArrayMap
3905 : RootIndex::kFixedArrayMap;
3906 DCHECK(RootsTable::IsImmortalImmovable(elements_map_index));
3907 StoreMapNoWriteBarrier(elements.value(), elements_map_index);
3909 TNode<Smi> capacity_smi = ParameterToTagged(capacity, capacity_mode);
3910 CSA_ASSERT(
this, SmiGreaterThan(capacity_smi, SmiConstant(0)));
3911 StoreObjectFieldNoWriteBarrier(elements.value(), FixedArray::kLengthOffset,
3916 return {array.value(), elements.value()};
3919 TNode<JSArray> CodeStubAssembler::AllocateUninitializedJSArray(
3920 TNode<Map> array_map, TNode<Smi> length, Node* allocation_site,
3921 TNode<IntPtrT> size_in_bytes) {
3922 CSA_SLOW_ASSERT(
this, TaggedIsPositiveSmi(length));
3925 TNode<Object> array = AllocateInNewSpace(size_in_bytes);
3927 StoreMapNoWriteBarrier(array, array_map);
3928 StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
3929 StoreObjectFieldRoot(array, JSArray::kPropertiesOrHashOffset,
3930 RootIndex::kEmptyFixedArray);
3932 if (allocation_site !=
nullptr) {
3933 InitializeAllocationMemento(array, IntPtrConstant(JSArray::kSize),
3940 TNode<JSArray> CodeStubAssembler::AllocateJSArray(
3941 ElementsKind kind, TNode<Map> array_map, Node* capacity, TNode<Smi> length,
3942 Node* allocation_site, ParameterMode capacity_mode,
3943 AllocationFlags allocation_flags) {
3944 CSA_SLOW_ASSERT(
this, TaggedIsPositiveSmi(length));
3945 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity, capacity_mode));
3947 TNode<JSArray> array;
3948 TNode<FixedArrayBase> elements;
3949 int capacity_as_constant;
3951 if (IsIntPtrOrSmiConstantZero(capacity, capacity_mode)) {
3954 array = AllocateUninitializedJSArrayWithoutElements(array_map, length,
3956 StoreObjectFieldRoot(array, JSArray::kElementsOffset,
3957 RootIndex::kEmptyFixedArray);
3958 }
else if (TryGetIntPtrOrSmiConstantValue(capacity, &capacity_as_constant,
3960 CHECK_GT(capacity_as_constant, 0);
3962 std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
3963 kind, array_map, length, allocation_site, capacity, capacity_mode,
3966 FillFixedArrayWithValue(kind, elements,
3967 IntPtrOrSmiConstant(0, capacity_mode), capacity,
3968 RootIndex::kTheHoleValue, capacity_mode);
3970 Label out(
this), empty(
this), nonempty(
this);
3971 TVARIABLE(JSArray, var_array);
3973 Branch(SmiEqual(ParameterToTagged(capacity, capacity_mode), SmiConstant(0)),
3980 var_array = AllocateUninitializedJSArrayWithoutElements(array_map, length,
3982 StoreObjectFieldRoot(var_array.value(), JSArray::kElementsOffset,
3983 RootIndex::kEmptyFixedArray);
3990 TNode<JSArray> array;
3991 std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
3992 kind, array_map, length, allocation_site, capacity, capacity_mode,
3996 FillFixedArrayWithValue(kind, elements,
3997 IntPtrOrSmiConstant(0, capacity_mode), capacity,
3998 RootIndex::kTheHoleValue, capacity_mode);
4003 array = var_array.value();
4009 Node* CodeStubAssembler::ExtractFastJSArray(Node* context, Node* array,
4010 Node* begin, Node* count,
4011 ParameterMode mode, Node* capacity,
4012 Node* allocation_site) {
4013 Node* original_array_map = LoadMap(array);
4014 Node* elements_kind = LoadMapElementsKind(original_array_map);
4017 Node* native_context = LoadNativeContext(context);
4018 TNode<Map> array_map = LoadJSArrayElementsMap(elements_kind, native_context);
4020 Node* new_elements = ExtractFixedArray(
4021 LoadElements(array), begin, count, capacity,
4022 ExtractFixedArrayFlag::kAllFixedArrays, mode,
nullptr, elements_kind);
4024 TNode<Object> result = AllocateUninitializedJSArrayWithoutElements(
4025 array_map, ParameterToTagged(count, mode), allocation_site);
4026 StoreObjectField(result, JSObject::kElementsOffset, new_elements);
4030 Node* CodeStubAssembler::CloneFastJSArray(Node* context, Node* array,
4032 Node* allocation_site,
4033 HoleConversionMode convert_holes) {
4037 CSA_ASSERT(
this, IsJSArray(array));
4039 Node* length = LoadJSArrayLength(array);
4040 Node* new_elements =
nullptr;
4041 VARIABLE(var_new_elements, MachineRepresentation::kTagged);
4042 TVARIABLE(Int32T, var_elements_kind, LoadMapElementsKind(LoadMap(array)));
4044 Label allocate_jsarray(
this), holey_extract(
this);
4046 bool need_conversion =
4047 convert_holes == HoleConversionMode::kConvertToUndefined;
4048 if (need_conversion) {
4050 GotoIf(IsHoleyFastElementsKind(var_elements_kind.value()), &holey_extract);
4055 ExtractFixedArray(LoadElements(array), IntPtrOrSmiConstant(0, mode),
4056 TaggedToParameter(length, mode),
nullptr,
4057 ExtractFixedArrayFlag::kAllFixedArraysDontCopyCOW, mode,
4058 nullptr, var_elements_kind.value());
4059 var_new_elements.Bind(new_elements);
4060 Goto(&allocate_jsarray);
4062 if (need_conversion) {
4063 BIND(&holey_extract);
4065 TVARIABLE(BoolT, var_holes_converted, Int32FalseConstant());
4072 new_elements = ExtractFixedArray(
4073 LoadElements(array), IntPtrOrSmiConstant(0, mode),
4074 TaggedToParameter(length, mode),
nullptr,
4075 ExtractFixedArrayFlag::kAllFixedArrays, mode, &var_holes_converted);
4076 var_new_elements.Bind(new_elements);
4078 GotoIfNot(var_holes_converted.value(), &allocate_jsarray);
4080 var_elements_kind = Int32Constant(PACKED_ELEMENTS);
4081 Goto(&allocate_jsarray);
4084 BIND(&allocate_jsarray);
4086 Node* native_context = LoadNativeContext(context);
4087 TNode<Map> array_map =
4088 LoadJSArrayElementsMap(var_elements_kind.value(), native_context);
4090 TNode<Object> result = AllocateUninitializedJSArrayWithoutElements(
4091 array_map, CAST(length), allocation_site);
4092 StoreObjectField(result, JSObject::kElementsOffset, var_new_elements.value());
4096 TNode<FixedArrayBase> CodeStubAssembler::AllocateFixedArray(
4097 ElementsKind kind, Node* capacity, ParameterMode mode,
4098 AllocationFlags flags, SloppyTNode<Map> fixed_array_map) {
4099 Comment(
"AllocateFixedArray");
4100 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity, mode));
4101 CSA_ASSERT(
this, IntPtrOrSmiGreaterThan(capacity,
4102 IntPtrOrSmiConstant(0, mode), mode));
4103 TNode<IntPtrT> total_size = GetFixedArrayAllocationSize(capacity, kind, mode);
4105 if (IsDoubleElementsKind(kind)) flags |= kDoubleAlignment;
4107 Node* array = Allocate(total_size, flags);
4108 if (fixed_array_map !=
nullptr) {
4115 if (flags == CodeStubAssembler::kNone) {
4116 StoreMapNoWriteBarrier(array, fixed_array_map);
4118 StoreMap(array, fixed_array_map);
4121 RootIndex map_index = IsDoubleElementsKind(kind)
4122 ? RootIndex::kFixedDoubleArrayMap
4123 : RootIndex::kFixedArrayMap;
4124 DCHECK(RootsTable::IsImmortalImmovable(map_index));
4125 StoreMapNoWriteBarrier(array, map_index);
4127 StoreObjectFieldNoWriteBarrier(array, FixedArray::kLengthOffset,
4128 ParameterToTagged(capacity, mode));
4129 return UncheckedCast<FixedArray>(array);
4132 TNode<FixedArray> CodeStubAssembler::ExtractToFixedArray(
4133 Node* source, Node* first, Node* count, Node* capacity, Node* source_map,
4134 ElementsKind from_kind, AllocationFlags allocation_flags,
4135 ExtractFixedArrayFlags extract_flags, ParameterMode parameter_mode,
4136 HoleConversionMode convert_holes, TVariable<BoolT>* var_holes_converted,
4137 Node* source_elements_kind) {
4138 DCHECK_NE(first,
nullptr);
4139 DCHECK_NE(count,
nullptr);
4140 DCHECK_NE(capacity,
nullptr);
4141 DCHECK(extract_flags & ExtractFixedArrayFlag::kFixedArrays);
4143 WordNotEqual(IntPtrOrSmiConstant(0, parameter_mode), capacity));
4144 CSA_ASSERT(
this, WordEqual(source_map, LoadMap(source)));
4146 VARIABLE(var_result, MachineRepresentation::kTagged);
4147 VARIABLE(var_target_map, MachineRepresentation::kTagged, source_map);
4149 Label done(
this, {&var_result}), is_cow(
this),
4150 new_space_check(
this, {&var_target_map});
4155 if (IsDoubleElementsKind(from_kind)) {
4156 CSA_ASSERT(
this, IsFixedDoubleArrayMap(source_map));
4157 var_target_map.Bind(LoadRoot(RootIndex::kFixedArrayMap));
4158 Goto(&new_space_check);
4160 CSA_ASSERT(
this, Word32BinaryNot(IsFixedDoubleArrayMap(source_map)));
4161 Branch(WordEqual(var_target_map.value(),
4162 LoadRoot(RootIndex::kFixedCOWArrayMap)),
4163 &is_cow, &new_space_check);
4171 if (extract_flags & ExtractFixedArrayFlag::kDontCopyCOW) {
4172 Branch(WordNotEqual(IntPtrOrSmiConstant(0, parameter_mode), first),
4173 &new_space_check, [&] {
4174 var_result.Bind(source);
4178 var_target_map.Bind(LoadRoot(RootIndex::kFixedArrayMap));
4179 Goto(&new_space_check);
4184 BIND(&new_space_check);
4186 bool handle_old_space =
true;
4187 if (extract_flags & ExtractFixedArrayFlag::kNewSpaceAllocationOnly) {
4188 handle_old_space =
false;
4189 CSA_ASSERT(
this, Word32BinaryNot(FixedArraySizeDoesntFitInNewSpace(
4190 count, FixedArray::kHeaderSize, parameter_mode)));
4194 !TryGetIntPtrOrSmiConstantValue(count, &constant_count,
4197 FixedArray::GetMaxLengthForNewSpaceAllocation(PACKED_ELEMENTS));
4200 Label old_space(
this, Label::kDeferred);
4201 if (handle_old_space) {
4202 GotoIfFixedArraySizeDoesntFitInNewSpace(
4203 capacity, &old_space, FixedArray::kHeaderSize, parameter_mode);
4206 Comment(
"Copy FixedArray new space");
4209 const ElementsKind to_kind = PACKED_ELEMENTS;
4210 TNode<FixedArrayBase> to_elements =
4211 AllocateFixedArray(to_kind, capacity, parameter_mode,
4212 AllocationFlag::kNone, var_target_map.value());
4213 var_result.Bind(to_elements);
4215 if (convert_holes == HoleConversionMode::kDontConvert &&
4216 !IsDoubleElementsKind(from_kind)) {
4220 FillFixedArrayWithValue(to_kind, to_elements, count, capacity,
4221 RootIndex::kTheHoleValue, parameter_mode);
4222 CopyElements(to_kind, to_elements, IntPtrConstant(0), CAST(source),
4223 ParameterToIntPtr(first, parameter_mode),
4224 ParameterToIntPtr(count, parameter_mode),
4225 SKIP_WRITE_BARRIER);
4227 CopyFixedArrayElements(from_kind, source, to_kind, to_elements, first,
4228 count, capacity, SKIP_WRITE_BARRIER,
4229 parameter_mode, convert_holes,
4230 var_holes_converted);
4234 if (handle_old_space) {
4237 Comment(
"Copy FixedArray old space");
4238 Label copy_one_by_one(
this);
4241 if (convert_holes == HoleConversionMode::kDontConvert &&
4242 source_elements_kind !=
nullptr) {
4244 GotoIfNot(IsFastSmiElementsKind(source_elements_kind),
4247 const ElementsKind to_smi_kind = PACKED_SMI_ELEMENTS;
4249 AllocateFixedArray(to_smi_kind, capacity, parameter_mode,
4250 allocation_flags, var_target_map.value());
4251 var_result.Bind(to_elements);
4253 FillFixedArrayWithValue(to_smi_kind, to_elements, count, capacity,
4254 RootIndex::kTheHoleValue, parameter_mode);
4258 CopyElements(to_smi_kind, to_elements, IntPtrConstant(0),
4259 CAST(source), ParameterToIntPtr(first, parameter_mode),
4260 ParameterToIntPtr(count, parameter_mode),
4261 SKIP_WRITE_BARRIER);
4264 Goto(©_one_by_one);
4267 BIND(©_one_by_one);
4270 AllocateFixedArray(to_kind, capacity, parameter_mode,
4271 allocation_flags, var_target_map.value());
4272 var_result.Bind(to_elements);
4273 CopyFixedArrayElements(from_kind, source, to_kind, to_elements, first,
4274 count, capacity, UPDATE_WRITE_BARRIER,
4275 parameter_mode, convert_holes,
4276 var_holes_converted);
4284 return UncheckedCast<FixedArray>(var_result.value());
4287 TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedDoubleArrayFillingHoles(
4288 Node* from_array, Node* first, Node* count, Node* capacity,
4289 Node* fixed_array_map, TVariable<BoolT>* var_holes_converted,
4290 AllocationFlags allocation_flags, ExtractFixedArrayFlags extract_flags,
4291 ParameterMode mode) {
4292 DCHECK_NE(first,
nullptr);
4293 DCHECK_NE(count,
nullptr);
4294 DCHECK_NE(capacity,
nullptr);
4295 DCHECK_NE(var_holes_converted,
nullptr);
4296 CSA_ASSERT(
this, IsFixedDoubleArrayMap(fixed_array_map));
4298 VARIABLE(var_result, MachineRepresentation::kTagged);
4299 const ElementsKind kind = PACKED_DOUBLE_ELEMENTS;
4300 Node* to_elements = AllocateFixedArray(kind, capacity, mode, allocation_flags,
4302 var_result.Bind(to_elements);
4305 *var_holes_converted = Int32FalseConstant();
4309 CSA_SLOW_ASSERT(
this, MatchesParameterMode(count, mode));
4310 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity, mode));
4311 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKindOrEmpty(from_array, kind));
4312 STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
4314 Comment(
"[ ExtractFixedDoubleArrayFillingHoles");
4317 FillFixedArrayWithValue(kind, to_elements, IntPtrOrSmiConstant(0, mode),
4318 capacity, RootIndex::kTheHoleValue, mode);
4320 const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
4321 Node* first_from_element_offset =
4322 ElementOffsetFromIndex(first, kind, mode, 0);
4323 Node* limit_offset = IntPtrAdd(first_from_element_offset,
4324 IntPtrConstant(first_element_offset));
4325 VARIABLE(var_from_offset, MachineType::PointerRepresentation(),
4326 ElementOffsetFromIndex(IntPtrOrSmiAdd(first, count, mode), kind,
4327 mode, first_element_offset));
4329 Label decrement(
this, {&var_from_offset}), done(
this);
4330 Node* to_array_adjusted =
4331 IntPtrSub(BitcastTaggedToWord(to_elements), first_from_element_offset);
4333 Branch(WordEqual(var_from_offset.value(), limit_offset), &done, &decrement);
4338 IntPtrSub(var_from_offset.value(), IntPtrConstant(kDoubleSize));
4339 var_from_offset.Bind(from_offset);
4341 Node* to_offset = from_offset;
4343 Label if_hole(
this);
4345 Node* value = LoadElementAndPrepareForStore(
4346 from_array, var_from_offset.value(), kind, kind, &if_hole);
4348 StoreNoWriteBarrier(MachineRepresentation::kFloat64, to_array_adjusted,
4351 Node* compare = WordNotEqual(from_offset, limit_offset);
4352 Branch(compare, &decrement, &done);
4359 *var_holes_converted = Int32TrueConstant();
4361 ExtractToFixedArray(from_array, first, count, capacity, fixed_array_map,
4362 kind, allocation_flags, extract_flags, mode,
4363 HoleConversionMode::kConvertToUndefined);
4364 var_result.Bind(to_elements);
4369 Comment(
"] ExtractFixedDoubleArrayFillingHoles");
4370 return UncheckedCast<FixedArrayBase>(var_result.value());
4373 TNode<FixedArrayBase> CodeStubAssembler::ExtractFixedArray(
4374 Node* source, Node* first, Node* count, Node* capacity,
4375 ExtractFixedArrayFlags extract_flags, ParameterMode parameter_mode,
4376 TVariable<BoolT>* var_holes_converted, Node* source_runtime_kind) {
4377 DCHECK(extract_flags & ExtractFixedArrayFlag::kFixedArrays ||
4378 extract_flags & ExtractFixedArrayFlag::kFixedDoubleArrays);
4381 DCHECK_IMPLIES(var_holes_converted !=
nullptr,
4382 !(extract_flags & ExtractFixedArrayFlag::kDontCopyCOW));
4383 HoleConversionMode convert_holes =
4384 var_holes_converted !=
nullptr ? HoleConversionMode::kConvertToUndefined
4385 : HoleConversionMode::kDontConvert;
4386 VARIABLE(var_result, MachineRepresentation::kTagged);
4387 const AllocationFlags allocation_flags =
4388 (extract_flags & ExtractFixedArrayFlag::kNewSpaceAllocationOnly)
4389 ? CodeStubAssembler::kNone
4390 : CodeStubAssembler::kAllowLargeObjectAllocation;
4391 if (first ==
nullptr) {
4392 first = IntPtrOrSmiConstant(0, parameter_mode);
4394 if (count ==
nullptr) {
4395 count = IntPtrOrSmiSub(
4396 TaggedToParameter(LoadFixedArrayBaseLength(source), parameter_mode),
4397 first, parameter_mode);
4400 this, IntPtrOrSmiLessThanOrEqual(IntPtrOrSmiConstant(0, parameter_mode),
4401 count, parameter_mode));
4403 if (capacity ==
nullptr) {
4406 CSA_ASSERT(
this, Word32BinaryNot(IntPtrOrSmiGreaterThan(
4407 IntPtrOrSmiAdd(first, count, parameter_mode), capacity,
4411 Label if_fixed_double_array(
this), empty(
this), done(
this, {&var_result});
4412 Node* source_map = LoadMap(source);
4413 GotoIf(WordEqual(IntPtrOrSmiConstant(0, parameter_mode), capacity), &empty);
4415 if (extract_flags & ExtractFixedArrayFlag::kFixedDoubleArrays) {
4416 if (extract_flags & ExtractFixedArrayFlag::kFixedArrays) {
4417 GotoIf(IsFixedDoubleArrayMap(source_map), &if_fixed_double_array);
4419 CSA_ASSERT(
this, IsFixedDoubleArrayMap(source_map));
4423 if (extract_flags & ExtractFixedArrayFlag::kFixedArrays) {
4426 Node* to_elements = ExtractToFixedArray(
4427 source, first, count, capacity, source_map, PACKED_ELEMENTS,
4428 allocation_flags, extract_flags, parameter_mode, convert_holes,
4429 var_holes_converted, source_runtime_kind);
4430 var_result.Bind(to_elements);
4434 if (extract_flags & ExtractFixedArrayFlag::kFixedDoubleArrays) {
4435 BIND(&if_fixed_double_array);
4436 Comment(
"Copy FixedDoubleArray");
4438 if (convert_holes == HoleConversionMode::kConvertToUndefined) {
4439 Node* to_elements = ExtractFixedDoubleArrayFillingHoles(
4440 source, first, count, capacity, source_map, var_holes_converted,
4441 allocation_flags, extract_flags, parameter_mode);
4442 var_result.Bind(to_elements);
4447 ElementsKind kind = PACKED_DOUBLE_ELEMENTS;
4448 Node* to_elements = AllocateFixedArray(kind, capacity, parameter_mode,
4449 allocation_flags, source_map);
4450 var_result.Bind(to_elements);
4451 CopyFixedArrayElements(kind, source, kind, to_elements, first, count,
4452 capacity, SKIP_WRITE_BARRIER, parameter_mode);
4460 Comment(
"Copy empty array");
4462 var_result.Bind(EmptyFixedArrayConstant());
4467 return UncheckedCast<FixedArray>(var_result.value());
4470 void CodeStubAssembler::InitializePropertyArrayLength(Node* property_array,
4472 ParameterMode mode) {
4473 CSA_SLOW_ASSERT(
this, IsPropertyArray(property_array));
4475 this, IntPtrOrSmiGreaterThan(length, IntPtrOrSmiConstant(0, mode), mode));
4478 IntPtrOrSmiLessThanOrEqual(
4479 length, IntPtrOrSmiConstant(PropertyArray::LengthField::kMax, mode),
4481 StoreObjectFieldNoWriteBarrier(
4482 property_array, PropertyArray::kLengthAndHashOffset,
4483 ParameterToTagged(length, mode), MachineRepresentation::kTaggedSigned);
4486 Node* CodeStubAssembler::AllocatePropertyArray(Node* capacity_node,
4488 AllocationFlags flags) {
4489 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity_node, mode));
4490 CSA_ASSERT(
this, IntPtrOrSmiGreaterThan(capacity_node,
4491 IntPtrOrSmiConstant(0, mode), mode));
4492 TNode<IntPtrT> total_size =
4493 GetPropertyArrayAllocationSize(capacity_node, mode);
4495 TNode<Object> array = Allocate(total_size, flags);
4496 RootIndex map_index = RootIndex::kPropertyArrayMap;
4497 DCHECK(RootsTable::IsImmortalImmovable(map_index));
4498 StoreMapNoWriteBarrier(array, map_index);
4499 InitializePropertyArrayLength(array, capacity_node, mode);
4503 void CodeStubAssembler::FillPropertyArrayWithUndefined(Node* array,
4506 ParameterMode mode) {
4507 CSA_SLOW_ASSERT(
this, MatchesParameterMode(from_node, mode));
4508 CSA_SLOW_ASSERT(
this, MatchesParameterMode(to_node, mode));
4509 CSA_SLOW_ASSERT(
this, IsPropertyArray(array));
4510 ElementsKind kind = PACKED_ELEMENTS;
4511 Node* value = UndefinedConstant();
4512 BuildFastFixedArrayForEach(array, kind, from_node, to_node,
4513 [
this, value](Node* array, Node* offset) {
4514 StoreNoWriteBarrier(
4515 MachineRepresentation::kTagged, array,
4521 void CodeStubAssembler::FillFixedArrayWithValue(ElementsKind kind, Node* array,
4522 Node* from_node, Node* to_node,
4523 RootIndex value_root_index,
4524 ParameterMode mode) {
4525 CSA_SLOW_ASSERT(
this, MatchesParameterMode(from_node, mode));
4526 CSA_SLOW_ASSERT(
this, MatchesParameterMode(to_node, mode));
4527 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKind(array, kind));
4528 DCHECK(value_root_index == RootIndex::kTheHoleValue ||
4529 value_root_index == RootIndex::kUndefinedValue);
4533 Node* value = LoadRoot(value_root_index);
4534 if (IsDoubleElementsKind(kind)) {
4535 value = LoadHeapNumberValue(value);
4538 BuildFastFixedArrayForEach(
4539 array, kind, from_node, to_node,
4540 [
this, value, kind](Node* array, Node* offset) {
4541 if (IsDoubleElementsKind(kind)) {
4542 StoreNoWriteBarrier(MachineRepresentation::kFloat64, array, offset,
4545 StoreNoWriteBarrier(MachineRepresentation::kTagged, array, offset,
4552 void CodeStubAssembler::StoreFixedDoubleArrayHole(
4553 TNode<FixedDoubleArray> array, Node* index, ParameterMode parameter_mode) {
4554 CSA_SLOW_ASSERT(
this, MatchesParameterMode(index, parameter_mode));
4556 ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, parameter_mode,
4557 FixedArray::kHeaderSize - kHeapObjectTag);
4558 CSA_ASSERT(
this, IsOffsetInBounds(
4559 offset, LoadAndUntagFixedArrayBaseLength(array),
4560 FixedDoubleArray::kHeaderSize, PACKED_DOUBLE_ELEMENTS));
4562 Is64() ? ReinterpretCast<UintPtrT>(Int64Constant(kHoleNanInt64))
4563 : ReinterpretCast<UintPtrT>(Int32Constant(kHoleNanLower32));
4568 StoreNoWriteBarrier(MachineRepresentation::kWord64, array, offset,
4571 StoreNoWriteBarrier(MachineRepresentation::kWord32, array, offset,
4573 StoreNoWriteBarrier(MachineRepresentation::kWord32, array,
4574 IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
4579 void CodeStubAssembler::FillFixedArrayWithSmiZero(TNode<FixedArray> array,
4580 TNode<IntPtrT> length) {
4581 CSA_ASSERT(
this, WordEqual(length, LoadAndUntagFixedArrayBaseLength(array)));
4583 TNode<IntPtrT> byte_length = TimesPointerSize(length);
4584 CSA_ASSERT(
this, UintPtrLessThan(length, byte_length));
4586 static const int32_t fa_base_data_offset =
4587 FixedArray::kHeaderSize - kHeapObjectTag;
4588 TNode<IntPtrT> backing_store = IntPtrAdd(BitcastTaggedToWord(array),
4589 IntPtrConstant(fa_base_data_offset));
4592 TNode<ExternalReference> memset =
4593 ExternalConstant(ExternalReference::libc_memset_function());
4594 STATIC_ASSERT(kSizetSize == kIntptrSize);
4595 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
4596 MachineType::IntPtr(), MachineType::UintPtr(), memset,
4597 backing_store, IntPtrConstant(0), byte_length);
4600 void CodeStubAssembler::FillFixedDoubleArrayWithZero(
4601 TNode<FixedDoubleArray> array, TNode<IntPtrT> length) {
4602 CSA_ASSERT(
this, WordEqual(length, LoadAndUntagFixedArrayBaseLength(array)));
4604 TNode<IntPtrT> byte_length = TimesDoubleSize(length);
4605 CSA_ASSERT(
this, UintPtrLessThan(length, byte_length));
4607 static const int32_t fa_base_data_offset =
4608 FixedDoubleArray::kHeaderSize - kHeapObjectTag;
4609 TNode<IntPtrT> backing_store = IntPtrAdd(BitcastTaggedToWord(array),
4610 IntPtrConstant(fa_base_data_offset));
4613 TNode<ExternalReference> memset =
4614 ExternalConstant(ExternalReference::libc_memset_function());
4615 STATIC_ASSERT(kSizetSize == kIntptrSize);
4616 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
4617 MachineType::IntPtr(), MachineType::UintPtr(), memset,
4618 backing_store, IntPtrConstant(0), byte_length);
4621 void CodeStubAssembler::JumpIfPointersFromHereAreInteresting(
4622 TNode<Object>
object, Label* interesting) {
4623 Label finished(
this);
4624 TNode<IntPtrT> object_word = BitcastTaggedToWord(
object);
4625 TNode<IntPtrT> object_page = PageFromAddress(object_word);
4626 TNode<IntPtrT> page_flags = UncheckedCast<IntPtrT>(Load(
4627 MachineType::IntPtr(), object_page, IntPtrConstant(Page::kFlagsOffset)));
4629 WordEqual(WordAnd(page_flags,
4631 MemoryChunk::kPointersFromHereAreInterestingMask)),
4633 &finished, interesting);
4637 void CodeStubAssembler::MoveElements(ElementsKind kind,
4638 TNode<FixedArrayBase> elements,
4639 TNode<IntPtrT> dst_index,
4640 TNode<IntPtrT> src_index,
4641 TNode<IntPtrT> length) {
4642 Label finished(
this);
4643 Label needs_barrier(
this);
4644 const bool needs_barrier_check = !IsDoubleElementsKind(kind);
4646 DCHECK(IsFastElementsKind(kind));
4647 CSA_ASSERT(
this, IsFixedArrayWithKind(elements, kind));
4649 IntPtrLessThanOrEqual(IntPtrAdd(dst_index, length),
4650 LoadAndUntagFixedArrayBaseLength(elements)));
4652 IntPtrLessThanOrEqual(IntPtrAdd(src_index, length),
4653 LoadAndUntagFixedArrayBaseLength(elements)));
4657 if (needs_barrier_check) {
4658 JumpIfPointersFromHereAreInteresting(elements, &needs_barrier);
4661 const TNode<IntPtrT> source_byte_length =
4662 IntPtrMul(length, IntPtrConstant(ElementsKindToByteSize(kind)));
4663 static const int32_t fa_base_data_offset =
4664 FixedArrayBase::kHeaderSize - kHeapObjectTag;
4665 TNode<IntPtrT> elements_intptr = BitcastTaggedToWord(elements);
4666 TNode<IntPtrT> target_data_ptr =
4667 IntPtrAdd(elements_intptr,
4668 ElementOffsetFromIndex(dst_index, kind, INTPTR_PARAMETERS,
4669 fa_base_data_offset));
4670 TNode<IntPtrT> source_data_ptr =
4671 IntPtrAdd(elements_intptr,
4672 ElementOffsetFromIndex(src_index, kind, INTPTR_PARAMETERS,
4673 fa_base_data_offset));
4674 TNode<ExternalReference> memmove =
4675 ExternalConstant(ExternalReference::libc_memmove_function());
4676 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
4677 MachineType::Pointer(), MachineType::UintPtr(), memmove,
4678 target_data_ptr, source_data_ptr, source_byte_length);
4680 if (needs_barrier_check) {
4683 BIND(&needs_barrier);
4685 const TNode<IntPtrT> begin = src_index;
4686 const TNode<IntPtrT> end = IntPtrAdd(begin, length);
4689 const TNode<IntPtrT> delta =
4690 IntPtrMul(IntPtrSub(dst_index, begin),
4691 IntPtrConstant(ElementsKindToByteSize(kind)));
4692 auto loop_body = [&](Node* array, Node* offset) {
4693 Node*
const element = Load(MachineType::AnyTagged(), array, offset);
4694 Node*
const delta_offset = IntPtrAdd(offset, delta);
4695 Store(array, delta_offset, element);
4698 Label iterate_forward(
this);
4699 Label iterate_backward(
this);
4700 Branch(IntPtrLessThan(delta, IntPtrConstant(0)), &iterate_forward,
4702 BIND(&iterate_forward);
4705 BuildFastFixedArrayForEach(elements, kind, begin, end, loop_body,
4707 ForEachDirection::kForward);
4711 BIND(&iterate_backward);
4713 BuildFastFixedArrayForEach(elements, kind, begin, end, loop_body,
4715 ForEachDirection::kReverse);
4723 void CodeStubAssembler::CopyElements(ElementsKind kind,
4724 TNode<FixedArrayBase> dst_elements,
4725 TNode<IntPtrT> dst_index,
4726 TNode<FixedArrayBase> src_elements,
4727 TNode<IntPtrT> src_index,
4728 TNode<IntPtrT> length,
4729 WriteBarrierMode write_barrier) {
4730 Label finished(
this);
4731 Label needs_barrier(
this);
4732 const bool needs_barrier_check = !IsDoubleElementsKind(kind);
4734 DCHECK(IsFastElementsKind(kind));
4735 CSA_ASSERT(
this, IsFixedArrayWithKind(dst_elements, kind));
4736 CSA_ASSERT(
this, IsFixedArrayWithKind(src_elements, kind));
4737 CSA_ASSERT(
this, IntPtrLessThanOrEqual(
4738 IntPtrAdd(dst_index, length),
4739 LoadAndUntagFixedArrayBaseLength(dst_elements)));
4740 CSA_ASSERT(
this, IntPtrLessThanOrEqual(
4741 IntPtrAdd(src_index, length),
4742 LoadAndUntagFixedArrayBaseLength(src_elements)));
4743 CSA_ASSERT(
this, Word32Or(WordNotEqual(dst_elements, src_elements),
4744 WordEqual(length, IntPtrConstant(0))));
4748 if (needs_barrier_check) {
4749 JumpIfPointersFromHereAreInteresting(dst_elements, &needs_barrier);
4752 TNode<IntPtrT> source_byte_length =
4753 IntPtrMul(length, IntPtrConstant(ElementsKindToByteSize(kind)));
4754 static const int32_t fa_base_data_offset =
4755 FixedArrayBase::kHeaderSize - kHeapObjectTag;
4756 TNode<IntPtrT> src_offset_start = ElementOffsetFromIndex(
4757 src_index, kind, INTPTR_PARAMETERS, fa_base_data_offset);
4758 TNode<IntPtrT> dst_offset_start = ElementOffsetFromIndex(
4759 dst_index, kind, INTPTR_PARAMETERS, fa_base_data_offset);
4760 TNode<IntPtrT> src_elements_intptr = BitcastTaggedToWord(src_elements);
4761 TNode<IntPtrT> source_data_ptr =
4762 IntPtrAdd(src_elements_intptr, src_offset_start);
4763 TNode<IntPtrT> dst_elements_intptr = BitcastTaggedToWord(dst_elements);
4764 TNode<IntPtrT> dst_data_ptr =
4765 IntPtrAdd(dst_elements_intptr, dst_offset_start);
4766 TNode<ExternalReference> memcpy =
4767 ExternalConstant(ExternalReference::libc_memcpy_function());
4768 CallCFunction3(MachineType::Pointer(), MachineType::Pointer(),
4769 MachineType::Pointer(), MachineType::UintPtr(), memcpy,
4770 dst_data_ptr, source_data_ptr, source_byte_length);
4772 if (needs_barrier_check) {
4775 BIND(&needs_barrier);
4777 const TNode<IntPtrT> begin = src_index;
4778 const TNode<IntPtrT> end = IntPtrAdd(begin, length);
4779 const TNode<IntPtrT> delta =
4780 IntPtrMul(IntPtrSub(dst_index, src_index),
4781 IntPtrConstant(ElementsKindToByteSize(kind)));
4782 BuildFastFixedArrayForEach(
4783 src_elements, kind, begin, end,
4784 [&](Node* array, Node* offset) {
4785 Node*
const element = Load(MachineType::AnyTagged(), array, offset);
4786 Node*
const delta_offset = IntPtrAdd(offset, delta);
4787 if (write_barrier == SKIP_WRITE_BARRIER) {
4788 StoreNoWriteBarrier(MachineRepresentation::kTagged, dst_elements,
4789 delta_offset, element);
4791 Store(dst_elements, delta_offset, element);
4794 INTPTR_PARAMETERS, ForEachDirection::kForward);
4801 void CodeStubAssembler::CopyFixedArrayElements(
4802 ElementsKind from_kind, Node* from_array, ElementsKind to_kind,
4803 Node* to_array, Node* first_element, Node* element_count, Node* capacity,
4804 WriteBarrierMode barrier_mode, ParameterMode mode,
4805 HoleConversionMode convert_holes, TVariable<BoolT>* var_holes_converted) {
4806 DCHECK_IMPLIES(var_holes_converted !=
nullptr,
4807 convert_holes == HoleConversionMode::kConvertToUndefined);
4808 CSA_SLOW_ASSERT(
this, MatchesParameterMode(element_count, mode));
4809 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity, mode));
4810 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKindOrEmpty(from_array, from_kind));
4811 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKindOrEmpty(to_array, to_kind));
4812 STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
4813 const int first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag;
4814 Comment(
"[ CopyFixedArrayElements");
4817 DCHECK(!IsFixedTypedArrayElementsKind(from_kind));
4818 DCHECK(!IsFixedTypedArrayElementsKind(to_kind));
4821 bool from_double_elements = IsDoubleElementsKind(from_kind);
4822 bool to_double_elements = IsDoubleElementsKind(to_kind);
4823 bool doubles_to_objects_conversion =
4824 IsDoubleElementsKind(from_kind) && IsObjectElementsKind(to_kind);
4825 bool needs_write_barrier =
4826 doubles_to_objects_conversion ||
4827 (barrier_mode == UPDATE_WRITE_BARRIER && IsObjectElementsKind(to_kind));
4828 bool element_offset_matches =
4829 !needs_write_barrier && (Is64() || IsDoubleElementsKind(from_kind) ==
4830 IsDoubleElementsKind(to_kind));
4832 Is64() ? ReinterpretCast<UintPtrT>(Int64Constant(kHoleNanInt64))
4833 : ReinterpretCast<UintPtrT>(Int32Constant(kHoleNanLower32));
4837 if (convert_holes == HoleConversionMode::kConvertToUndefined) {
4838 DCHECK(IsObjectElementsKind(to_kind));
4842 FillFixedArrayWithValue(to_kind, to_array, IntPtrOrSmiConstant(0, mode),
4843 element_count, RootIndex::kUndefinedValue, mode);
4844 FillFixedArrayWithValue(to_kind, to_array, element_count, capacity,
4845 RootIndex::kTheHoleValue, mode);
4846 }
else if (doubles_to_objects_conversion) {
4849 FillFixedArrayWithValue(to_kind, to_array, IntPtrOrSmiConstant(0, mode),
4850 capacity, RootIndex::kTheHoleValue, mode);
4851 }
else if (element_count != capacity) {
4852 FillFixedArrayWithValue(to_kind, to_array, element_count, capacity,
4853 RootIndex::kTheHoleValue, mode);
4856 Node* first_from_element_offset =
4857 ElementOffsetFromIndex(first_element, from_kind, mode, 0);
4858 Node* limit_offset = IntPtrAdd(first_from_element_offset,
4859 IntPtrConstant(first_element_offset));
4861 var_from_offset, MachineType::PointerRepresentation(),
4862 ElementOffsetFromIndex(IntPtrOrSmiAdd(first_element, element_count, mode),
4863 from_kind, mode, first_element_offset));
4866 VARIABLE(var_to_offset, MachineType::PointerRepresentation());
4867 if (element_offset_matches) {
4868 var_to_offset.Bind(var_from_offset.value());
4870 var_to_offset.Bind(ElementOffsetFromIndex(element_count, to_kind, mode,
4871 first_element_offset));
4874 Variable* vars[] = {&var_from_offset, &var_to_offset, var_holes_converted};
4876 var_holes_converted !=
nullptr ? arraysize(vars) : arraysize(vars) - 1;
4877 Label decrement(
this, num_vars, vars);
4879 Node* to_array_adjusted =
4880 element_offset_matches
4881 ? IntPtrSub(BitcastTaggedToWord(to_array), first_from_element_offset)
4884 Branch(WordEqual(var_from_offset.value(), limit_offset), &done, &decrement);
4888 Node* from_offset = IntPtrSub(
4889 var_from_offset.value(),
4890 IntPtrConstant(from_double_elements ? kDoubleSize : kPointerSize));
4891 var_from_offset.Bind(from_offset);
4894 if (element_offset_matches) {
4895 to_offset = from_offset;
4897 to_offset = IntPtrSub(
4898 var_to_offset.value(),
4899 IntPtrConstant(to_double_elements ? kDoubleSize : kPointerSize));
4900 var_to_offset.Bind(to_offset);
4903 Label next_iter(
this), store_double_hole(
this), signal_hole(
this);
4905 if (convert_holes == HoleConversionMode::kConvertToUndefined) {
4908 if_hole = &signal_hole;
4909 }
else if (doubles_to_objects_conversion) {
4912 if_hole = &next_iter;
4913 }
else if (IsDoubleElementsKind(to_kind)) {
4914 if_hole = &store_double_hole;
4920 Node* value = LoadElementAndPrepareForStore(
4921 from_array, var_from_offset.value(), from_kind, to_kind, if_hole);
4923 if (needs_write_barrier) {
4924 CHECK_EQ(to_array, to_array_adjusted);
4925 Store(to_array_adjusted, to_offset, value);
4926 }
else if (to_double_elements) {
4927 StoreNoWriteBarrier(MachineRepresentation::kFloat64, to_array_adjusted,
4930 StoreNoWriteBarrier(MachineRepresentation::kTagged, to_array_adjusted,
4935 if (if_hole == &store_double_hole) {
4936 BIND(&store_double_hole);
4946 StoreNoWriteBarrier(MachineRepresentation::kWord64, to_array_adjusted,
4947 to_offset, double_hole);
4949 StoreNoWriteBarrier(MachineRepresentation::kWord32, to_array_adjusted,
4950 to_offset, double_hole);
4951 StoreNoWriteBarrier(MachineRepresentation::kWord32, to_array_adjusted,
4952 IntPtrAdd(to_offset, IntPtrConstant(kPointerSize)),
4956 }
else if (if_hole == &signal_hole) {
4959 if (var_holes_converted !=
nullptr) {
4960 *var_holes_converted = Int32TrueConstant();
4966 Node* compare = WordNotEqual(from_offset, limit_offset);
4967 Branch(compare, &decrement, &done);
4971 Comment(
"] CopyFixedArrayElements");
4974 TNode<FixedArray> CodeStubAssembler::HeapObjectToFixedArray(
4975 TNode<HeapObject> base, Label* cast_fail) {
4976 Label fixed_array(
this);
4977 TNode<Map> map = LoadMap(base);
4978 GotoIf(WordEqual(map, LoadRoot(RootIndex::kFixedArrayMap)), &fixed_array);
4979 GotoIf(WordNotEqual(map, LoadRoot(RootIndex::kFixedCOWArrayMap)), cast_fail);
4982 return UncheckedCast<FixedArray>(base);
4985 void CodeStubAssembler::CopyPropertyArrayValues(Node* from_array,
4987 Node* property_count,
4988 WriteBarrierMode barrier_mode,
4990 DestroySource destroy_source) {
4991 CSA_SLOW_ASSERT(
this, MatchesParameterMode(property_count, mode));
4992 CSA_SLOW_ASSERT(
this, Word32Or(IsPropertyArray(from_array),
4993 IsEmptyFixedArray(from_array)));
4994 CSA_SLOW_ASSERT(
this, IsPropertyArray(to_array));
4995 Comment(
"[ CopyPropertyArrayValues");
4997 bool needs_write_barrier = barrier_mode == UPDATE_WRITE_BARRIER;
4999 if (destroy_source == DestroySource::kNo) {
5002 needs_write_barrier =
true;
5005 Node* start = IntPtrOrSmiConstant(0, mode);
5006 ElementsKind kind = PACKED_ELEMENTS;
5007 BuildFastFixedArrayForEach(
5008 from_array, kind, start, property_count,
5009 [
this, to_array, needs_write_barrier, destroy_source](Node* array,
5011 Node* value = Load(MachineType::AnyTagged(), array, offset);
5013 if (destroy_source == DestroySource::kNo) {
5014 value = CloneIfMutablePrimitive(CAST(value));
5017 if (needs_write_barrier) {
5018 Store(to_array, offset, value);
5020 StoreNoWriteBarrier(MachineRepresentation::kTagged, to_array, offset,
5028 if (destroy_source == DestroySource::kYes) {
5029 Label did_zap(
this);
5030 GotoIf(IsEmptyFixedArray(from_array), &did_zap);
5031 FillPropertyArrayWithUndefined(from_array, start, property_count, mode);
5037 Comment(
"] CopyPropertyArrayValues");
5040 void CodeStubAssembler::CopyStringCharacters(Node* from_string, Node* to_string,
5041 TNode<IntPtrT> from_index,
5042 TNode<IntPtrT> to_index,
5043 TNode<IntPtrT> character_count,
5044 String::Encoding from_encoding,
5045 String::Encoding to_encoding) {
5049 bool from_one_byte = from_encoding == String::ONE_BYTE_ENCODING;
5050 bool to_one_byte = to_encoding == String::ONE_BYTE_ENCODING;
5051 DCHECK_IMPLIES(to_one_byte, from_one_byte);
5052 Comment(
"CopyStringCharacters %s -> %s",
5053 from_one_byte ?
"ONE_BYTE_ENCODING" :
"TWO_BYTE_ENCODING",
5054 to_one_byte ?
"ONE_BYTE_ENCODING" :
"TWO_BYTE_ENCODING");
5056 ElementsKind from_kind = from_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
5057 ElementsKind to_kind = to_one_byte ? UINT8_ELEMENTS : UINT16_ELEMENTS;
5058 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize);
5059 int header_size = SeqOneByteString::kHeaderSize - kHeapObjectTag;
5060 Node* from_offset = ElementOffsetFromIndex(from_index, from_kind,
5061 INTPTR_PARAMETERS, header_size);
5063 ElementOffsetFromIndex(to_index, to_kind, INTPTR_PARAMETERS, header_size);
5065 ElementOffsetFromIndex(character_count, from_kind, INTPTR_PARAMETERS);
5066 Node* limit_offset = IntPtrAdd(from_offset, byte_count);
5070 from_one_byte ? MachineType::Uint8() : MachineType::Uint16();
5071 MachineRepresentation rep = to_one_byte ? MachineRepresentation::kWord8
5072 : MachineRepresentation::kWord16;
5073 int from_increment = 1 << ElementsKindToShiftSize(from_kind);
5074 int to_increment = 1 << ElementsKindToShiftSize(to_kind);
5076 VARIABLE(current_to_offset, MachineType::PointerRepresentation(), to_offset);
5077 VariableList vars({¤t_to_offset}, zone());
5078 int to_index_constant = 0, from_index_constant = 0;
5079 bool index_same = (from_encoding == to_encoding) &&
5080 (from_index == to_index ||
5081 (ToInt32Constant(from_index, from_index_constant) &&
5082 ToInt32Constant(to_index, to_index_constant) &&
5083 from_index_constant == to_index_constant));
5084 BuildFastLoop(vars, from_offset, limit_offset,
5085 [
this, from_string, to_string, ¤t_to_offset, to_increment,
5086 type, rep, index_same](Node* offset) {
5087 Node* value = Load(type, from_string, offset);
5088 StoreNoWriteBarrier(
5090 index_same ? offset : current_to_offset.value(), value);
5092 Increment(¤t_to_offset, to_increment);
5095 from_increment, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
5098 Node* CodeStubAssembler::LoadElementAndPrepareForStore(Node* array,
5100 ElementsKind from_kind,
5101 ElementsKind to_kind,
5103 CSA_ASSERT(
this, IsFixedArrayWithKind(array, from_kind));
5104 if (IsDoubleElementsKind(from_kind)) {
5106 LoadDoubleWithHoleCheck(array, offset, if_hole, MachineType::Float64());
5107 if (!IsDoubleElementsKind(to_kind)) {
5108 value = AllocateHeapNumberWithValue(value);
5113 Node* value = Load(MachineType::AnyTagged(), array, offset);
5115 GotoIf(WordEqual(value, TheHoleConstant()), if_hole);
5117 if (IsDoubleElementsKind(to_kind)) {
5118 if (IsSmiElementsKind(from_kind)) {
5119 value = SmiToFloat64(value);
5121 value = LoadHeapNumberValue(value);
5128 Node* CodeStubAssembler::CalculateNewElementsCapacity(Node* old_capacity,
5129 ParameterMode mode) {
5130 CSA_SLOW_ASSERT(
this, MatchesParameterMode(old_capacity, mode));
5131 Node* half_old_capacity = WordOrSmiShr(old_capacity, 1, mode);
5132 Node* new_capacity = IntPtrOrSmiAdd(half_old_capacity, old_capacity, mode);
5134 IntPtrOrSmiConstant(JSObject::kMinAddedElementsCapacity, mode);
5135 return IntPtrOrSmiAdd(new_capacity, padding, mode);
5138 Node* CodeStubAssembler::TryGrowElementsCapacity(Node*
object, Node* elements,
5139 ElementsKind kind, Node* key,
5141 CSA_SLOW_ASSERT(
this, TaggedIsNotSmi(
object));
5142 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKindOrEmpty(elements, kind));
5143 CSA_SLOW_ASSERT(
this, TaggedIsSmi(key));
5144 Node* capacity = LoadFixedArrayBaseLength(elements);
5146 ParameterMode mode = OptimalParameterMode();
5147 capacity = TaggedToParameter(capacity, mode);
5148 key = TaggedToParameter(key, mode);
5150 return TryGrowElementsCapacity(
object, elements, kind, key, capacity, mode,
5154 Node* CodeStubAssembler::TryGrowElementsCapacity(Node*
object, Node* elements,
5155 ElementsKind kind, Node* key,
5159 Comment(
"TryGrowElementsCapacity");
5160 CSA_SLOW_ASSERT(
this, TaggedIsNotSmi(
object));
5161 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKindOrEmpty(elements, kind));
5162 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity, mode));
5163 CSA_SLOW_ASSERT(
this, MatchesParameterMode(key, mode));
5166 Node* max_gap = IntPtrOrSmiConstant(JSObject::kMaxGap, mode);
5167 Node* max_capacity = IntPtrOrSmiAdd(capacity, max_gap, mode);
5168 GotoIf(UintPtrOrSmiGreaterThanOrEqual(key, max_capacity, mode), bailout);
5171 Node* new_capacity = CalculateNewElementsCapacity(
5172 IntPtrOrSmiAdd(key, IntPtrOrSmiConstant(1, mode), mode), mode);
5173 return GrowElementsCapacity(
object, elements, kind, kind, capacity,
5174 new_capacity, mode, bailout);
5177 Node* CodeStubAssembler::GrowElementsCapacity(
5178 Node*
object, Node* elements, ElementsKind from_kind, ElementsKind to_kind,
5179 Node* capacity, Node* new_capacity, ParameterMode mode, Label* bailout) {
5180 Comment(
"[ GrowElementsCapacity");
5181 CSA_SLOW_ASSERT(
this, TaggedIsNotSmi(
object));
5182 CSA_SLOW_ASSERT(
this, IsFixedArrayWithKindOrEmpty(elements, from_kind));
5183 CSA_SLOW_ASSERT(
this, MatchesParameterMode(capacity, mode));
5184 CSA_SLOW_ASSERT(
this, MatchesParameterMode(new_capacity, mode));
5188 int max_size = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(to_kind);
5189 GotoIf(UintPtrOrSmiGreaterThanOrEqual(
5190 new_capacity, IntPtrOrSmiConstant(max_size, mode), mode),
5194 Node* new_elements = AllocateFixedArray(to_kind, new_capacity, mode);
5199 CopyFixedArrayElements(from_kind, elements, to_kind, new_elements, capacity,
5200 new_capacity, SKIP_WRITE_BARRIER, mode);
5202 StoreObjectField(
object, JSObject::kElementsOffset, new_elements);
5203 Comment(
"] GrowElementsCapacity");
5204 return new_elements;
5207 void CodeStubAssembler::InitializeAllocationMemento(Node* base,
5208 Node* base_allocation_size,
5209 Node* allocation_site) {
5210 Comment(
"[Initialize AllocationMemento");
5211 TNode<Object> memento =
5212 InnerAllocate(CAST(base), UncheckedCast<IntPtrT>(base_allocation_size));
5213 StoreMapNoWriteBarrier(memento, RootIndex::kAllocationMementoMap);
5214 StoreObjectFieldNoWriteBarrier(
5215 memento, AllocationMemento::kAllocationSiteOffset, allocation_site);
5216 if (FLAG_allocation_site_pretenuring) {
5217 TNode<Int32T> count = UncheckedCast<Int32T>(LoadObjectField(
5218 allocation_site, AllocationSite::kPretenureCreateCountOffset,
5219 MachineType::Int32()));
5221 TNode<Int32T> incremented_count = Int32Add(count, Int32Constant(1));
5222 StoreObjectFieldNoWriteBarrier(
5223 allocation_site, AllocationSite::kPretenureCreateCountOffset,
5224 incremented_count, MachineRepresentation::kWord32);
5229 Node* CodeStubAssembler::TryTaggedToFloat64(Node* value,
5230 Label* if_valueisnotnumber) {
5232 VARIABLE(var_result, MachineRepresentation::kFloat64);
5235 Label if_valueissmi(
this), if_valueisnotsmi(
this);
5236 Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
5238 BIND(&if_valueissmi);
5241 var_result.Bind(SmiToFloat64(value));
5245 BIND(&if_valueisnotsmi);
5248 Label if_valueisheapnumber(
this);
5249 Branch(IsHeapNumber(value), &if_valueisheapnumber, if_valueisnotnumber);
5251 BIND(&if_valueisheapnumber);
5254 var_result.Bind(LoadHeapNumberValue(value));
5259 return var_result.value();
5262 Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) {
5264 VARIABLE(var_value, MachineRepresentation::kTagged);
5265 VARIABLE(var_result, MachineRepresentation::kFloat64);
5266 Label loop(
this, &var_value), done_loop(
this, &var_result);
5267 var_value.Bind(value);
5271 Label if_valueisnotnumber(
this, Label::kDeferred);
5274 value = var_value.value();
5278 Node*
const result = TryTaggedToFloat64(value, &if_valueisnotnumber);
5279 var_result.Bind(result);
5282 BIND(&if_valueisnotnumber);
5285 var_value.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, value));
5290 return var_result.value();
5293 Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) {
5294 VARIABLE(var_result, MachineRepresentation::kWord32);
5296 TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumber>(context, value,
5297 &done, &var_result);
5299 return var_result.value();
5304 void CodeStubAssembler::TaggedToWord32OrBigInt(Node* context, Node* value,
5306 Variable* var_word32,
5308 Variable* var_bigint) {
5309 TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumeric>(
5310 context, value, if_number, var_word32, if_bigint, var_bigint);
5316 void CodeStubAssembler::TaggedToWord32OrBigIntWithFeedback(
5317 Node* context, Node* value, Label* if_number, Variable* var_word32,
5318 Label* if_bigint, Variable* var_bigint, Variable* var_feedback) {
5319 TaggedToWord32OrBigIntImpl<Object::Conversion::kToNumeric>(
5320 context, value, if_number, var_word32, if_bigint, var_bigint,
5324 template <Object::Conversion conversion>
5325 void CodeStubAssembler::TaggedToWord32OrBigIntImpl(
5326 Node* context, Node* value, Label* if_number, Variable* var_word32,
5327 Label* if_bigint, Variable* var_bigint, Variable* var_feedback) {
5328 DCHECK(var_word32->rep() == MachineRepresentation::kWord32);
5329 DCHECK(var_bigint ==
nullptr ||
5330 var_bigint->rep() == MachineRepresentation::kTagged);
5331 DCHECK(var_feedback ==
nullptr ||
5332 var_feedback->rep() == MachineRepresentation::kTaggedSigned);
5335 VARIABLE(var_value, MachineRepresentation::kTagged, value);
5336 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kNone);
5337 Variable* loop_vars[] = {&var_value, var_feedback};
5339 var_feedback !=
nullptr ? arraysize(loop_vars) : arraysize(loop_vars) - 1;
5340 Label loop(
this, num_vars, loop_vars);
5344 value = var_value.value();
5345 Label not_smi(
this), is_heap_number(
this), is_oddball(
this),
5347 GotoIf(TaggedIsNotSmi(value), ¬_smi);
5350 var_word32->Bind(SmiToInt32(value));
5351 CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
5355 Node* map = LoadMap(value);
5356 GotoIf(IsHeapNumberMap(map), &is_heap_number);
5357 Node* instance_type = LoadMapInstanceType(map);
5358 if (conversion == Object::Conversion::kToNumeric) {
5359 GotoIf(IsBigIntInstanceType(instance_type), &is_bigint);
5364 if (var_feedback !=
nullptr) {
5368 CSA_ASSERT(
this, SmiEqual(CAST(var_feedback->value()),
5369 SmiConstant(BinaryOperationFeedback::kNone)));
5371 GotoIf(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &is_oddball);
5373 auto builtin = conversion == Object::Conversion::kToNumeric
5374 ? Builtins::kNonNumberToNumeric
5375 : Builtins::kNonNumberToNumber;
5376 var_value.Bind(CallBuiltin(builtin, context, value));
5377 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kAny);
5381 var_value.Bind(LoadObjectField(value, Oddball::kToNumberOffset));
5382 OverwriteFeedback(var_feedback,
5383 BinaryOperationFeedback::kNumberOrOddball);
5387 BIND(&is_heap_number);
5388 var_word32->Bind(TruncateHeapNumberValueToWord32(value));
5389 CombineFeedback(var_feedback, BinaryOperationFeedback::kNumber);
5392 if (conversion == Object::Conversion::kToNumeric) {
5394 var_bigint->Bind(value);
5395 CombineFeedback(var_feedback, BinaryOperationFeedback::kBigInt);
5401 Node* CodeStubAssembler::TruncateHeapNumberValueToWord32(Node*
object) {
5402 Node* value = LoadHeapNumberValue(
object);
5403 return TruncateFloat64ToWord32(value);
5406 void CodeStubAssembler::TryHeapNumberToSmi(TNode<HeapNumber> number,
5407 TVariable<Smi>& var_result_smi,
5409 TNode<Float64T> value = LoadHeapNumberValue(number);
5410 TryFloat64ToSmi(value, var_result_smi, if_smi);
5413 void CodeStubAssembler::TryFloat64ToSmi(TNode<Float64T> value,
5414 TVariable<Smi>& var_result_smi,
5416 TNode<Int32T> value32 = RoundFloat64ToInt32(value);
5417 TNode<Float64T> value64 = ChangeInt32ToFloat64(value32);
5419 Label if_int32(
this), if_heap_number(
this, Label::kDeferred);
5421 GotoIfNot(Float64Equal(value, value64), &if_heap_number);
5422 GotoIfNot(Word32Equal(value32, Int32Constant(0)), &if_int32);
5423 Branch(Int32LessThan(UncheckedCast<Int32T>(Float64ExtractHighWord32(value)),
5425 &if_heap_number, &if_int32);
5427 TVARIABLE(Number, var_result);
5430 if (SmiValuesAre32Bits()) {
5431 var_result_smi = SmiTag(ChangeInt32ToIntPtr(value32));
5433 DCHECK(SmiValuesAre31Bits());
5434 TNode<PairT<Int32T, BoolT>> pair = Int32AddWithOverflow(value32, value32);
5435 TNode<BoolT> overflow = Projection<1>(pair);
5436 GotoIf(overflow, &if_heap_number);
5438 BitcastWordToTaggedSigned(ChangeInt32ToIntPtr(Projection<0>(pair)));
5442 BIND(&if_heap_number);
5445 TNode<Number> CodeStubAssembler::ChangeFloat64ToTagged(
5446 SloppyTNode<Float64T> value) {
5447 Label if_smi(
this), done(
this);
5448 TVARIABLE(Smi, var_smi_result);
5449 TVARIABLE(Number, var_result);
5450 TryFloat64ToSmi(value, var_smi_result, &if_smi);
5452 var_result = AllocateHeapNumberWithValue(value);
5457 var_result = var_smi_result.value();
5461 return var_result.value();
5464 TNode<Number> CodeStubAssembler::ChangeInt32ToTagged(
5465 SloppyTNode<Int32T> value) {
5466 if (SmiValuesAre32Bits()) {
5467 return SmiTag(ChangeInt32ToIntPtr(value));
5469 DCHECK(SmiValuesAre31Bits());
5470 TVARIABLE(Number, var_result);
5471 TNode<PairT<Int32T, BoolT>> pair = Int32AddWithOverflow(value, value);
5472 TNode<BoolT> overflow = Projection<1>(pair);
5473 Label if_overflow(
this, Label::kDeferred), if_notoverflow(
this),
5475 Branch(overflow, &if_overflow, &if_notoverflow);
5478 TNode<Float64T> value64 = ChangeInt32ToFloat64(value);
5479 TNode<HeapNumber> result = AllocateHeapNumberWithValue(value64);
5480 var_result = result;
5483 BIND(&if_notoverflow);
5485 TNode<IntPtrT> almost_tagged_value =
5486 ChangeInt32ToIntPtr(Projection<0>(pair));
5487 TNode<Smi> result = BitcastWordToTaggedSigned(almost_tagged_value);
5488 var_result = result;
5492 return var_result.value();
5495 TNode<Number> CodeStubAssembler::ChangeUint32ToTagged(
5496 SloppyTNode<Uint32T> value) {
5497 Label if_overflow(
this, Label::kDeferred), if_not_overflow(
this),
5499 TVARIABLE(Number, var_result);
5501 Branch(Uint32LessThan(Uint32Constant(Smi::kMaxValue), value), &if_overflow,
5504 BIND(&if_not_overflow);
5507 var_result = SmiTag(Signed(ChangeUint32ToWord(value)));
5513 TNode<Float64T> float64_value = ChangeUint32ToFloat64(value);
5514 var_result = AllocateHeapNumberWithValue(float64_value);
5519 return var_result.value();
5522 TNode<Number> CodeStubAssembler::ChangeUintPtrToTagged(TNode<UintPtrT> value) {
5523 Label if_overflow(
this, Label::kDeferred), if_not_overflow(
this),
5525 TVARIABLE(Number, var_result);
5527 Branch(UintPtrLessThan(UintPtrConstant(Smi::kMaxValue), value), &if_overflow,
5530 BIND(&if_not_overflow);
5533 var_result = SmiTag(Signed(value));
5539 TNode<Float64T> float64_value = ChangeUintPtrToFloat64(value);
5540 var_result = AllocateHeapNumberWithValue(float64_value);
5545 return var_result.value();
5548 TNode<String> CodeStubAssembler::ToThisString(Node* context, Node* value,
5549 char const* method_name) {
5550 VARIABLE(var_value, MachineRepresentation::kTagged, value);
5553 Label if_valueissmi(
this, Label::kDeferred), if_valueisnotsmi(
this),
5554 if_valueisstring(
this);
5555 Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi);
5556 BIND(&if_valueisnotsmi);
5559 Node* value_instance_type = LoadInstanceType(value);
5562 Label if_valueisnotstring(
this, Label::kDeferred);
5563 Branch(IsStringInstanceType(value_instance_type), &if_valueisstring,
5564 &if_valueisnotstring);
5565 BIND(&if_valueisnotstring);
5568 Label if_valueisnullorundefined(
this, Label::kDeferred);
5569 GotoIf(IsNullOrUndefined(value), &if_valueisnullorundefined);
5571 var_value.Bind(CallBuiltin(Builtins::kToString, context, value));
5572 Goto(&if_valueisstring);
5574 BIND(&if_valueisnullorundefined);
5577 ThrowTypeError(context, MessageTemplate::kCalledOnNullOrUndefined,
5582 BIND(&if_valueissmi);
5585 var_value.Bind(CallBuiltin(Builtins::kNumberToString, context, value));
5586 Goto(&if_valueisstring);
5588 BIND(&if_valueisstring);
5589 return CAST(var_value.value());
5592 TNode<Uint32T> CodeStubAssembler::ChangeNumberToUint32(TNode<Number> value) {
5593 TVARIABLE(Uint32T, var_result);
5594 Label if_smi(
this), if_heapnumber(
this, Label::kDeferred), done(
this);
5595 Branch(TaggedIsSmi(value), &if_smi, &if_heapnumber);
5598 var_result = Unsigned(SmiToInt32(CAST(value)));
5601 BIND(&if_heapnumber);
5603 var_result = ChangeFloat64ToUint32(LoadHeapNumberValue(CAST(value)));
5607 return var_result.value();
5610 TNode<Float64T> CodeStubAssembler::ChangeNumberToFloat64(
5611 SloppyTNode<Number> value) {
5613 CSA_SLOW_ASSERT(
this, IsNumber(value));
5614 TVARIABLE(Float64T, result);
5616 Label done(
this, &result);
5617 GotoIf(TaggedIsSmi(value), &smi);
5618 result = LoadHeapNumberValue(CAST(value));
5623 result = SmiToFloat64(CAST(value));
5628 return result.value();
5631 TNode<UintPtrT> CodeStubAssembler::ChangeNonnegativeNumberToUintPtr(
5632 TNode<Number> value) {
5633 TVARIABLE(UintPtrT, result);
5634 Label done(
this, &result);
5635 Branch(TaggedIsSmi(value),
5637 TNode<Smi> value_smi = CAST(value);
5638 CSA_SLOW_ASSERT(
this, SmiLessThan(SmiConstant(-1), value_smi));
5639 result = UncheckedCast<UintPtrT>(SmiToIntPtr(value_smi));
5643 TNode<HeapNumber> value_hn = CAST(value);
5644 result = ChangeFloat64ToUintPtr(LoadHeapNumberValue(value_hn));
5649 return result.value();
5652 TNode<WordT> CodeStubAssembler::TimesPointerSize(SloppyTNode<WordT> value) {
5653 return WordShl(value, kPointerSizeLog2);
5656 TNode<WordT> CodeStubAssembler::TimesDoubleSize(SloppyTNode<WordT> value) {
5657 return WordShl(value, kDoubleSizeLog2);
5660 Node* CodeStubAssembler::ToThisValue(Node* context, Node* value,
5661 PrimitiveType primitive_type,
5662 char const* method_name) {
5664 VARIABLE(var_value, MachineRepresentation::kTagged, value);
5665 Label loop(
this, &var_value), done_loop(
this),
5666 done_throw(
this, Label::kDeferred);
5671 value = var_value.value();
5674 GotoIf(TaggedIsSmi(value), (primitive_type == PrimitiveType::kNumber)
5679 Node* value_map = LoadMap(value);
5682 Node* value_instance_type = LoadMapInstanceType(value_map);
5685 Label if_valueisvalue(
this, Label::kDeferred), if_valueisnotvalue(
this);
5686 Branch(InstanceTypeEqual(value_instance_type, JS_VALUE_TYPE),
5687 &if_valueisvalue, &if_valueisnotvalue);
5689 BIND(&if_valueisvalue);
5692 var_value.Bind(LoadObjectField(value, JSValue::kValueOffset));
5696 BIND(&if_valueisnotvalue);
5698 switch (primitive_type) {
5699 case PrimitiveType::kBoolean:
5700 GotoIf(WordEqual(value_map, BooleanMapConstant()), &done_loop);
5702 case PrimitiveType::kNumber:
5703 GotoIf(WordEqual(value_map, HeapNumberMapConstant()), &done_loop);
5705 case PrimitiveType::kString:
5706 GotoIf(IsStringInstanceType(value_instance_type), &done_loop);
5708 case PrimitiveType::kSymbol:
5709 GotoIf(WordEqual(value_map, SymbolMapConstant()), &done_loop);
5718 const char* primitive_name =
nullptr;
5719 switch (primitive_type) {
5720 case PrimitiveType::kBoolean:
5721 primitive_name =
"Boolean";
5723 case PrimitiveType::kNumber:
5724 primitive_name =
"Number";
5726 case PrimitiveType::kString:
5727 primitive_name =
"String";
5729 case PrimitiveType::kSymbol:
5730 primitive_name =
"Symbol";
5733 CHECK_NOT_NULL(primitive_name);
5736 ThrowTypeError(context, MessageTemplate::kNotGeneric, method_name,
5741 return var_value.value();
5744 Node* CodeStubAssembler::ThrowIfNotInstanceType(Node* context, Node* value,
5745 InstanceType instance_type,
5746 char const* method_name) {
5747 Label out(
this), throw_exception(
this, Label::kDeferred);
5748 VARIABLE(var_value_map, MachineRepresentation::kTagged);
5750 GotoIf(TaggedIsSmi(value), &throw_exception);
5753 var_value_map.Bind(LoadMap(value));
5754 Node*
const value_instance_type = LoadMapInstanceType(var_value_map.value());
5756 Branch(Word32Equal(value_instance_type, Int32Constant(instance_type)), &out,
5760 BIND(&throw_exception);
5761 ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
5762 StringConstant(method_name), value);
5765 return var_value_map.value();
5768 Node* CodeStubAssembler::ThrowIfNotJSReceiver(Node* context, Node* value,
5769 MessageTemplate msg_template,
5770 const char* method_name) {
5771 Label out(
this), throw_exception(
this, Label::kDeferred);
5772 VARIABLE(var_value_map, MachineRepresentation::kTagged);
5774 GotoIf(TaggedIsSmi(value), &throw_exception);
5777 var_value_map.Bind(LoadMap(value));
5778 Node*
const value_instance_type = LoadMapInstanceType(var_value_map.value());
5780 Branch(IsJSReceiverInstanceType(value_instance_type), &out, &throw_exception);
5783 BIND(&throw_exception);
5784 ThrowTypeError(context, msg_template, method_name);
5787 return var_value_map.value();
5790 void CodeStubAssembler::ThrowRangeError(Node* context, MessageTemplate message,
5791 Node* arg0, Node* arg1, Node* arg2) {
5792 Node* template_index = SmiConstant(static_cast<int>(message));
5793 if (arg0 ==
nullptr) {
5794 CallRuntime(Runtime::kThrowRangeError, context, template_index);
5795 }
else if (arg1 ==
nullptr) {
5796 CallRuntime(Runtime::kThrowRangeError, context, template_index, arg0);
5797 }
else if (arg2 ==
nullptr) {
5798 CallRuntime(Runtime::kThrowRangeError, context, template_index, arg0, arg1);
5800 CallRuntime(Runtime::kThrowRangeError, context, template_index, arg0, arg1,
5806 void CodeStubAssembler::ThrowTypeError(Node* context, MessageTemplate message,
5807 char const* arg0,
char const* arg1) {
5808 Node* arg0_node =
nullptr;
5809 if (arg0) arg0_node = StringConstant(arg0);
5810 Node* arg1_node =
nullptr;
5811 if (arg1) arg1_node = StringConstant(arg1);
5812 ThrowTypeError(context, message, arg0_node, arg1_node);
5815 void CodeStubAssembler::ThrowTypeError(Node* context, MessageTemplate message,
5816 Node* arg0, Node* arg1, Node* arg2) {
5817 Node* template_index = SmiConstant(static_cast<int>(message));
5818 if (arg0 ==
nullptr) {
5819 CallRuntime(Runtime::kThrowTypeError, context, template_index);
5820 }
else if (arg1 ==
nullptr) {
5821 CallRuntime(Runtime::kThrowTypeError, context, template_index, arg0);
5822 }
else if (arg2 ==
nullptr) {
5823 CallRuntime(Runtime::kThrowTypeError, context, template_index, arg0, arg1);
5825 CallRuntime(Runtime::kThrowTypeError, context, template_index, arg0, arg1,
5831 TNode<BoolT> CodeStubAssembler::InstanceTypeEqual(
5832 SloppyTNode<Int32T> instance_type,
int type) {
5833 return Word32Equal(instance_type, Int32Constant(type));
5836 TNode<BoolT> CodeStubAssembler::IsDictionaryMap(SloppyTNode<Map> map) {
5837 CSA_SLOW_ASSERT(
this, IsMap(map));
5838 Node* bit_field3 = LoadMapBitField3(map);
5839 return IsSetWord32<Map::IsDictionaryMapBit>(bit_field3);
5842 TNode<BoolT> CodeStubAssembler::IsExtensibleMap(SloppyTNode<Map> map) {
5843 CSA_ASSERT(
this, IsMap(map));
5844 return IsSetWord32<Map::IsExtensibleBit>(LoadMapBitField2(map));
5847 TNode<BoolT> CodeStubAssembler::IsExtensibleNonPrototypeMap(TNode<Map> map) {
5848 int kMask = Map::IsExtensibleBit::kMask | Map::IsPrototypeMapBit::kMask;
5849 int kExpected = Map::IsExtensibleBit::kMask;
5850 return Word32Equal(Word32And(LoadMapBitField2(map), Int32Constant(kMask)),
5851 Int32Constant(kExpected));
5854 TNode<BoolT> CodeStubAssembler::IsCallableMap(SloppyTNode<Map> map) {
5855 CSA_ASSERT(
this, IsMap(map));
5856 return IsSetWord32<Map::IsCallableBit>(LoadMapBitField(map));
5859 TNode<BoolT> CodeStubAssembler::IsDeprecatedMap(SloppyTNode<Map> map) {
5860 CSA_ASSERT(
this, IsMap(map));
5861 return IsSetWord32<Map::IsDeprecatedBit>(LoadMapBitField3(map));
5864 TNode<BoolT> CodeStubAssembler::IsUndetectableMap(SloppyTNode<Map> map) {
5865 CSA_ASSERT(
this, IsMap(map));
5866 return IsSetWord32<Map::IsUndetectableBit>(LoadMapBitField(map));
5869 TNode<BoolT> CodeStubAssembler::IsNoElementsProtectorCellInvalid() {
5870 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5871 Node* cell = LoadRoot(RootIndex::kNoElementsProtector);
5872 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5873 return WordEqual(cell_value, invalid);
5876 TNode<BoolT> CodeStubAssembler::IsArrayIteratorProtectorCellInvalid() {
5877 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5878 Node* cell = LoadRoot(RootIndex::kArrayIteratorProtector);
5879 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5880 return WordEqual(cell_value, invalid);
5883 TNode<BoolT> CodeStubAssembler::IsPromiseResolveProtectorCellInvalid() {
5884 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5885 Node* cell = LoadRoot(RootIndex::kPromiseResolveProtector);
5886 Node* cell_value = LoadObjectField(cell, Cell::kValueOffset);
5887 return WordEqual(cell_value, invalid);
5890 TNode<BoolT> CodeStubAssembler::IsPromiseThenProtectorCellInvalid() {
5891 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5892 Node* cell = LoadRoot(RootIndex::kPromiseThenProtector);
5893 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5894 return WordEqual(cell_value, invalid);
5897 TNode<BoolT> CodeStubAssembler::IsArraySpeciesProtectorCellInvalid() {
5898 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5899 Node* cell = LoadRoot(RootIndex::kArraySpeciesProtector);
5900 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5901 return WordEqual(cell_value, invalid);
5904 TNode<BoolT> CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() {
5905 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5906 Node* cell = LoadRoot(RootIndex::kTypedArraySpeciesProtector);
5907 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5908 return WordEqual(cell_value, invalid);
5911 TNode<BoolT> CodeStubAssembler::IsRegExpSpeciesProtectorCellInvalid() {
5912 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5913 Node* cell = LoadRoot(RootIndex::kRegExpSpeciesProtector);
5914 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5915 return WordEqual(cell_value, invalid);
5918 TNode<BoolT> CodeStubAssembler::IsPromiseSpeciesProtectorCellInvalid() {
5919 Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
5920 Node* cell = LoadRoot(RootIndex::kPromiseSpeciesProtector);
5921 Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
5922 return WordEqual(cell_value, invalid);
5925 TNode<BoolT> CodeStubAssembler::IsPrototypeInitialArrayPrototype(
5926 SloppyTNode<Context> context, SloppyTNode<Map> map) {
5927 Node*
const native_context = LoadNativeContext(context);
5928 Node*
const initial_array_prototype = LoadContextElement(
5929 native_context, Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
5930 Node* proto = LoadMapPrototype(map);
5931 return WordEqual(proto, initial_array_prototype);
5934 TNode<BoolT> CodeStubAssembler::IsPrototypeTypedArrayPrototype(
5935 SloppyTNode<Context> context, SloppyTNode<Map> map) {
5936 TNode<Context>
const native_context = LoadNativeContext(context);
5937 TNode<Object>
const typed_array_prototype =
5938 LoadContextElement(native_context, Context::TYPED_ARRAY_PROTOTYPE_INDEX);
5939 TNode<HeapObject> proto = LoadMapPrototype(map);
5940 TNode<HeapObject> proto_of_proto = Select<HeapObject>(
5941 IsJSObject(proto), [=] {
return LoadMapPrototype(LoadMap(proto)); },
5942 [=] {
return NullConstant(); });
5943 return WordEqual(proto_of_proto, typed_array_prototype);
5946 TNode<BoolT> CodeStubAssembler::IsFastAliasedArgumentsMap(
5947 TNode<Context> context, TNode<Map> map) {
5948 TNode<Context>
const native_context = LoadNativeContext(context);
5949 TNode<Object>
const arguments_map = LoadContextElement(
5950 native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
5951 return WordEqual(arguments_map, map);
5954 TNode<BoolT> CodeStubAssembler::IsSlowAliasedArgumentsMap(
5955 TNode<Context> context, TNode<Map> map) {
5956 TNode<Context>
const native_context = LoadNativeContext(context);
5957 TNode<Object>
const arguments_map = LoadContextElement(
5958 native_context, Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX);
5959 return WordEqual(arguments_map, map);
5962 TNode<BoolT> CodeStubAssembler::IsSloppyArgumentsMap(TNode<Context> context,
5964 TNode<Context>
const native_context = LoadNativeContext(context);
5965 TNode<Object>
const arguments_map =
5966 LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
5967 return WordEqual(arguments_map, map);
5970 TNode<BoolT> CodeStubAssembler::IsStrictArgumentsMap(TNode<Context> context,
5972 TNode<Context>
const native_context = LoadNativeContext(context);
5973 TNode<Object>
const arguments_map =
5974 LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
5975 return WordEqual(arguments_map, map);
5978 TNode<BoolT> CodeStubAssembler::TaggedIsCallable(TNode<Object>
object) {
5979 return Select<BoolT>(
5980 TaggedIsSmi(
object), [=] {
return Int32FalseConstant(); },
5982 return IsCallableMap(LoadMap(UncheckedCast<HeapObject>(
object)));
5986 TNode<BoolT> CodeStubAssembler::IsCallable(SloppyTNode<HeapObject>
object) {
5987 return IsCallableMap(LoadMap(
object));
5990 TNode<BoolT> CodeStubAssembler::IsCell(SloppyTNode<HeapObject>
object) {
5991 return WordEqual(LoadMap(
object), LoadRoot(RootIndex::kCellMap));
5994 TNode<BoolT> CodeStubAssembler::IsCode(SloppyTNode<HeapObject>
object) {
5995 return HasInstanceType(
object, CODE_TYPE);
5998 TNode<BoolT> CodeStubAssembler::IsConstructorMap(SloppyTNode<Map> map) {
5999 CSA_ASSERT(
this, IsMap(map));
6000 return IsSetWord32<Map::IsConstructorBit>(LoadMapBitField(map));
6003 TNode<BoolT> CodeStubAssembler::IsConstructor(SloppyTNode<HeapObject>
object) {
6004 return IsConstructorMap(LoadMap(
object));
6007 TNode<BoolT> CodeStubAssembler::IsFunctionWithPrototypeSlotMap(
6008 SloppyTNode<Map> map) {
6009 CSA_ASSERT(
this, IsMap(map));
6010 return IsSetWord32<Map::HasPrototypeSlotBit>(LoadMapBitField(map));
6013 TNode<BoolT> CodeStubAssembler::IsSpecialReceiverInstanceType(
6014 TNode<Int32T> instance_type) {
6015 STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE);
6016 return Int32LessThanOrEqual(instance_type,
6017 Int32Constant(LAST_SPECIAL_RECEIVER_TYPE));
6020 TNode<BoolT> CodeStubAssembler::IsCustomElementsReceiverInstanceType(
6021 TNode<Int32T> instance_type) {
6022 return Int32LessThanOrEqual(instance_type,
6023 Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER));
6026 TNode<BoolT> CodeStubAssembler::IsStringInstanceType(
6027 SloppyTNode<Int32T> instance_type) {
6028 STATIC_ASSERT(INTERNALIZED_STRING_TYPE == FIRST_TYPE);
6029 return Int32LessThan(instance_type, Int32Constant(FIRST_NONSTRING_TYPE));
6032 TNode<BoolT> CodeStubAssembler::IsOneByteStringInstanceType(
6033 SloppyTNode<Int32T> instance_type) {
6034 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6036 Word32And(instance_type, Int32Constant(kStringEncodingMask)),
6037 Int32Constant(kOneByteStringTag));
6040 TNode<BoolT> CodeStubAssembler::HasOnlyOneByteChars(
6041 TNode<Int32T> instance_type) {
6042 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6043 return IsSetWord32(instance_type, kStringEncodingMask | kOneByteDataHintMask);
6046 TNode<BoolT> CodeStubAssembler::IsSequentialStringInstanceType(
6047 SloppyTNode<Int32T> instance_type) {
6048 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6050 Word32And(instance_type, Int32Constant(kStringRepresentationMask)),
6051 Int32Constant(kSeqStringTag));
6054 TNode<BoolT> CodeStubAssembler::IsConsStringInstanceType(
6055 SloppyTNode<Int32T> instance_type) {
6056 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6058 Word32And(instance_type, Int32Constant(kStringRepresentationMask)),
6059 Int32Constant(kConsStringTag));
6062 TNode<BoolT> CodeStubAssembler::IsIndirectStringInstanceType(
6063 SloppyTNode<Int32T> instance_type) {
6064 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6065 STATIC_ASSERT(kIsIndirectStringMask == 0x1);
6066 STATIC_ASSERT(kIsIndirectStringTag == 0x1);
6067 return UncheckedCast<BoolT>(
6068 Word32And(instance_type, Int32Constant(kIsIndirectStringMask)));
6071 TNode<BoolT> CodeStubAssembler::IsExternalStringInstanceType(
6072 SloppyTNode<Int32T> instance_type) {
6073 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6075 Word32And(instance_type, Int32Constant(kStringRepresentationMask)),
6076 Int32Constant(kExternalStringTag));
6079 TNode<BoolT> CodeStubAssembler::IsUncachedExternalStringInstanceType(
6080 SloppyTNode<Int32T> instance_type) {
6081 CSA_ASSERT(
this, IsStringInstanceType(instance_type));
6082 STATIC_ASSERT(kUncachedExternalStringTag != 0);
6083 return IsSetWord32(instance_type, kUncachedExternalStringMask);
6086 TNode<BoolT> CodeStubAssembler::IsJSReceiverInstanceType(
6087 SloppyTNode<Int32T> instance_type) {
6088 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
6089 return Int32GreaterThanOrEqual(instance_type,
6090 Int32Constant(FIRST_JS_RECEIVER_TYPE));
6093 TNode<BoolT> CodeStubAssembler::IsJSReceiverMap(SloppyTNode<Map> map) {
6094 return IsJSReceiverInstanceType(LoadMapInstanceType(map));
6097 TNode<BoolT> CodeStubAssembler::IsJSReceiver(SloppyTNode<HeapObject>
object) {
6098 return IsJSReceiverMap(LoadMap(
object));
6101 TNode<BoolT> CodeStubAssembler::IsNullOrJSReceiver(
6102 SloppyTNode<HeapObject>
object) {
6103 return UncheckedCast<BoolT>(Word32Or(IsJSReceiver(
object), IsNull(
object)));
6106 TNode<BoolT> CodeStubAssembler::IsNullOrUndefined(SloppyTNode<Object> value) {
6107 return UncheckedCast<BoolT>(Word32Or(IsUndefined(value), IsNull(value)));
6110 TNode<BoolT> CodeStubAssembler::IsJSGlobalProxyInstanceType(
6111 SloppyTNode<Int32T> instance_type) {
6112 return InstanceTypeEqual(instance_type, JS_GLOBAL_PROXY_TYPE);
6115 TNode<BoolT> CodeStubAssembler::IsJSObjectInstanceType(
6116 SloppyTNode<Int32T> instance_type) {
6117 STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
6118 return Int32GreaterThanOrEqual(instance_type,
6119 Int32Constant(FIRST_JS_OBJECT_TYPE));
6122 TNode<BoolT> CodeStubAssembler::IsJSObjectMap(SloppyTNode<Map> map) {
6123 CSA_ASSERT(
this, IsMap(map));
6124 return IsJSObjectInstanceType(LoadMapInstanceType(map));
6127 TNode<BoolT> CodeStubAssembler::IsJSObject(SloppyTNode<HeapObject>
object) {
6128 return IsJSObjectMap(LoadMap(
object));
6131 TNode<BoolT> CodeStubAssembler::IsJSPromiseMap(SloppyTNode<Map> map) {
6132 CSA_ASSERT(
this, IsMap(map));
6133 return InstanceTypeEqual(LoadMapInstanceType(map), JS_PROMISE_TYPE);
6136 TNode<BoolT> CodeStubAssembler::IsJSPromise(SloppyTNode<HeapObject>
object) {
6137 return IsJSPromiseMap(LoadMap(
object));
6140 TNode<BoolT> CodeStubAssembler::IsJSProxy(SloppyTNode<HeapObject>
object) {
6141 return HasInstanceType(
object, JS_PROXY_TYPE);
6144 TNode<BoolT> CodeStubAssembler::IsJSGlobalProxy(
6145 SloppyTNode<HeapObject>
object) {
6146 return HasInstanceType(
object, JS_GLOBAL_PROXY_TYPE);
6149 TNode<BoolT> CodeStubAssembler::IsMap(SloppyTNode<HeapObject> map) {
6150 return IsMetaMap(LoadMap(map));
6153 TNode<BoolT> CodeStubAssembler::IsJSValueInstanceType(
6154 SloppyTNode<Int32T> instance_type) {
6155 return InstanceTypeEqual(instance_type, JS_VALUE_TYPE);
6158 TNode<BoolT> CodeStubAssembler::IsJSValue(SloppyTNode<HeapObject>
object) {
6159 return IsJSValueMap(LoadMap(
object));
6162 TNode<BoolT> CodeStubAssembler::IsJSValueMap(SloppyTNode<Map> map) {
6163 return IsJSValueInstanceType(LoadMapInstanceType(map));
6166 TNode<BoolT> CodeStubAssembler::IsJSArrayInstanceType(
6167 SloppyTNode<Int32T> instance_type) {
6168 return InstanceTypeEqual(instance_type, JS_ARRAY_TYPE);
6171 TNode<BoolT> CodeStubAssembler::IsJSArray(SloppyTNode<HeapObject>
object) {
6172 return IsJSArrayMap(LoadMap(
object));
6175 TNode<BoolT> CodeStubAssembler::IsJSArrayMap(SloppyTNode<Map> map) {
6176 return IsJSArrayInstanceType(LoadMapInstanceType(map));
6179 TNode<BoolT> CodeStubAssembler::IsJSArrayIterator(
6180 SloppyTNode<HeapObject>
object) {
6181 return HasInstanceType(
object, JS_ARRAY_ITERATOR_TYPE);
6184 TNode<BoolT> CodeStubAssembler::IsJSAsyncGeneratorObject(
6185 SloppyTNode<HeapObject>
object) {
6186 return HasInstanceType(
object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
6189 TNode<BoolT> CodeStubAssembler::IsContext(SloppyTNode<HeapObject>
object) {
6190 Node* instance_type = LoadInstanceType(
object);
6191 return UncheckedCast<BoolT>(Word32And(
6192 Int32GreaterThanOrEqual(instance_type, Int32Constant(FIRST_CONTEXT_TYPE)),
6193 Int32LessThanOrEqual(instance_type, Int32Constant(LAST_CONTEXT_TYPE))));
6196 TNode<BoolT> CodeStubAssembler::IsFixedArray(SloppyTNode<HeapObject>
object) {
6197 return HasInstanceType(
object, FIXED_ARRAY_TYPE);
6200 TNode<BoolT> CodeStubAssembler::IsFixedArraySubclass(
6201 SloppyTNode<HeapObject>
object) {
6202 Node* instance_type = LoadInstanceType(
object);
6203 return UncheckedCast<BoolT>(
6204 Word32And(Int32GreaterThanOrEqual(instance_type,
6205 Int32Constant(FIRST_FIXED_ARRAY_TYPE)),
6206 Int32LessThanOrEqual(instance_type,
6207 Int32Constant(LAST_FIXED_ARRAY_TYPE))));
6210 TNode<BoolT> CodeStubAssembler::IsNotWeakFixedArraySubclass(
6211 SloppyTNode<HeapObject>
object) {
6212 Node* instance_type = LoadInstanceType(
object);
6213 return UncheckedCast<BoolT>(Word32Or(
6214 Int32LessThan(instance_type, Int32Constant(FIRST_WEAK_FIXED_ARRAY_TYPE)),
6215 Int32GreaterThan(instance_type,
6216 Int32Constant(LAST_WEAK_FIXED_ARRAY_TYPE))));
6219 TNode<BoolT> CodeStubAssembler::IsPromiseCapability(
6220 SloppyTNode<HeapObject>
object) {
6221 return HasInstanceType(
object, PROMISE_CAPABILITY_TYPE);
6224 TNode<BoolT> CodeStubAssembler::IsPropertyArray(
6225 SloppyTNode<HeapObject>
object) {
6226 return HasInstanceType(
object, PROPERTY_ARRAY_TYPE);
6238 TNode<BoolT> CodeStubAssembler::IsFixedArrayWithKindOrEmpty(
6239 SloppyTNode<HeapObject>
object, ElementsKind kind) {
6241 TVARIABLE(BoolT, var_result, Int32TrueConstant());
6243 GotoIf(IsFixedArrayWithKind(
object, kind), &out);
6245 TNode<Smi>
const length = LoadFixedArrayBaseLength(CAST(
object));
6246 GotoIf(SmiEqual(length, SmiConstant(0)), &out);
6248 var_result = Int32FalseConstant();
6252 return var_result.value();
6255 TNode<BoolT> CodeStubAssembler::IsFixedArrayWithKind(
6256 SloppyTNode<HeapObject>
object, ElementsKind kind) {
6257 if (IsDoubleElementsKind(kind)) {
6258 return IsFixedDoubleArray(
object);
6260 DCHECK(IsSmiOrObjectElementsKind(kind));
6261 return IsFixedArraySubclass(
object);
6265 TNode<BoolT> CodeStubAssembler::IsBoolean(SloppyTNode<HeapObject>
object) {
6266 return IsBooleanMap(LoadMap(
object));
6269 TNode<BoolT> CodeStubAssembler::IsPropertyCell(SloppyTNode<HeapObject>
object) {
6270 return IsPropertyCellMap(LoadMap(
object));
6273 TNode<BoolT> CodeStubAssembler::IsAccessorInfo(SloppyTNode<HeapObject>
object) {
6274 return IsAccessorInfoMap(LoadMap(
object));
6277 TNode<BoolT> CodeStubAssembler::IsAccessorPair(SloppyTNode<HeapObject>
object) {
6278 return IsAccessorPairMap(LoadMap(
object));
6281 TNode<BoolT> CodeStubAssembler::IsAllocationSite(
6282 SloppyTNode<HeapObject>
object) {
6283 return IsAllocationSiteInstanceType(LoadInstanceType(
object));
6286 TNode<BoolT> CodeStubAssembler::IsAnyHeapNumber(
6287 SloppyTNode<HeapObject>
object) {
6288 return UncheckedCast<BoolT>(
6289 Word32Or(IsMutableHeapNumber(
object), IsHeapNumber(
object)));
6292 TNode<BoolT> CodeStubAssembler::IsHeapNumber(SloppyTNode<HeapObject>
object) {
6293 return IsHeapNumberMap(LoadMap(
object));
6296 TNode<BoolT> CodeStubAssembler::IsHeapNumberInstanceType(
6297 SloppyTNode<Int32T> instance_type) {
6298 return InstanceTypeEqual(instance_type, HEAP_NUMBER_TYPE);
6301 TNode<BoolT> CodeStubAssembler::IsOddball(SloppyTNode<HeapObject>
object) {
6302 return IsOddballInstanceType(LoadInstanceType(
object));
6305 TNode<BoolT> CodeStubAssembler::IsOddballInstanceType(
6306 SloppyTNode<Int32T> instance_type) {
6307 return InstanceTypeEqual(instance_type, ODDBALL_TYPE);
6310 TNode<BoolT> CodeStubAssembler::IsMutableHeapNumber(
6311 SloppyTNode<HeapObject>
object) {
6312 return IsMutableHeapNumberMap(LoadMap(
object));
6315 TNode<BoolT> CodeStubAssembler::IsFeedbackCell(SloppyTNode<HeapObject>
object) {
6316 return HasInstanceType(
object, FEEDBACK_CELL_TYPE);
6319 TNode<BoolT> CodeStubAssembler::IsFeedbackVector(
6320 SloppyTNode<HeapObject>
object) {
6321 return IsFeedbackVectorMap(LoadMap(
object));
6324 TNode<BoolT> CodeStubAssembler::IsName(SloppyTNode<HeapObject>
object) {
6325 return IsNameInstanceType(LoadInstanceType(
object));
6328 TNode<BoolT> CodeStubAssembler::IsNameInstanceType(
6329 SloppyTNode<Int32T> instance_type) {
6330 return Int32LessThanOrEqual(instance_type, Int32Constant(LAST_NAME_TYPE));
6333 TNode<BoolT> CodeStubAssembler::IsString(SloppyTNode<HeapObject>
object) {
6334 return IsStringInstanceType(LoadInstanceType(
object));
6337 TNode<BoolT> CodeStubAssembler::IsSymbolInstanceType(
6338 SloppyTNode<Int32T> instance_type) {
6339 return InstanceTypeEqual(instance_type, SYMBOL_TYPE);
6342 TNode<BoolT> CodeStubAssembler::IsSymbol(SloppyTNode<HeapObject>
object) {
6343 return IsSymbolMap(LoadMap(
object));
6346 TNode<BoolT> CodeStubAssembler::IsBigIntInstanceType(
6347 SloppyTNode<Int32T> instance_type) {
6348 return InstanceTypeEqual(instance_type, BIGINT_TYPE);
6351 TNode<BoolT> CodeStubAssembler::IsBigInt(SloppyTNode<HeapObject>
object) {
6352 return IsBigIntInstanceType(LoadInstanceType(
object));
6355 TNode<BoolT> CodeStubAssembler::IsPrimitiveInstanceType(
6356 SloppyTNode<Int32T> instance_type) {
6357 return Int32LessThanOrEqual(instance_type,
6358 Int32Constant(LAST_PRIMITIVE_TYPE));
6361 TNode<BoolT> CodeStubAssembler::IsPrivateSymbol(
6362 SloppyTNode<HeapObject>
object) {
6363 return Select<BoolT>(IsSymbol(
object),
6365 TNode<Symbol> symbol = CAST(
object);
6366 TNode<Uint32T> flags = LoadObjectField<Uint32T>(
6367 symbol, Symbol::kFlagsOffset);
6368 return IsSetWord32<Symbol::IsPrivateBit>(flags);
6370 [=] {
return Int32FalseConstant(); });
6373 TNode<BoolT> CodeStubAssembler::IsNativeContext(
6374 SloppyTNode<HeapObject>
object) {
6375 return WordEqual(LoadMap(
object), LoadRoot(RootIndex::kNativeContextMap));
6378 TNode<BoolT> CodeStubAssembler::IsFixedDoubleArray(
6379 SloppyTNode<HeapObject>
object) {
6380 return WordEqual(LoadMap(
object), FixedDoubleArrayMapConstant());
6383 TNode<BoolT> CodeStubAssembler::IsHashTable(SloppyTNode<HeapObject>
object) {
6384 Node* instance_type = LoadInstanceType(
object);
6385 return UncheckedCast<BoolT>(
6386 Word32And(Int32GreaterThanOrEqual(instance_type,
6387 Int32Constant(FIRST_HASH_TABLE_TYPE)),
6388 Int32LessThanOrEqual(instance_type,
6389 Int32Constant(LAST_HASH_TABLE_TYPE))));
6392 TNode<BoolT> CodeStubAssembler::IsEphemeronHashTable(
6393 SloppyTNode<HeapObject>
object) {
6394 return HasInstanceType(
object, EPHEMERON_HASH_TABLE_TYPE);
6397 TNode<BoolT> CodeStubAssembler::IsNameDictionary(
6398 SloppyTNode<HeapObject>
object) {
6399 return HasInstanceType(
object, NAME_DICTIONARY_TYPE);
6402 TNode<BoolT> CodeStubAssembler::IsGlobalDictionary(
6403 SloppyTNode<HeapObject>
object) {
6404 return HasInstanceType(
object, GLOBAL_DICTIONARY_TYPE);
6407 TNode<BoolT> CodeStubAssembler::IsNumberDictionary(
6408 SloppyTNode<HeapObject>
object) {
6409 return HasInstanceType(
object, NUMBER_DICTIONARY_TYPE);
6412 TNode<BoolT> CodeStubAssembler::IsJSGeneratorObject(
6413 SloppyTNode<HeapObject>
object) {
6414 return HasInstanceType(
object, JS_GENERATOR_OBJECT_TYPE);
6417 TNode<BoolT> CodeStubAssembler::IsJSFunctionInstanceType(
6418 SloppyTNode<Int32T> instance_type) {
6419 return InstanceTypeEqual(instance_type, JS_FUNCTION_TYPE);
6422 TNode<BoolT> CodeStubAssembler::IsAllocationSiteInstanceType(
6423 SloppyTNode<Int32T> instance_type) {
6424 return InstanceTypeEqual(instance_type, ALLOCATION_SITE_TYPE);
6427 TNode<BoolT> CodeStubAssembler::IsJSFunction(SloppyTNode<HeapObject>
object) {
6428 return IsJSFunctionMap(LoadMap(
object));
6431 TNode<BoolT> CodeStubAssembler::IsJSFunctionMap(SloppyTNode<Map> map) {
6432 return IsJSFunctionInstanceType(LoadMapInstanceType(map));
6435 TNode<BoolT> CodeStubAssembler::IsJSTypedArray(SloppyTNode<HeapObject>
object) {
6436 return HasInstanceType(
object, JS_TYPED_ARRAY_TYPE);
6439 TNode<BoolT> CodeStubAssembler::IsJSArrayBuffer(
6440 SloppyTNode<HeapObject>
object) {
6441 return HasInstanceType(
object, JS_ARRAY_BUFFER_TYPE);
6444 TNode<BoolT> CodeStubAssembler::IsJSDataView(TNode<HeapObject>
object) {
6445 return HasInstanceType(
object, JS_DATA_VIEW_TYPE);
6448 TNode<BoolT> CodeStubAssembler::IsFixedTypedArray(
6449 SloppyTNode<HeapObject>
object) {
6450 TNode<Int32T> instance_type = LoadInstanceType(
object);
6451 return UncheckedCast<BoolT>(Word32And(
6452 Int32GreaterThanOrEqual(instance_type,
6453 Int32Constant(FIRST_FIXED_TYPED_ARRAY_TYPE)),
6454 Int32LessThanOrEqual(instance_type,
6455 Int32Constant(LAST_FIXED_TYPED_ARRAY_TYPE))));
6458 TNode<BoolT> CodeStubAssembler::IsJSRegExp(SloppyTNode<HeapObject>
object) {
6459 return HasInstanceType(
object, JS_REGEXP_TYPE);
6462 TNode<BoolT> CodeStubAssembler::IsNumber(SloppyTNode<Object>
object) {
6463 return Select<BoolT>(TaggedIsSmi(
object), [=] {
return Int32TrueConstant(); },
6464 [=] {
return IsHeapNumber(CAST(
object)); });
6467 TNode<BoolT> CodeStubAssembler::IsNumeric(SloppyTNode<Object>
object) {
6468 return Select<BoolT>(
6469 TaggedIsSmi(
object), [=] {
return Int32TrueConstant(); },
6471 return UncheckedCast<BoolT>(
6472 Word32Or(IsHeapNumber(CAST(
object)), IsBigInt(CAST(
object))));
6476 TNode<BoolT> CodeStubAssembler::IsNumberNormalized(SloppyTNode<Number> number) {
6477 TVARIABLE(BoolT, var_result, Int32TrueConstant());
6480 GotoIf(TaggedIsSmi(number), &out);
6482 TNode<Float64T> value = LoadHeapNumberValue(CAST(number));
6483 TNode<Float64T> smi_min =
6484 Float64Constant(static_cast<double>(Smi::kMinValue));
6485 TNode<Float64T> smi_max =
6486 Float64Constant(static_cast<double>(Smi::kMaxValue));
6488 GotoIf(Float64LessThan(value, smi_min), &out);
6489 GotoIf(Float64GreaterThan(value, smi_max), &out);
6490 GotoIfNot(Float64Equal(value, value), &out);
6492 var_result = Int32FalseConstant();
6496 return var_result.value();
6499 TNode<BoolT> CodeStubAssembler::IsNumberPositive(SloppyTNode<Number> number) {
6500 return Select<BoolT>(TaggedIsSmi(number),
6501 [=] {
return TaggedIsPositiveSmi(number); },
6502 [=] {
return IsHeapNumberPositive(CAST(number)); });
6506 TNode<BoolT> CodeStubAssembler::IsHeapNumberPositive(TNode<HeapNumber> number) {
6507 TNode<Float64T> value = LoadHeapNumberValue(number);
6508 TNode<Float64T> float_zero = Float64Constant(0.);
6509 return Float64GreaterThanOrEqual(value, float_zero);
6512 TNode<BoolT> CodeStubAssembler::IsNumberNonNegativeSafeInteger(
6513 TNode<Number> number) {
6514 return Select<BoolT>(
6516 TaggedIsSmi(number), [=] {
return TaggedIsPositiveSmi(number); },
6518 TNode<HeapNumber> heap_number = CAST(number);
6519 return Select<BoolT>(IsInteger(heap_number),
6520 [=] {
return IsHeapNumberPositive(heap_number); },
6521 [=] {
return Int32FalseConstant(); });
6525 TNode<BoolT> CodeStubAssembler::IsSafeInteger(TNode<Object> number) {
6526 return Select<BoolT>(
6527 TaggedIsSmi(number), [=] {
return Int32TrueConstant(); },
6529 return Select<BoolT>(
6530 IsHeapNumber(CAST(number)),
6531 [=] {
return IsSafeInteger(UncheckedCast<HeapNumber>(number)); },
6532 [=] {
return Int32FalseConstant(); });
6536 TNode<BoolT> CodeStubAssembler::IsSafeInteger(TNode<HeapNumber> number) {
6538 TNode<Float64T> number_value = LoadHeapNumberValue(number);
6540 TNode<Float64T> integer = Float64Trunc(number_value);
6542 return Select<BoolT>(
6545 Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0)),
6548 return Float64LessThanOrEqual(Float64Abs(integer),
6549 Float64Constant(kMaxSafeInteger));
6551 [=] {
return Int32FalseConstant(); });
6554 TNode<BoolT> CodeStubAssembler::IsInteger(TNode<Object> number) {
6555 return Select<BoolT>(
6556 TaggedIsSmi(number), [=] {
return Int32TrueConstant(); },
6558 return Select<BoolT>(
6559 IsHeapNumber(CAST(number)),
6560 [=] {
return IsInteger(UncheckedCast<HeapNumber>(number)); },
6561 [=] {
return Int32FalseConstant(); });
6565 TNode<BoolT> CodeStubAssembler::IsInteger(TNode<HeapNumber> number) {
6566 TNode<Float64T> number_value = LoadHeapNumberValue(number);
6568 TNode<Float64T> integer = Float64Trunc(number_value);
6570 return Float64Equal(Float64Sub(number_value, integer), Float64Constant(0.0));
6573 TNode<BoolT> CodeStubAssembler::IsHeapNumberUint32(TNode<HeapNumber> number) {
6575 return Select<BoolT>(
6576 IsHeapNumberPositive(number),
6578 TNode<Float64T> value = LoadHeapNumberValue(number);
6579 TNode<Uint32T> int_value = Unsigned(TruncateFloat64ToWord32(value));
6580 return Float64Equal(value, ChangeUint32ToFloat64(int_value));
6582 [=] {
return Int32FalseConstant(); });
6585 TNode<BoolT> CodeStubAssembler::IsNumberArrayIndex(TNode<Number> number) {
6586 return Select<BoolT>(TaggedIsSmi(number),
6587 [=] {
return TaggedIsPositiveSmi(number); },
6588 [=] {
return IsHeapNumberUint32(CAST(number)); });
6591 Node* CodeStubAssembler::FixedArraySizeDoesntFitInNewSpace(Node* element_count,
6593 ParameterMode mode) {
6594 int max_newspace_elements =
6595 (kMaxRegularHeapObjectSize - base_size) / kPointerSize;
6596 return IntPtrOrSmiGreaterThan(
6597 element_count, IntPtrOrSmiConstant(max_newspace_elements, mode), mode);
6600 TNode<Int32T> CodeStubAssembler::StringCharCodeAt(SloppyTNode<String>
string,
6601 SloppyTNode<IntPtrT> index) {
6602 CSA_ASSERT(
this, IsString(
string));
6604 CSA_ASSERT(
this, IntPtrGreaterThanOrEqual(index, IntPtrConstant(0)));
6605 CSA_ASSERT(
this, IntPtrLessThan(index, LoadStringLengthAsWord(
string)));
6607 TVARIABLE(Int32T, var_result);
6609 Label return_result(
this), if_runtime(
this, Label::kDeferred),
6610 if_stringistwobyte(
this), if_stringisonebyte(
this);
6612 ToDirectStringAssembler to_direct(state(),
string);
6613 to_direct.TryToDirect(&if_runtime);
6614 Node*
const offset = IntPtrAdd(index, to_direct.offset());
6615 Node*
const instance_type = to_direct.instance_type();
6617 Node*
const string_data = to_direct.PointerToData(&if_runtime);
6620 Branch(IsOneByteStringInstanceType(instance_type), &if_stringisonebyte,
6621 &if_stringistwobyte);
6623 BIND(&if_stringisonebyte);
6626 UncheckedCast<Int32T>(Load(MachineType::Uint8(), string_data, offset));
6627 Goto(&return_result);
6630 BIND(&if_stringistwobyte);
6633 UncheckedCast<Int32T>(Load(MachineType::Uint16(), string_data,
6634 WordShl(offset, IntPtrConstant(1))));
6635 Goto(&return_result);
6640 Node* result = CallRuntime(Runtime::kStringCharCodeAt, NoContextConstant(),
6641 string, SmiTag(index));
6642 var_result = SmiToInt32(result);
6643 Goto(&return_result);
6646 BIND(&return_result);
6647 return var_result.value();
6650 TNode<String> CodeStubAssembler::StringFromSingleCharCode(TNode<Int32T> code) {
6651 VARIABLE(var_result, MachineRepresentation::kTagged);
6654 Label if_codeisonebyte(
this), if_codeistwobyte(
this, Label::kDeferred),
6656 Branch(Int32LessThanOrEqual(code, Int32Constant(String::kMaxOneByteCharCode)),
6657 &if_codeisonebyte, &if_codeistwobyte);
6658 BIND(&if_codeisonebyte);
6661 TNode<FixedArray> cache =
6662 CAST(LoadRoot(RootIndex::kSingleCharacterStringCache));
6663 TNode<IntPtrT> code_index = Signed(ChangeUint32ToWord(code));
6667 Label if_entryisundefined(
this, Label::kDeferred),
6668 if_entryisnotundefined(
this);
6669 Node* entry = LoadFixedArrayElement(cache, code_index);
6670 Branch(IsUndefined(entry), &if_entryisundefined, &if_entryisnotundefined);
6672 BIND(&if_entryisundefined);
6675 TNode<String> result = AllocateSeqOneByteString(1);
6676 StoreNoWriteBarrier(
6677 MachineRepresentation::kWord8, result,
6678 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), code);
6679 StoreFixedArrayElement(cache, code_index, result);
6680 var_result.Bind(result);
6684 BIND(&if_entryisnotundefined);
6687 var_result.Bind(entry);
6692 BIND(&if_codeistwobyte);
6695 Node* result = AllocateSeqTwoByteString(1);
6696 StoreNoWriteBarrier(
6697 MachineRepresentation::kWord16, result,
6698 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code);
6699 var_result.Bind(result);
6704 CSA_ASSERT(
this, IsString(var_result.value()));
6705 return CAST(var_result.value());
6713 TNode<String> CodeStubAssembler::AllocAndCopyStringCharacters(
6714 Node* from, Node* from_instance_type, TNode<IntPtrT> from_index,
6715 TNode<IntPtrT> character_count) {
6716 Label end(
this), one_byte_sequential(
this), two_byte_sequential(
this);
6717 TVARIABLE(String, var_result);
6719 Branch(IsOneByteStringInstanceType(from_instance_type), &one_byte_sequential,
6720 &two_byte_sequential);
6723 BIND(&one_byte_sequential);
6725 TNode<String> result = AllocateSeqOneByteString(
6726 NoContextConstant(), Unsigned(TruncateIntPtrToInt32(character_count)));
6727 CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
6728 character_count, String::ONE_BYTE_ENCODING,
6729 String::ONE_BYTE_ENCODING);
6730 var_result = result;
6735 BIND(&two_byte_sequential);
6737 TNode<String> result = AllocateSeqTwoByteString(
6738 NoContextConstant(), Unsigned(TruncateIntPtrToInt32(character_count)));
6739 CopyStringCharacters(from, result, from_index, IntPtrConstant(0),
6740 character_count, String::TWO_BYTE_ENCODING,
6741 String::TWO_BYTE_ENCODING);
6742 var_result = result;
6747 return var_result.value();
6750 TNode<String> CodeStubAssembler::SubString(TNode<String>
string,
6751 TNode<IntPtrT> from,
6752 TNode<IntPtrT> to) {
6753 TVARIABLE(String, var_result);
6754 ToDirectStringAssembler to_direct(state(),
string);
6755 Label end(
this), runtime(
this);
6757 TNode<IntPtrT>
const substr_length = IntPtrSub(to, from);
6758 TNode<IntPtrT>
const string_length = LoadStringLengthAsWord(
string);
6762 Label original_string_or_invalid_length(
this);
6763 GotoIf(UintPtrGreaterThanOrEqual(substr_length, string_length),
6764 &original_string_or_invalid_length);
6768 Label single_char(
this);
6769 GotoIf(IntPtrEqual(substr_length, IntPtrConstant(1)), &single_char);
6776 TNode<String> direct_string = to_direct.TryToDirect(&runtime);
6777 TNode<IntPtrT> offset = IntPtrAdd(from, to_direct.offset());
6778 Node*
const instance_type = to_direct.instance_type();
6782 Label external_string(
this);
6784 if (FLAG_string_slices) {
6788 GotoIf(IntPtrLessThan(substr_length,
6789 IntPtrConstant(SlicedString::kMinLength)),
6794 Counters* counters = isolate()->counters();
6795 IncrementCounter(counters->sub_string_native(), 1);
6797 Label one_byte_slice(
this), two_byte_slice(
this);
6798 Branch(IsOneByteStringInstanceType(to_direct.instance_type()),
6799 &one_byte_slice, &two_byte_slice);
6801 BIND(&one_byte_slice);
6803 var_result = AllocateSlicedOneByteString(
6804 Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string,
6809 BIND(&two_byte_slice);
6811 var_result = AllocateSlicedTwoByteString(
6812 Unsigned(TruncateIntPtrToInt32(substr_length)), direct_string,
6822 GotoIf(to_direct.is_external(), &external_string);
6824 var_result = AllocAndCopyStringCharacters(direct_string, instance_type,
6825 offset, substr_length);
6827 Counters* counters = isolate()->counters();
6828 IncrementCounter(counters->sub_string_native(), 1);
6834 BIND(&external_string);
6836 Node*
const fake_sequential_string = to_direct.PointerToString(&runtime);
6838 var_result = AllocAndCopyStringCharacters(
6839 fake_sequential_string, instance_type, offset, substr_length);
6841 Counters* counters = isolate()->counters();
6842 IncrementCounter(counters->sub_string_native(), 1);
6850 TNode<Int32T> char_code = StringCharCodeAt(
string, from);
6851 var_result = StringFromSingleCharCode(char_code);
6855 BIND(&original_string_or_invalid_length);
6857 CSA_ASSERT(
this, IntPtrEqual(substr_length, string_length));
6860 GotoIf(UintPtrGreaterThan(from, IntPtrConstant(0)), &runtime);
6864 Counters* counters = isolate()->counters();
6865 IncrementCounter(counters->sub_string_native(), 1);
6867 var_result = string;
6875 CAST(CallRuntime(Runtime::kStringSubstring, NoContextConstant(),
string,
6876 SmiTag(from), SmiTag(to)));
6881 return var_result.value();
6884 ToDirectStringAssembler::ToDirectStringAssembler(
6885 compiler::CodeAssemblerState* state, Node*
string, Flags flags)
6886 : CodeStubAssembler(state),
6887 var_string_(this, MachineRepresentation::kTagged, string),
6888 var_instance_type_(this, MachineRepresentation::kWord32),
6889 var_offset_(this, MachineType::PointerRepresentation()),
6890 var_is_external_(this, MachineRepresentation::kWord32),
6892 CSA_ASSERT(
this, TaggedIsNotSmi(
string));
6893 CSA_ASSERT(
this, IsString(
string));
6895 var_string_.Bind(
string);
6896 var_offset_.Bind(IntPtrConstant(0));
6897 var_instance_type_.Bind(LoadInstanceType(
string));
6898 var_is_external_.Bind(Int32Constant(0));
6901 TNode<String> ToDirectStringAssembler::TryToDirect(Label* if_bailout) {
6902 VariableList vars({&var_string_, &var_offset_, &var_instance_type_}, zone());
6903 Label dispatch(
this, vars);
6904 Label if_iscons(
this);
6905 Label if_isexternal(
this);
6906 Label if_issliced(
this);
6907 Label if_isthin(
this);
6910 Branch(IsSequentialStringInstanceType(var_instance_type_.value()), &out,
6916 int32_t values[] = {
6917 kSeqStringTag, kConsStringTag, kExternalStringTag,
6918 kSlicedStringTag, kThinStringTag,
6921 &out, &if_iscons, &if_isexternal, &if_issliced, &if_isthin,
6923 STATIC_ASSERT(arraysize(values) == arraysize(labels));
6925 Node*
const representation = Word32And(
6926 var_instance_type_.value(), Int32Constant(kStringRepresentationMask));
6927 Switch(representation, if_bailout, values, labels, arraysize(values));
6934 Node*
const string = var_string_.value();
6935 GotoIfNot(IsEmptyString(LoadObjectField(
string, ConsString::kSecondOffset)),
6938 Node*
const lhs = LoadObjectField(
string, ConsString::kFirstOffset);
6939 var_string_.Bind(lhs);
6940 var_instance_type_.Bind(LoadInstanceType(lhs));
6948 if (!FLAG_string_slices || (flags_ & kDontUnpackSlicedStrings)) {
6951 Node*
const string = var_string_.value();
6952 Node*
const sliced_offset =
6953 LoadAndUntagObjectField(
string, SlicedString::kOffsetOffset);
6954 var_offset_.Bind(IntPtrAdd(var_offset_.value(), sliced_offset));
6956 Node*
const parent = LoadObjectField(
string, SlicedString::kParentOffset);
6957 var_string_.Bind(parent);
6958 var_instance_type_.Bind(LoadInstanceType(parent));
6967 Node*
const string = var_string_.value();
6968 Node*
const actual_string =
6969 LoadObjectField(
string, ThinString::kActualOffset);
6970 Node*
const actual_instance_type = LoadInstanceType(actual_string);
6972 var_string_.Bind(actual_string);
6973 var_instance_type_.Bind(actual_instance_type);
6979 BIND(&if_isexternal);
6980 var_is_external_.Bind(Int32Constant(1));
6984 return CAST(var_string_.value());
6987 TNode<RawPtrT> ToDirectStringAssembler::TryToSequential(
6988 StringPointerKind ptr_kind, Label* if_bailout) {
6989 CHECK(ptr_kind == PTR_TO_DATA || ptr_kind == PTR_TO_STRING);
6991 TVARIABLE(RawPtrT, var_result);
6992 Label out(
this), if_issequential(
this), if_isexternal(
this, Label::kDeferred);
6993 Branch(is_external(), &if_isexternal, &if_issequential);
6995 BIND(&if_issequential);
6997 STATIC_ASSERT(SeqOneByteString::kHeaderSize ==
6998 SeqTwoByteString::kHeaderSize);
6999 TNode<IntPtrT> result = BitcastTaggedToWord(var_string_.value());
7000 if (ptr_kind == PTR_TO_DATA) {
7001 result = IntPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize -
7004 var_result = ReinterpretCast<RawPtrT>(result);
7008 BIND(&if_isexternal);
7010 GotoIf(IsUncachedExternalStringInstanceType(var_instance_type_.value()),
7013 TNode<String>
string = CAST(var_string_.value());
7014 TNode<IntPtrT> result =
7015 LoadObjectField<IntPtrT>(string, ExternalString::kResourceDataOffset);
7016 if (ptr_kind == PTR_TO_STRING) {
7017 result = IntPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize -
7020 var_result = ReinterpretCast<RawPtrT>(result);
7025 return var_result.value();
7028 void CodeStubAssembler::BranchIfCanDerefIndirectString(Node*
string,
7029 Node* instance_type,
7031 Label* cannot_deref) {
7032 CSA_ASSERT(
this, IsString(
string));
7033 Node* representation =
7034 Word32And(instance_type, Int32Constant(kStringRepresentationMask));
7035 GotoIf(Word32Equal(representation, Int32Constant(kThinStringTag)), can_deref);
7036 GotoIf(Word32NotEqual(representation, Int32Constant(kConsStringTag)),
7039 Node* rhs = LoadObjectField(
string, ConsString::kSecondOffset);
7040 GotoIf(IsEmptyString(rhs), can_deref);
7044 Node* CodeStubAssembler::DerefIndirectString(TNode<String>
string,
7045 TNode<Int32T> instance_type,
7046 Label* cannot_deref) {
7048 BranchIfCanDerefIndirectString(
string, instance_type, &deref, cannot_deref);
7050 STATIC_ASSERT(static_cast<int>(ThinString::kActualOffset) ==
7051 static_cast<int>(ConsString::kFirstOffset));
7052 return LoadObjectField(
string, ThinString::kActualOffset);
7055 void CodeStubAssembler::DerefIndirectString(Variable* var_string,
7056 Node* instance_type) {
7058 Label can_deref(
this), cannot_deref(
this);
7059 BranchIfCanDerefIndirectString(var_string->value(), instance_type, &can_deref,
7061 BIND(&cannot_deref);
7067 STATIC_ASSERT(static_cast<int>(ThinString::kActualOffset) ==
7068 static_cast<int>(ConsString::kFirstOffset));
7070 LoadObjectField(var_string->value(), ThinString::kActualOffset));
7073 void CodeStubAssembler::MaybeDerefIndirectString(Variable* var_string,
7074 Node* instance_type,
7076 Label* cannot_deref) {
7078 BranchIfCanDerefIndirectString(var_string->value(), instance_type, &deref,
7083 DerefIndirectString(var_string, instance_type);
7088 void CodeStubAssembler::MaybeDerefIndirectStrings(Variable* var_left,
7089 Node* left_instance_type,
7090 Variable* var_right,
7091 Node* right_instance_type,
7092 Label* did_something) {
7093 Label did_nothing_left(
this), did_something_left(
this),
7094 didnt_do_anything(
this);
7095 MaybeDerefIndirectString(var_left, left_instance_type, &did_something_left,
7098 BIND(&did_something_left);
7100 MaybeDerefIndirectString(var_right, right_instance_type, did_something,
7104 BIND(&did_nothing_left);
7106 MaybeDerefIndirectString(var_right, right_instance_type, did_something,
7107 &didnt_do_anything);
7110 BIND(&didnt_do_anything);
7114 TNode<String> CodeStubAssembler::StringAdd(Node* context, TNode<String> left,
7115 TNode<String> right,
7116 AllocationFlags flags) {
7117 TVARIABLE(String, result);
7118 Label check_right(
this), runtime(
this, Label::kDeferred), cons(
this),
7119 done(
this, &result), done_native(
this, &result);
7120 Counters* counters = isolate()->counters();
7122 TNode<Uint32T> left_length = LoadStringLengthAsWord32(left);
7123 GotoIfNot(Word32Equal(left_length, Uint32Constant(0)), &check_right);
7128 TNode<Uint32T> right_length = LoadStringLengthAsWord32(right);
7129 GotoIfNot(Word32Equal(right_length, Uint32Constant(0)), &cons);
7135 TNode<Uint32T> new_length = Uint32Add(left_length, right_length);
7140 GotoIf(Uint32GreaterThan(new_length, Uint32Constant(String::kMaxLength)),
7143 TVARIABLE(String, var_left, left);
7144 TVARIABLE(String, var_right, right);
7145 Variable* input_vars[2] = {&var_left, &var_right};
7146 Label non_cons(
this, 2, input_vars);
7147 Label slow(
this, Label::kDeferred);
7148 GotoIf(Uint32LessThan(new_length, Uint32Constant(ConsString::kMinLength)),
7152 NewConsString(new_length, var_left.value(), var_right.value(), flags);
7157 Comment(
"Full string concatenate");
7158 Node* left_instance_type = LoadInstanceType(var_left.value());
7159 Node* right_instance_type = LoadInstanceType(var_right.value());
7162 Node* ored_instance_types =
7163 Word32Or(left_instance_type, right_instance_type);
7164 Node* xored_instance_types =
7165 Word32Xor(left_instance_type, right_instance_type);
7168 GotoIf(IsSetWord32(xored_instance_types, kStringEncodingMask), &runtime);
7169 GotoIf(IsSetWord32(ored_instance_types, kStringRepresentationMask), &slow);
7171 TNode<IntPtrT> word_left_length = Signed(ChangeUint32ToWord(left_length));
7172 TNode<IntPtrT> word_right_length = Signed(ChangeUint32ToWord(right_length));
7174 Label two_byte(
this);
7175 GotoIf(Word32Equal(Word32And(ored_instance_types,
7176 Int32Constant(kStringEncodingMask)),
7177 Int32Constant(kTwoByteStringTag)),
7180 result = AllocateSeqOneByteString(context, new_length);
7181 CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0),
7182 IntPtrConstant(0), word_left_length,
7183 String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING);
7184 CopyStringCharacters(var_right.value(), result.value(), IntPtrConstant(0),
7185 word_left_length, word_right_length,
7186 String::ONE_BYTE_ENCODING, String::ONE_BYTE_ENCODING);
7192 result = AllocateSeqTwoByteString(context, new_length);
7193 CopyStringCharacters(var_left.value(), result.value(), IntPtrConstant(0),
7194 IntPtrConstant(0), word_left_length,
7195 String::TWO_BYTE_ENCODING,
7196 String::TWO_BYTE_ENCODING);
7197 CopyStringCharacters(var_right.value(), result.value(), IntPtrConstant(0),
7198 word_left_length, word_right_length,
7199 String::TWO_BYTE_ENCODING,
7200 String::TWO_BYTE_ENCODING);
7207 MaybeDerefIndirectStrings(&var_left, left_instance_type, &var_right,
7208 right_instance_type, &non_cons);
7214 result = CAST(CallRuntime(Runtime::kStringAdd, context, left, right));
7220 IncrementCounter(counters->string_add_native(), 1);
7225 return result.value();
7228 TNode<String> CodeStubAssembler::StringFromSingleCodePoint(
7229 TNode<Int32T> codepoint, UnicodeEncoding encoding) {
7230 VARIABLE(var_result, MachineRepresentation::kTagged, EmptyStringConstant());
7232 Label if_isword16(
this), if_isword32(
this), return_result(
this);
7234 Branch(Uint32LessThan(codepoint, Int32Constant(0x10000)), &if_isword16,
7239 var_result.Bind(StringFromSingleCharCode(codepoint));
7240 Goto(&return_result);
7246 case UnicodeEncoding::UTF16:
7248 case UnicodeEncoding::UTF32: {
7250 Node* lead_offset = Int32Constant(0xD800 - (0x10000 >> 10));
7254 Int32Add(Word32Shr(codepoint, Int32Constant(10)), lead_offset);
7257 Node* trail = Int32Add(Word32And(codepoint, Int32Constant(0x3FF)),
7258 Int32Constant(0xDC00));
7261 codepoint = Signed(Word32Or(Word32Shl(trail, Int32Constant(16)), lead));
7266 Node* value = AllocateSeqTwoByteString(2);
7267 StoreNoWriteBarrier(
7268 MachineRepresentation::kWord32, value,
7269 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag),
7271 var_result.Bind(value);
7272 Goto(&return_result);
7275 BIND(&return_result);
7276 return CAST(var_result.value());
7279 TNode<Number> CodeStubAssembler::StringToNumber(TNode<String> input) {
7280 Label runtime(
this, Label::kDeferred);
7283 TVARIABLE(Number, var_result);
7286 TNode<Uint32T> hash = LoadNameHashField(input);
7287 GotoIf(IsSetWord32(hash, Name::kDoesNotContainCachedArrayIndexMask),
7291 SmiTag(Signed(DecodeWordFromWord32<String::ArrayIndexValueBits>(hash)));
7297 CAST(CallRuntime(Runtime::kStringToNumber, NoContextConstant(), input));
7302 return var_result.value();
7305 TNode<String> CodeStubAssembler::NumberToString(TNode<Number> input) {
7306 TVARIABLE(String, result);
7307 TVARIABLE(Smi, smi_input);
7308 Label runtime(
this, Label::kDeferred), if_smi(
this), if_heap_number(
this),
7309 done(
this, &result);
7312 Node* number_string_cache = LoadRoot(RootIndex::kNumberStringCache);
7318 BitcastTaggedToWord(LoadFixedArrayBaseLength(number_string_cache));
7319 TNode<IntPtrT> one = IntPtrConstant(1);
7320 mask = IntPtrSub(mask, one);
7322 GotoIfNot(TaggedIsSmi(input), &if_heap_number);
7323 smi_input = CAST(input);
7326 BIND(&if_heap_number);
7328 TNode<HeapNumber> heap_number_input = CAST(input);
7330 TryHeapNumberToSmi(heap_number_input, smi_input, &if_smi);
7334 LoadObjectField<Int32T>(heap_number_input, HeapNumber::kValueOffset);
7335 TNode<Int32T> high = LoadObjectField<Int32T>(
7336 heap_number_input, HeapNumber::kValueOffset + kIntSize);
7337 TNode<Word32T> hash = Word32Xor(low, high);
7338 TNode<WordT> word_hash = WordShl(ChangeInt32ToIntPtr(hash), one);
7339 TNode<WordT> index =
7340 WordAnd(word_hash, WordSar(mask, SmiShiftBitsConstant()));
7343 Node* number_key = LoadFixedArrayElement(CAST(number_string_cache), index);
7344 GotoIf(TaggedIsSmi(number_key), &runtime);
7345 GotoIfNot(IsHeapNumber(number_key), &runtime);
7348 Node* low_compare = LoadObjectField(number_key, HeapNumber::kValueOffset,
7349 MachineType::Int32());
7350 Node* high_compare = LoadObjectField(
7351 number_key, HeapNumber::kValueOffset + kIntSize, MachineType::Int32());
7352 GotoIfNot(Word32Equal(low, low_compare), &runtime);
7353 GotoIfNot(Word32Equal(high, high_compare), &runtime);
7357 LoadFixedArrayElement(CAST(number_string_cache), index, kPointerSize));
7364 Node* smi_index = BitcastWordToTagged(
7365 WordAnd(WordShl(BitcastTaggedToWord(smi_input.value()), one), mask));
7366 Node* smi_key = LoadFixedArrayElement(CAST(number_string_cache), smi_index,
7368 GotoIf(WordNotEqual(smi_key, smi_input.value()), &runtime);
7371 result = CAST(LoadFixedArrayElement(CAST(number_string_cache), smi_index,
7372 kPointerSize, SMI_PARAMETERS));
7380 CAST(CallRuntime(Runtime::kNumberToString, NoContextConstant(), input));
7384 return result.value();
7387 Node* CodeStubAssembler::NonNumberToNumberOrNumeric(
7388 Node* context, Node* input, Object::Conversion mode,
7389 BigIntHandling bigint_handling) {
7390 CSA_ASSERT(
this, Word32BinaryNot(TaggedIsSmi(input)));
7391 CSA_ASSERT(
this, Word32BinaryNot(IsHeapNumber(input)));
7394 VARIABLE(var_input, MachineRepresentation::kTagged, input);
7395 VARIABLE(var_result, MachineRepresentation::kTagged);
7396 Label loop(
this, &var_input);
7402 Node* input = var_input.value();
7405 Node* input_instance_type = LoadInstanceType(input);
7406 Label if_inputisstring(
this), if_inputisoddball(
this),
7407 if_inputisbigint(
this), if_inputisreceiver(
this, Label::kDeferred),
7408 if_inputisother(
this, Label::kDeferred);
7409 GotoIf(IsStringInstanceType(input_instance_type), &if_inputisstring);
7410 GotoIf(IsBigIntInstanceType(input_instance_type), &if_inputisbigint);
7411 GotoIf(InstanceTypeEqual(input_instance_type, ODDBALL_TYPE),
7412 &if_inputisoddball);
7413 Branch(IsJSReceiverInstanceType(input_instance_type), &if_inputisreceiver,
7416 BIND(&if_inputisstring);
7419 TNode<String> string_input = CAST(input);
7420 var_result.Bind(StringToNumber(string_input));
7424 BIND(&if_inputisbigint);
7425 if (mode == Object::Conversion::kToNumeric) {
7426 var_result.Bind(input);
7429 DCHECK_EQ(mode, Object::Conversion::kToNumber);
7430 if (bigint_handling == BigIntHandling::kThrow) {
7431 Goto(&if_inputisother);
7433 DCHECK_EQ(bigint_handling, BigIntHandling::kConvertToNumber);
7434 var_result.Bind(CallRuntime(Runtime::kBigIntToNumber, context, input));
7439 BIND(&if_inputisoddball);
7442 var_result.Bind(LoadObjectField(input, Oddball::kToNumberOffset));
7446 BIND(&if_inputisreceiver);
7450 Callable callable = CodeFactory::NonPrimitiveToPrimitive(
7451 isolate(), ToPrimitiveHint::kNumber);
7452 Node* result = CallStub(callable, context, input);
7455 Label if_done(
this), if_notdone(
this);
7456 Branch(mode == Object::Conversion::kToNumber ? IsNumber(result)
7457 : IsNumeric(result),
7458 &if_done, &if_notdone);
7464 var_result.Bind(result);
7471 var_input.Bind(result);
7476 BIND(&if_inputisother);
7484 auto function_id = mode == Object::Conversion::kToNumber
7485 ? Runtime::kToNumber
7486 : Runtime::kToNumeric;
7487 var_result.Bind(CallRuntime(function_id, context, input));
7493 if (mode == Object::Conversion::kToNumeric) {
7494 CSA_ASSERT(
this, IsNumeric(var_result.value()));
7496 DCHECK_EQ(mode, Object::Conversion::kToNumber);
7497 CSA_ASSERT(
this, IsNumber(var_result.value()));
7499 return var_result.value();
7502 TNode<Number> CodeStubAssembler::NonNumberToNumber(
7503 SloppyTNode<Context> context, SloppyTNode<HeapObject> input,
7504 BigIntHandling bigint_handling) {
7505 return CAST(NonNumberToNumberOrNumeric(
7506 context, input, Object::Conversion::kToNumber, bigint_handling));
7509 TNode<Numeric> CodeStubAssembler::NonNumberToNumeric(
7510 SloppyTNode<Context> context, SloppyTNode<HeapObject> input) {
7511 Node* result = NonNumberToNumberOrNumeric(context, input,
7512 Object::Conversion::kToNumeric);
7513 CSA_SLOW_ASSERT(
this, IsNumeric(result));
7514 return UncheckedCast<Numeric>(result);
7517 TNode<Number> CodeStubAssembler::ToNumber_Inline(SloppyTNode<Context> context,
7518 SloppyTNode<Object> input) {
7519 TVARIABLE(Number, var_result);
7520 Label end(
this), not_smi(
this, Label::kDeferred);
7522 GotoIfNot(TaggedIsSmi(input), ¬_smi);
7523 var_result = CAST(input);
7529 Select<Number>(IsHeapNumber(CAST(input)), [=] {
return CAST(input); },
7531 return CAST(CallBuiltin(Builtins::kNonNumberToNumber,
7538 return var_result.value();
7541 TNode<Number> CodeStubAssembler::ToNumber(SloppyTNode<Context> context,
7542 SloppyTNode<Object> input,
7543 BigIntHandling bigint_handling) {
7544 TVARIABLE(Number, var_result);
7547 Label not_smi(
this, Label::kDeferred);
7548 GotoIfNot(TaggedIsSmi(input), ¬_smi);
7549 TNode<Smi> input_smi = CAST(input);
7550 var_result = input_smi;
7555 Label not_heap_number(
this, Label::kDeferred);
7556 TNode<HeapObject> input_ho = CAST(input);
7557 GotoIfNot(IsHeapNumber(input_ho), ¬_heap_number);
7559 TNode<HeapNumber> input_hn = CAST(input_ho);
7560 var_result = input_hn;
7563 BIND(¬_heap_number);
7565 var_result = NonNumberToNumber(context, input_ho, bigint_handling);
7571 return var_result.value();
7574 TNode<BigInt> CodeStubAssembler::ToBigInt(SloppyTNode<Context> context,
7575 SloppyTNode<Object> input) {
7576 TVARIABLE(BigInt, var_result);
7577 Label if_bigint(
this), done(
this), if_throw(
this);
7579 GotoIf(TaggedIsSmi(input), &if_throw);
7580 GotoIf(IsBigInt(CAST(input)), &if_bigint);
7581 var_result = CAST(CallRuntime(Runtime::kToBigInt, context, input));
7585 var_result = CAST(input);
7589 ThrowTypeError(context, MessageTemplate::kBigIntFromObject, input);
7592 return var_result.value();
7595 void CodeStubAssembler::TaggedToNumeric(Node* context, Node* value, Label* done,
7596 Variable* var_numeric) {
7597 TaggedToNumeric(context, value, done, var_numeric,
nullptr);
7600 void CodeStubAssembler::TaggedToNumericWithFeedback(Node* context, Node* value,
7602 Variable* var_numeric,
7603 Variable* var_feedback) {
7604 DCHECK_NOT_NULL(var_feedback);
7605 TaggedToNumeric(context, value, done, var_numeric, var_feedback);
7608 void CodeStubAssembler::TaggedToNumeric(Node* context, Node* value, Label* done,
7609 Variable* var_numeric,
7610 Variable* var_feedback) {
7611 var_numeric->Bind(value);
7612 Label if_smi(
this), if_heapnumber(
this), if_bigint(
this), if_oddball(
this);
7613 GotoIf(TaggedIsSmi(value), &if_smi);
7614 Node* map = LoadMap(value);
7615 GotoIf(IsHeapNumberMap(map), &if_heapnumber);
7616 Node* instance_type = LoadMapInstanceType(map);
7617 GotoIf(IsBigIntInstanceType(instance_type), &if_bigint);
7620 GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)), &if_oddball);
7621 var_numeric->Bind(CallBuiltin(Builtins::kNonNumberToNumeric, context, value));
7622 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kAny);
7626 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
7629 BIND(&if_heapnumber);
7630 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kNumber);
7634 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kBigInt);
7638 OverwriteFeedback(var_feedback, BinaryOperationFeedback::kNumberOrOddball);
7639 var_numeric->Bind(LoadObjectField(value, Oddball::kToNumberOffset));
7644 TNode<Number> CodeStubAssembler::ToUint32(SloppyTNode<Context> context,
7645 SloppyTNode<Object> input) {
7646 Node*
const float_zero = Float64Constant(0.0);
7647 Node*
const float_two_32 = Float64Constant(static_cast<double>(1ULL << 32));
7651 VARIABLE(var_result, MachineRepresentation::kTagged, input);
7657 Label next(
this, Label::kDeferred);
7658 Branch(TaggedIsPositiveSmi(input), &out, &next);
7662 Node*
const number = ToNumber(context, input);
7663 var_result.Bind(number);
7667 Label next(
this, Label::kDeferred);
7668 Branch(TaggedIsPositiveSmi(number), &out, &next);
7672 Label if_isnegativesmi(
this), if_isheapnumber(
this);
7673 Branch(TaggedIsSmi(number), &if_isnegativesmi, &if_isheapnumber);
7675 BIND(&if_isnegativesmi);
7677 Node*
const uint32_value = SmiToInt32(number);
7678 Node* float64_value = ChangeUint32ToFloat64(uint32_value);
7679 var_result.Bind(AllocateHeapNumberWithValue(float64_value));
7683 BIND(&if_isheapnumber);
7685 Label return_zero(
this);
7686 Node*
const value = LoadHeapNumberValue(number);
7691 Branch(Float64Equal(value, float_zero), &return_zero, &next);
7698 Branch(Float64Equal(value, value), &next, &return_zero);
7705 Node*
const positive_infinity =
7706 Float64Constant(std::numeric_limits<double>::infinity());
7707 Branch(Float64Equal(value, positive_infinity), &return_zero, &next);
7714 Node*
const negative_infinity =
7715 Float64Constant(-1.0 * std::numeric_limits<double>::infinity());
7716 Branch(Float64Equal(value, negative_infinity), &return_zero, &next);
7725 Node* x = Float64Trunc(value);
7726 x = Float64Mod(x, float_two_32);
7727 x = Float64Add(x, float_two_32);
7728 x = Float64Mod(x, float_two_32);
7730 Node*
const result = ChangeFloat64ToTagged(x);
7731 var_result.Bind(result);
7737 var_result.Bind(SmiConstant(0));
7743 return CAST(var_result.value());
7746 TNode<String> CodeStubAssembler::ToString(SloppyTNode<Context> context,
7747 SloppyTNode<Object> input) {
7748 Label is_number(
this);
7749 Label runtime(
this, Label::kDeferred), done(
this);
7750 VARIABLE(result, MachineRepresentation::kTagged);
7751 GotoIf(TaggedIsSmi(input), &is_number);
7753 TNode<Map> input_map = LoadMap(CAST(input));
7754 TNode<Int32T> input_instance_type = LoadMapInstanceType(input_map);
7757 GotoIf(IsStringInstanceType(input_instance_type), &done);
7759 Label not_heap_number(
this);
7760 Branch(IsHeapNumberMap(input_map), &is_number, ¬_heap_number);
7763 TNode<Number> number_input = CAST(input);
7764 result.Bind(NumberToString(number_input));
7767 BIND(¬_heap_number);
7769 GotoIfNot(InstanceTypeEqual(input_instance_type, ODDBALL_TYPE), &runtime);
7770 result.Bind(LoadObjectField(CAST(input), Oddball::kToStringOffset));
7776 result.Bind(CallRuntime(Runtime::kToString, context, input));
7781 return CAST(result.value());
7784 TNode<String> CodeStubAssembler::ToString_Inline(SloppyTNode<Context> context,
7785 SloppyTNode<Object> input) {
7786 VARIABLE(var_result, MachineRepresentation::kTagged, input);
7787 Label stub_call(
this, Label::kDeferred), out(
this);
7789 GotoIf(TaggedIsSmi(input), &stub_call);
7790 Branch(IsString(CAST(input)), &out, &stub_call);
7793 var_result.Bind(CallBuiltin(Builtins::kToString, context, input));
7797 return CAST(var_result.value());
7800 Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) {
7801 Label if_isreceiver(
this, Label::kDeferred), if_isnotreceiver(
this);
7802 VARIABLE(result, MachineRepresentation::kTagged);
7803 Label done(
this, &result);
7805 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver);
7807 BIND(&if_isreceiver);
7810 Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
7811 result.Bind(CallStub(callable, context, input));
7815 BIND(&if_isnotreceiver);
7822 return result.value();
7825 TNode<JSReceiver> CodeStubAssembler::ToObject(SloppyTNode<Context> context,
7826 SloppyTNode<Object> input) {
7827 return CAST(CallBuiltin(Builtins::kToObject, context, input));
7830 TNode<JSReceiver> CodeStubAssembler::ToObject_Inline(TNode<Context> context,
7831 TNode<Object> input) {
7832 TVARIABLE(JSReceiver, result);
7833 Label if_isreceiver(
this), if_isnotreceiver(
this, Label::kDeferred);
7836 BranchIfJSReceiver(input, &if_isreceiver, &if_isnotreceiver);
7838 BIND(&if_isreceiver);
7840 result = CAST(input);
7844 BIND(&if_isnotreceiver);
7846 result = ToObject(context, input);
7851 return result.value();
7854 TNode<Smi> CodeStubAssembler::ToSmiIndex(TNode<Object> input,
7855 TNode<Context> context,
7856 Label* range_error) {
7857 TVARIABLE(Smi, result);
7858 Label check_undefined(
this), return_zero(
this), defined(
this),
7859 negative_check(
this), done(
this);
7861 GotoIfNot(TaggedIsSmi(input), &check_undefined);
7862 result = CAST(input);
7863 Goto(&negative_check);
7865 BIND(&check_undefined);
7866 Branch(IsUndefined(input), &return_zero, &defined);
7869 TNode<Number> integer_input =
7870 CAST(CallBuiltin(Builtins::kToInteger_TruncateMinusZero, context, input));
7871 GotoIfNot(TaggedIsSmi(integer_input), range_error);
7872 result = CAST(integer_input);
7873 Goto(&negative_check);
7875 BIND(&negative_check);
7876 Branch(SmiLessThan(result.value(), SmiConstant(0)), range_error, &done);
7879 result = SmiConstant(0);
7883 return result.value();
7886 TNode<Smi> CodeStubAssembler::ToSmiLength(TNode<Object> input,
7887 TNode<Context> context,
7888 Label* range_error) {
7889 TVARIABLE(Smi, result);
7890 Label to_integer(
this), negative_check(
this),
7891 heap_number_negative_check(
this), return_zero(
this), done(
this);
7893 GotoIfNot(TaggedIsSmi(input), &to_integer);
7894 result = CAST(input);
7895 Goto(&negative_check);
7899 TNode<Number> integer_input = CAST(
7900 CallBuiltin(Builtins::kToInteger_TruncateMinusZero, context, input));
7901 GotoIfNot(TaggedIsSmi(integer_input), &heap_number_negative_check);
7902 result = CAST(integer_input);
7903 Goto(&negative_check);
7906 BIND(&heap_number_negative_check);
7907 TNode<HeapNumber> heap_number_input = CAST(integer_input);
7908 Branch(IsTrue(CallBuiltin(Builtins::kLessThan, context, heap_number_input,
7910 &return_zero, range_error);
7913 BIND(&negative_check);
7914 Branch(SmiLessThan(result.value(), SmiConstant(0)), &return_zero, &done);
7917 result = SmiConstant(0);
7921 return result.value();
7924 TNode<Number> CodeStubAssembler::ToLength_Inline(SloppyTNode<Context> context,
7925 SloppyTNode<Object> input) {
7926 TNode<Smi> smi_zero = SmiConstant(0);
7927 return Select<Number>(
7928 TaggedIsSmi(input), [=] {
return SmiMax(CAST(input), smi_zero); },
7929 [=] {
return CAST(CallBuiltin(Builtins::kToLength, context, input)); });
7932 TNode<Number> CodeStubAssembler::ToInteger_Inline(
7933 SloppyTNode<Context> context, SloppyTNode<Object> input,
7934 ToIntegerTruncationMode mode) {
7935 Builtins::Name builtin = (mode == kNoTruncation)
7936 ? Builtins::kToInteger
7937 : Builtins::kToInteger_TruncateMinusZero;
7938 return Select<Number>(
7939 TaggedIsSmi(input), [=] {
return CAST(input); },
7940 [=] {
return CAST(CallBuiltin(builtin, context, input)); });
7943 TNode<Number> CodeStubAssembler::ToInteger(SloppyTNode<Context> context,
7944 SloppyTNode<Object> input,
7945 ToIntegerTruncationMode mode) {
7947 TVARIABLE(Object, var_arg, input);
7948 Label loop(
this, &var_arg), out(
this);
7953 Label return_zero(
this, Label::kDeferred);
7956 TNode<Object> arg = var_arg.value();
7959 GotoIf(TaggedIsSmi(arg), &out);
7962 Label if_argisheapnumber(
this),
7963 if_argisnotheapnumber(
this, Label::kDeferred);
7964 Branch(IsHeapNumber(CAST(arg)), &if_argisheapnumber,
7965 &if_argisnotheapnumber);
7967 BIND(&if_argisheapnumber);
7969 TNode<HeapNumber> arg_hn = CAST(arg);
7971 Node* arg_value = LoadHeapNumberValue(arg_hn);
7974 GotoIfNot(Float64Equal(arg_value, arg_value), &return_zero);
7977 TNode<Float64T> value = Float64Trunc(arg_value);
7979 if (mode == kTruncateMinusZero) {
7981 GotoIf(Float64Equal(value, Float64Constant(0.0)), &return_zero);
7984 var_arg = ChangeFloat64ToTagged(value);
7988 BIND(&if_argisnotheapnumber);
7991 var_arg = UncheckedCast<Object>(
7992 CallBuiltin(Builtins::kNonNumberToNumber, context, arg));
7997 var_arg = SmiConstant(0);
8002 if (mode == kTruncateMinusZero) {
8003 CSA_ASSERT(
this, IsNumberNormalized(CAST(var_arg.value())));
8005 return CAST(var_arg.value());
8008 TNode<Uint32T> CodeStubAssembler::DecodeWord32(SloppyTNode<Word32T> word32,
8010 return UncheckedCast<Uint32T>(Word32Shr(
8011 Word32And(word32, Int32Constant(mask)), static_cast<int>(shift)));
8014 TNode<UintPtrT> CodeStubAssembler::DecodeWord(SloppyTNode<WordT> word,
8017 WordShr(WordAnd(word, IntPtrConstant(mask)), static_cast<int>(shift)));
8020 TNode<WordT> CodeStubAssembler::UpdateWord(TNode<WordT> word,
8021 TNode<WordT> value,
uint32_t shift,
8023 TNode<WordT> encoded_value = WordShl(value, static_cast<int>(shift));
8024 TNode<IntPtrT> inverted_mask = IntPtrConstant(~static_cast<intptr_t>(mask));
8026 CSA_ASSERT(
this, WordEqual(WordAnd(encoded_value, inverted_mask),
8027 IntPtrConstant(0)));
8028 return WordOr(WordAnd(word, inverted_mask), encoded_value);
8031 void CodeStubAssembler::SetCounter(StatsCounter* counter,
int value) {
8032 if (FLAG_native_code_counters && counter->Enabled()) {
8033 Node* counter_address =
8034 ExternalConstant(ExternalReference::Create(counter));
8035 StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address,
8036 Int32Constant(value));
8040 void CodeStubAssembler::IncrementCounter(StatsCounter* counter,
int delta) {
8041 DCHECK_GT(delta, 0);
8042 if (FLAG_native_code_counters && counter->Enabled()) {
8043 Node* counter_address =
8044 ExternalConstant(ExternalReference::Create(counter));
8045 Node* value = Load(MachineType::Int32(), counter_address);
8046 value = Int32Add(value, Int32Constant(delta));
8047 StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value);
8051 void CodeStubAssembler::DecrementCounter(StatsCounter* counter,
int delta) {
8052 DCHECK_GT(delta, 0);
8053 if (FLAG_native_code_counters && counter->Enabled()) {
8054 Node* counter_address =
8055 ExternalConstant(ExternalReference::Create(counter));
8056 Node* value = Load(MachineType::Int32(), counter_address);
8057 value = Int32Sub(value, Int32Constant(delta));
8058 StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value);
8062 void CodeStubAssembler::Increment(Variable* variable,
int value,
8063 ParameterMode mode) {
8064 DCHECK_IMPLIES(mode == INTPTR_PARAMETERS,
8065 variable->rep() == MachineType::PointerRepresentation());
8066 DCHECK_IMPLIES(mode == SMI_PARAMETERS,
8067 variable->rep() == MachineRepresentation::kTagged ||
8068 variable->rep() == MachineRepresentation::kTaggedSigned);
8069 variable->Bind(IntPtrOrSmiAdd(variable->value(),
8070 IntPtrOrSmiConstant(value, mode), mode));
8073 void CodeStubAssembler::Use(Label* label) {
8074 GotoIf(Word32Equal(Int32Constant(0), Int32Constant(1)), label);
8077 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex,
8078 Variable* var_index, Label* if_keyisunique,
8079 Variable* var_unique, Label* if_bailout,
8080 Label* if_notinternalized) {
8081 DCHECK_EQ(MachineType::PointerRepresentation(), var_index->rep());
8082 DCHECK_EQ(MachineRepresentation::kTagged, var_unique->rep());
8083 Comment(
"TryToName");
8085 Label if_hascachedindex(
this), if_keyisnotindex(
this), if_thinstring(
this),
8086 if_keyisother(
this, Label::kDeferred);
8088 var_index->Bind(TryToIntptr(key, &if_keyisnotindex));
8089 Goto(if_keyisindex);
8091 BIND(&if_keyisnotindex);
8092 Node* key_map = LoadMap(key);
8093 var_unique->Bind(key);
8095 GotoIf(IsSymbolMap(key_map), if_keyisunique);
8096 Node* key_instance_type = LoadMapInstanceType(key_map);
8098 STATIC_ASSERT(FIRST_NAME_TYPE == FIRST_TYPE);
8099 GotoIfNot(IsStringInstanceType(key_instance_type), &if_keyisother);
8102 Node* hash = LoadNameHashField(key);
8103 GotoIf(IsClearWord32(hash, Name::kDoesNotContainCachedArrayIndexMask),
8104 &if_hascachedindex);
8107 GotoIf(IsClearWord32(hash, Name::kIsNotArrayIndexMask), if_bailout);
8109 GotoIf(InstanceTypeEqual(key_instance_type, THIN_STRING_TYPE),
8111 GotoIf(InstanceTypeEqual(key_instance_type, THIN_ONE_BYTE_STRING_TYPE),
8114 STATIC_ASSERT(kNotInternalizedTag != 0);
8115 GotoIf(IsSetWord32(key_instance_type, kIsNotInternalizedMask),
8116 if_notinternalized !=
nullptr ? if_notinternalized : if_bailout);
8117 Goto(if_keyisunique);
8119 BIND(&if_thinstring);
8120 var_unique->Bind(LoadObjectField(key, ThinString::kActualOffset));
8121 Goto(if_keyisunique);
8123 BIND(&if_hascachedindex);
8124 var_index->Bind(DecodeWordFromWord32<Name::ArrayIndexValueBits>(hash));
8125 Goto(if_keyisindex);
8127 BIND(&if_keyisother);
8128 GotoIfNot(InstanceTypeEqual(key_instance_type, ODDBALL_TYPE), if_bailout);
8129 var_unique->Bind(LoadObjectField(key, Oddball::kToStringOffset));
8130 Goto(if_keyisunique);
8133 void CodeStubAssembler::TryInternalizeString(
8134 Node*
string, Label* if_index, Variable* var_index, Label* if_internalized,
8135 Variable* var_internalized, Label* if_not_internalized, Label* if_bailout) {
8136 DCHECK(var_index->rep() == MachineType::PointerRepresentation());
8137 DCHECK_EQ(var_internalized->rep(), MachineRepresentation::kTagged);
8138 CSA_SLOW_ASSERT(
this, IsString(
string));
8140 ExternalConstant(ExternalReference::try_internalize_string_function());
8141 Node*
const isolate_ptr =
8142 ExternalConstant(ExternalReference::isolate_address(isolate()));
8144 CallCFunction2(MachineType::AnyTagged(), MachineType::Pointer(),
8145 MachineType::AnyTagged(),
function, isolate_ptr,
string);
8146 Label internalized(
this);
8147 GotoIf(TaggedIsNotSmi(result), &internalized);
8148 Node* word_result = SmiUntag(result);
8149 GotoIf(WordEqual(word_result, IntPtrConstant(ResultSentinel::kNotFound)),
8150 if_not_internalized);
8151 GotoIf(WordEqual(word_result, IntPtrConstant(ResultSentinel::kUnsupported)),
8153 var_index->Bind(word_result);
8156 BIND(&internalized);
8157 var_internalized->Bind(result);
8158 Goto(if_internalized);
8161 template <
typename Dictionary>
8162 TNode<IntPtrT> CodeStubAssembler::EntryToIndex(TNode<IntPtrT> entry,
8164 TNode<IntPtrT> entry_index =
8165 IntPtrMul(entry, IntPtrConstant(Dictionary::kEntrySize));
8166 return IntPtrAdd(entry_index, IntPtrConstant(Dictionary::kElementsStartIndex +
8170 TNode<MaybeObject> CodeStubAssembler::LoadDescriptorArrayElement(
8171 TNode<DescriptorArray>
object, Node* index,
int additional_offset) {
8172 return LoadArrayElement(
object, DescriptorArray::kHeaderSize, index,
8176 TNode<Name> CodeStubAssembler::LoadKeyByKeyIndex(
8177 TNode<DescriptorArray> container, TNode<IntPtrT> key_index) {
8178 return CAST(LoadDescriptorArrayElement(container, key_index, 0));
8181 TNode<Uint32T> CodeStubAssembler::LoadDetailsByKeyIndex(
8182 TNode<DescriptorArray> container, TNode<IntPtrT> key_index) {
8183 const int kKeyToDetails =
8184 DescriptorArray::ToDetailsIndex(0) - DescriptorArray::ToKeyIndex(0);
8185 return Unsigned(LoadAndUntagToWord32ArrayElement(
8186 container, DescriptorArray::kHeaderSize, key_index,
8187 kKeyToDetails * kPointerSize));
8190 TNode<Object> CodeStubAssembler::LoadValueByKeyIndex(
8191 TNode<DescriptorArray> container, TNode<IntPtrT> key_index) {
8192 const int kKeyToValue =
8193 DescriptorArray::ToValueIndex(0) - DescriptorArray::ToKeyIndex(0);
8194 return CAST(LoadDescriptorArrayElement(container, key_index,
8195 kKeyToValue * kPointerSize));
8198 TNode<MaybeObject> CodeStubAssembler::LoadFieldTypeByKeyIndex(
8199 TNode<DescriptorArray> container, TNode<IntPtrT> key_index) {
8200 const int kKeyToValue =
8201 DescriptorArray::ToValueIndex(0) - DescriptorArray::ToKeyIndex(0);
8202 return LoadDescriptorArrayElement(container, key_index,
8203 kKeyToValue * kPointerSize);
8206 TNode<IntPtrT> CodeStubAssembler::DescriptorEntryToIndex(
8207 TNode<IntPtrT> descriptor_entry) {
8208 return IntPtrMul(descriptor_entry,
8209 IntPtrConstant(DescriptorArray::kEntrySize));
8212 TNode<Name> CodeStubAssembler::LoadKeyByDescriptorEntry(
8213 TNode<DescriptorArray> container, TNode<IntPtrT> descriptor_entry) {
8214 return CAST(LoadDescriptorArrayElement(
8215 container, DescriptorEntryToIndex(descriptor_entry),
8216 DescriptorArray::ToKeyIndex(0) * kPointerSize));
8219 TNode<Name> CodeStubAssembler::LoadKeyByDescriptorEntry(
8220 TNode<DescriptorArray> container,
int descriptor_entry) {
8221 return CAST(LoadDescriptorArrayElement(
8222 container, IntPtrConstant(0),
8223 DescriptorArray::ToKeyIndex(descriptor_entry) * kPointerSize));
8226 TNode<Uint32T> CodeStubAssembler::LoadDetailsByDescriptorEntry(
8227 TNode<DescriptorArray> container, TNode<IntPtrT> descriptor_entry) {
8228 return Unsigned(LoadAndUntagToWord32ArrayElement(
8229 container, DescriptorArray::kHeaderSize,
8230 DescriptorEntryToIndex(descriptor_entry),
8231 DescriptorArray::ToDetailsIndex(0) * kPointerSize));
8234 TNode<Uint32T> CodeStubAssembler::LoadDetailsByDescriptorEntry(
8235 TNode<DescriptorArray> container,
int descriptor_entry) {
8236 return Unsigned(LoadAndUntagToWord32ArrayElement(
8237 container, DescriptorArray::kHeaderSize, IntPtrConstant(0),
8238 DescriptorArray::ToDetailsIndex(descriptor_entry) * kPointerSize));
8241 TNode<Object> CodeStubAssembler::LoadValueByDescriptorEntry(
8242 TNode<DescriptorArray> container,
int descriptor_entry) {
8243 return CAST(LoadDescriptorArrayElement(
8244 container, IntPtrConstant(0),
8245 DescriptorArray::ToValueIndex(descriptor_entry) * kPointerSize));
8248 TNode<MaybeObject> CodeStubAssembler::LoadFieldTypeByDescriptorEntry(
8249 TNode<DescriptorArray> container, TNode<IntPtrT> descriptor_entry) {
8250 return LoadDescriptorArrayElement(
8251 container, DescriptorEntryToIndex(descriptor_entry),
8252 DescriptorArray::ToValueIndex(0) * kPointerSize);
8255 template TNode<IntPtrT> CodeStubAssembler::EntryToIndex<NameDictionary>(
8256 TNode<IntPtrT>,
int);
8257 template TNode<IntPtrT> CodeStubAssembler::EntryToIndex<GlobalDictionary>(
8258 TNode<IntPtrT>,
int);
8259 template TNode<IntPtrT> CodeStubAssembler::EntryToIndex<NumberDictionary>(
8260 TNode<IntPtrT>,
int);
8263 TNode<IntPtrT> CodeStubAssembler::HashTableComputeCapacity(
8264 TNode<IntPtrT> at_least_space_for) {
8265 TNode<IntPtrT> capacity = IntPtrRoundUpToPowerOfTwo32(
8266 IntPtrAdd(at_least_space_for, WordShr(at_least_space_for, 1)));
8267 return IntPtrMax(capacity, IntPtrConstant(HashTableBase::kMinCapacity));
8270 TNode<IntPtrT> CodeStubAssembler::IntPtrMax(SloppyTNode<IntPtrT> left,
8271 SloppyTNode<IntPtrT> right) {
8272 intptr_t left_constant;
8273 intptr_t right_constant;
8274 if (ToIntPtrConstant(left, left_constant) &&
8275 ToIntPtrConstant(right, right_constant)) {
8276 return IntPtrConstant(std::max(left_constant, right_constant));
8278 return SelectConstant<IntPtrT>(IntPtrGreaterThanOrEqual(left, right), left,
8282 TNode<IntPtrT> CodeStubAssembler::IntPtrMin(SloppyTNode<IntPtrT> left,
8283 SloppyTNode<IntPtrT> right) {
8284 intptr_t left_constant;
8285 intptr_t right_constant;
8286 if (ToIntPtrConstant(left, left_constant) &&
8287 ToIntPtrConstant(right, right_constant)) {
8288 return IntPtrConstant(std::min(left_constant, right_constant));
8290 return SelectConstant<IntPtrT>(IntPtrLessThanOrEqual(left, right), left,
8295 TNode<HeapObject> CodeStubAssembler::LoadName<NameDictionary>(
8296 TNode<HeapObject> key) {
8297 CSA_ASSERT(
this, Word32Or(IsTheHole(key), IsName(key)));
8302 TNode<HeapObject> CodeStubAssembler::LoadName<GlobalDictionary>(
8303 TNode<HeapObject> key) {
8304 TNode<PropertyCell> property_cell = CAST(key);
8305 return CAST(LoadObjectField(property_cell, PropertyCell::kNameOffset));
8308 template <
typename Dictionary>
8309 void CodeStubAssembler::NameDictionaryLookup(
8310 TNode<Dictionary> dictionary, TNode<Name> unique_name, Label* if_found,
8311 TVariable<IntPtrT>* var_name_index, Label* if_not_found,
int inlined_probes,
8313 static_assert(std::is_same<Dictionary, NameDictionary>::value ||
8314 std::is_same<Dictionary, GlobalDictionary>::value,
8315 "Unexpected NameDictionary");
8316 DCHECK_EQ(MachineType::PointerRepresentation(), var_name_index->rep());
8317 DCHECK_IMPLIES(mode == kFindInsertionIndex,
8318 inlined_probes == 0 && if_found ==
nullptr);
8319 Comment(
"NameDictionaryLookup");
8321 TNode<IntPtrT> capacity = SmiUntag(GetCapacity<Dictionary>(dictionary));
8322 TNode<WordT> mask = IntPtrSub(capacity, IntPtrConstant(1));
8323 TNode<WordT> hash = ChangeUint32ToWord(LoadNameHash(unique_name));
8326 TNode<IntPtrT> count = IntPtrConstant(0);
8327 TNode<IntPtrT> entry = Signed(WordAnd(hash, mask));
8328 Node* undefined = UndefinedConstant();
8330 for (
int i = 0;
i < inlined_probes;
i++) {
8331 TNode<IntPtrT> index = EntryToIndex<Dictionary>(entry);
8332 *var_name_index = index;
8334 TNode<HeapObject> current = CAST(LoadFixedArrayElement(dictionary, index));
8335 GotoIf(WordEqual(current, undefined), if_not_found);
8336 current = LoadName<Dictionary>(current);
8337 GotoIf(WordEqual(current, unique_name), if_found);
8340 count = IntPtrConstant(
i + 1);
8341 entry = Signed(WordAnd(IntPtrAdd(entry, count), mask));
8343 if (mode == kFindInsertionIndex) {
8345 *var_name_index = IntPtrConstant(0);
8348 TVARIABLE(IntPtrT, var_count, count);
8349 TVARIABLE(IntPtrT, var_entry, entry);
8350 Variable* loop_vars[] = {&var_count, &var_entry, var_name_index};
8351 Label loop(
this, 3, loop_vars);
8355 TNode<IntPtrT> entry = var_entry.value();
8357 TNode<IntPtrT> index = EntryToIndex<Dictionary>(entry);
8358 *var_name_index = index;
8360 TNode<HeapObject> current = CAST(LoadFixedArrayElement(dictionary, index));
8361 GotoIf(WordEqual(current, undefined), if_not_found);
8362 if (mode == kFindExisting) {
8363 current = LoadName<Dictionary>(current);
8364 GotoIf(WordEqual(current, unique_name), if_found);
8366 DCHECK_EQ(kFindInsertionIndex, mode);
8367 GotoIf(WordEqual(current, TheHoleConstant()), if_not_found);
8371 Increment(&var_count);
8372 entry = Signed(WordAnd(IntPtrAdd(entry, var_count.value()), mask));
8380 template void CodeStubAssembler::NameDictionaryLookup<NameDictionary>(
8381 TNode<NameDictionary>, TNode<Name>, Label*, TVariable<IntPtrT>*, Label*,
8383 template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>(
8384 TNode<GlobalDictionary>, TNode<Name>, Label*, TVariable<IntPtrT>*, Label*,
8387 Node* CodeStubAssembler::ComputeUnseededHash(Node* key) {
8389 Node* hash = TruncateIntPtrToInt32(key);
8390 hash = Int32Add(Word32Xor(hash, Int32Constant(0xFFFFFFFF)),
8391 Word32Shl(hash, Int32Constant(15)));
8392 hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12)));
8393 hash = Int32Add(hash, Word32Shl(hash, Int32Constant(2)));
8394 hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(4)));
8395 hash = Int32Mul(hash, Int32Constant(2057));
8396 hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(16)));
8397 return Word32And(hash, Int32Constant(0x3FFFFFFF));
8400 Node* CodeStubAssembler::ComputeSeededHash(Node* key) {
8401 Node*
const function_addr =
8402 ExternalConstant(ExternalReference::compute_integer_hash());
8403 Node*
const isolate_ptr =
8404 ExternalConstant(ExternalReference::isolate_address(isolate()));
8406 MachineType type_ptr = MachineType::Pointer();
8407 MachineType type_uint32 = MachineType::Uint32();
8409 Node*
const result =
8410 CallCFunction2(type_uint32, type_ptr, type_uint32, function_addr,
8411 isolate_ptr, TruncateIntPtrToInt32(key));
8415 void CodeStubAssembler::NumberDictionaryLookup(
8416 TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
8417 Label* if_found, TVariable<IntPtrT>* var_entry, Label* if_not_found) {
8418 CSA_ASSERT(
this, IsNumberDictionary(dictionary));
8419 DCHECK_EQ(MachineType::PointerRepresentation(), var_entry->rep());
8420 Comment(
"NumberDictionaryLookup");
8422 TNode<IntPtrT> capacity = SmiUntag(GetCapacity<NumberDictionary>(dictionary));
8423 TNode<WordT> mask = IntPtrSub(capacity, IntPtrConstant(1));
8425 TNode<WordT> hash = ChangeUint32ToWord(ComputeSeededHash(intptr_index));
8426 Node* key_as_float64 = RoundIntPtrToFloat64(intptr_index);
8429 TNode<IntPtrT> count = IntPtrConstant(0);
8430 TNode<IntPtrT> entry = Signed(WordAnd(hash, mask));
8432 Node* undefined = UndefinedConstant();
8433 Node* the_hole = TheHoleConstant();
8435 TVARIABLE(IntPtrT, var_count, count);
8436 Variable* loop_vars[] = {&var_count, var_entry};
8437 Label loop(
this, 2, loop_vars);
8442 TNode<IntPtrT> entry = var_entry->value();
8444 TNode<IntPtrT> index = EntryToIndex<NumberDictionary>(entry);
8445 Node* current = LoadFixedArrayElement(dictionary, index);
8446 GotoIf(WordEqual(current, undefined), if_not_found);
8447 Label next_probe(
this);
8449 Label if_currentissmi(
this), if_currentisnotsmi(
this);
8450 Branch(TaggedIsSmi(current), &if_currentissmi, &if_currentisnotsmi);
8451 BIND(&if_currentissmi);
8453 Node* current_value = SmiUntag(current);
8454 Branch(WordEqual(current_value, intptr_index), if_found, &next_probe);
8456 BIND(&if_currentisnotsmi);
8458 GotoIf(WordEqual(current, the_hole), &next_probe);
8460 Node* current_value = LoadHeapNumberValue(current);
8461 Branch(Float64Equal(current_value, key_as_float64), if_found,
8468 Increment(&var_count);
8469 entry = Signed(WordAnd(IntPtrAdd(entry, var_count.value()), mask));
8476 TNode<Object> CodeStubAssembler::BasicLoadNumberDictionaryElement(
8477 TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
8478 Label* not_data, Label* if_hole) {
8479 TVARIABLE(IntPtrT, var_entry);
8480 Label if_found(
this);
8481 NumberDictionaryLookup(dictionary, intptr_index, &if_found, &var_entry,
8486 TNode<IntPtrT> index = EntryToIndex<NumberDictionary>(var_entry.value());
8487 TNode<Uint32T> details =
8488 LoadDetailsByKeyIndex<NumberDictionary>(dictionary, index);
8489 TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
8491 GotoIfNot(Word32Equal(kind, Int32Constant(kData)), not_data);
8493 return LoadValueByKeyIndex<NumberDictionary>(dictionary, index);
8496 void CodeStubAssembler::BasicStoreNumberDictionaryElement(
8497 TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
8498 TNode<Object> value, Label* not_data, Label* if_hole, Label* read_only) {
8499 TVARIABLE(IntPtrT, var_entry);
8500 Label if_found(
this);
8501 NumberDictionaryLookup(dictionary, intptr_index, &if_found, &var_entry,
8506 TNode<IntPtrT> index = EntryToIndex<NumberDictionary>(var_entry.value());
8507 TNode<Uint32T> details =
8508 LoadDetailsByKeyIndex<NumberDictionary>(dictionary, index);
8509 TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
8511 GotoIfNot(Word32Equal(kind, Int32Constant(kData)), not_data);
8514 GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
8518 StoreValueByKeyIndex<NumberDictionary>(dictionary, index, value);
8521 template <
class Dictionary>
8522 void CodeStubAssembler::FindInsertionEntry(TNode<Dictionary> dictionary,
8524 TVariable<IntPtrT>* var_key_index) {
8529 void CodeStubAssembler::FindInsertionEntry<NameDictionary>(
8530 TNode<NameDictionary> dictionary, TNode<Name> key,
8531 TVariable<IntPtrT>* var_key_index) {
8533 NameDictionaryLookup<NameDictionary>(dictionary, key,
nullptr, var_key_index,
8534 &done, 0, kFindInsertionIndex);
8538 template <
class Dictionary>
8539 void CodeStubAssembler::InsertEntry(TNode<Dictionary> dictionary,
8540 TNode<Name> key, TNode<Object> value,
8541 TNode<IntPtrT> index,
8542 TNode<Smi> enum_index) {
8547 void CodeStubAssembler::InsertEntry<NameDictionary>(
8548 TNode<NameDictionary> dictionary, TNode<Name> name, TNode<Object> value,
8549 TNode<IntPtrT> index, TNode<Smi> enum_index) {
8551 StoreFixedArrayElement(dictionary, index, name);
8552 StoreValueByKeyIndex<NameDictionary>(dictionary, index, value);
8555 PropertyDetails d(kData, NONE, PropertyCellType::kNoCell);
8557 SmiShl(enum_index, PropertyDetails::DictionaryStorageField::kShift);
8559 DCHECK_EQ(0, d.dictionary_index());
8560 TVARIABLE(Smi, var_details, SmiOr(SmiConstant(d.AsSmi()), enum_index));
8563 Label not_private(
this, &var_details);
8564 GotoIfNot(IsPrivateSymbol(name), ¬_private);
8565 TNode<Smi> dont_enum =
8566 SmiShl(SmiConstant(DONT_ENUM), PropertyDetails::AttributesField::kShift);
8567 var_details = SmiOr(var_details.value(), dont_enum);
8572 StoreDetailsByKeyIndex<NameDictionary>(dictionary, index,
8573 var_details.value());
8577 void CodeStubAssembler::InsertEntry<GlobalDictionary>(
8578 TNode<GlobalDictionary> dictionary, TNode<Name> key, TNode<Object> value,
8579 TNode<IntPtrT> index, TNode<Smi> enum_index) {
8583 template <
class Dictionary>
8584 void CodeStubAssembler::Add(TNode<Dictionary> dictionary, TNode<Name> key,
8585 TNode<Object> value, Label* bailout) {
8586 CSA_ASSERT(
this, Word32BinaryNot(IsEmptyPropertyDictionary(dictionary)));
8587 TNode<Smi> capacity = GetCapacity<Dictionary>(dictionary);
8588 TNode<Smi> nof = GetNumberOfElements<Dictionary>(dictionary);
8589 TNode<Smi> new_nof = SmiAdd(nof, SmiConstant(1));
8593 TNode<Smi> required_capacity_pseudo_smi = SmiAdd(new_nof, SmiShr(new_nof, 1));
8594 GotoIf(SmiBelow(capacity, required_capacity_pseudo_smi), bailout);
8596 TNode<Smi> deleted = GetNumberOfDeletedElements<Dictionary>(dictionary);
8597 CSA_ASSERT(
this, SmiAbove(capacity, new_nof));
8598 TNode<Smi> half_of_free_elements = SmiShr(SmiSub(capacity, new_nof), 1);
8599 GotoIf(SmiAbove(deleted, half_of_free_elements), bailout);
8601 TNode<Smi> enum_index = GetNextEnumerationIndex<Dictionary>(dictionary);
8602 TNode<Smi> new_enum_index = SmiAdd(enum_index, SmiConstant(1));
8603 TNode<Smi> max_enum_index =
8604 SmiConstant(PropertyDetails::DictionaryStorageField::kMax);
8605 GotoIf(SmiAbove(new_enum_index, max_enum_index), bailout);
8610 SetNextEnumerationIndex<Dictionary>(dictionary, new_enum_index);
8611 SetNumberOfElements<Dictionary>(dictionary, new_nof);
8613 TVARIABLE(IntPtrT, var_key_index);
8614 FindInsertionEntry<Dictionary>(dictionary, key, &var_key_index);
8615 InsertEntry<Dictionary>(dictionary, key, value, var_key_index.value(),
8619 template void CodeStubAssembler::Add<NameDictionary>(TNode<NameDictionary>,
8620 TNode<Name>, TNode<Object>,
8623 template <
typename Array>
8624 void CodeStubAssembler::LookupLinear(TNode<Name> unique_name,
8626 TNode<Uint32T> number_of_valid_entries,
8628 TVariable<IntPtrT>* var_name_index,
8629 Label* if_not_found) {
8630 static_assert(std::is_base_of<FixedArray, Array>::value ||
8631 std::is_base_of<WeakFixedArray, Array>::value ||
8632 std::is_base_of<DescriptorArray, Array>::value,
8633 "T must be a descendant of FixedArray or a WeakFixedArray");
8634 Comment(
"LookupLinear");
8635 TNode<IntPtrT> first_inclusive = IntPtrConstant(Array::ToKeyIndex(0));
8636 TNode<IntPtrT> factor = IntPtrConstant(Array::kEntrySize);
8637 TNode<IntPtrT> last_exclusive = IntPtrAdd(
8639 IntPtrMul(ChangeInt32ToIntPtr(number_of_valid_entries), factor));
8641 BuildFastLoop(last_exclusive, first_inclusive,
8642 [=](SloppyTNode<IntPtrT> name_index) {
8643 TNode<MaybeObject> element =
8644 LoadArrayElement(array, Array::kHeaderSize, name_index);
8645 TNode<Name> candidate_name = CAST(element);
8646 *var_name_index = name_index;
8647 GotoIf(WordEqual(candidate_name, unique_name), if_found);
8649 -Array::kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPre);
8654 TNode<Uint32T> CodeStubAssembler::NumberOfEntries<DescriptorArray>(
8655 TNode<DescriptorArray> descriptors) {
8656 return Unsigned(LoadNumberOfDescriptors(descriptors));
8660 TNode<Uint32T> CodeStubAssembler::NumberOfEntries<TransitionArray>(
8661 TNode<TransitionArray> transitions) {
8662 TNode<IntPtrT> length = LoadAndUntagWeakFixedArrayLength(transitions);
8663 return Select<Uint32T>(
8664 UintPtrLessThan(length, IntPtrConstant(TransitionArray::kFirstIndex)),
8665 [=] {
return Unsigned(Int32Constant(0)); },
8667 return Unsigned(LoadAndUntagToWord32ArrayElement(
8668 transitions, WeakFixedArray::kHeaderSize,
8669 IntPtrConstant(TransitionArray::kTransitionLengthIndex)));
8673 template <
typename Array>
8674 TNode<IntPtrT> CodeStubAssembler::EntryIndexToIndex(
8675 TNode<Uint32T> entry_index) {
8676 TNode<Int32T> entry_size = Int32Constant(Array::kEntrySize);
8677 TNode<Word32T> index = Int32Mul(entry_index, entry_size);
8678 return ChangeInt32ToIntPtr(index);
8681 template <
typename Array>
8682 TNode<IntPtrT> CodeStubAssembler::ToKeyIndex(TNode<Uint32T> entry_index) {
8683 return IntPtrAdd(IntPtrConstant(Array::ToKeyIndex(0)),
8684 EntryIndexToIndex<Array>(entry_index));
8687 template TNode<IntPtrT> CodeStubAssembler::ToKeyIndex<DescriptorArray>(
8689 template TNode<IntPtrT> CodeStubAssembler::ToKeyIndex<TransitionArray>(
8693 TNode<Uint32T> CodeStubAssembler::GetSortedKeyIndex<DescriptorArray>(
8694 TNode<DescriptorArray> descriptors, TNode<Uint32T> descriptor_number) {
8695 TNode<Uint32T> details =
8696 DescriptorArrayGetDetails(descriptors, descriptor_number);
8697 return DecodeWord32<PropertyDetails::DescriptorPointer>(details);
8701 TNode<Uint32T> CodeStubAssembler::GetSortedKeyIndex<TransitionArray>(
8702 TNode<TransitionArray> transitions, TNode<Uint32T> transition_number) {
8703 return transition_number;
8706 template <
typename Array>
8707 TNode<Name> CodeStubAssembler::GetKey(TNode<Array> array,
8708 TNode<Uint32T> entry_index) {
8709 static_assert(std::is_base_of<TransitionArray, Array>::value ||
8710 std::is_base_of<DescriptorArray, Array>::value,
8711 "T must be a descendant of DescriptorArray or TransitionArray");
8712 const int key_offset = Array::ToKeyIndex(0) * kPointerSize;
8713 TNode<MaybeObject> element =
8714 LoadArrayElement(array, Array::kHeaderSize,
8715 EntryIndexToIndex<Array>(entry_index), key_offset);
8716 return CAST(element);
8719 template TNode<Name> CodeStubAssembler::GetKey<DescriptorArray>(
8720 TNode<DescriptorArray>, TNode<Uint32T>);
8721 template TNode<Name> CodeStubAssembler::GetKey<TransitionArray>(
8722 TNode<TransitionArray>, TNode<Uint32T>);
8724 TNode<Uint32T> CodeStubAssembler::DescriptorArrayGetDetails(
8725 TNode<DescriptorArray> descriptors, TNode<Uint32T> descriptor_number) {
8726 const int details_offset = DescriptorArray::ToDetailsIndex(0) * kPointerSize;
8727 return Unsigned(LoadAndUntagToWord32ArrayElement(
8728 descriptors, DescriptorArray::kHeaderSize,
8729 EntryIndexToIndex<DescriptorArray>(descriptor_number), details_offset));
8732 template <
typename Array>
8733 void CodeStubAssembler::LookupBinary(TNode<Name> unique_name,
8735 TNode<Uint32T> number_of_valid_entries,
8737 TVariable<IntPtrT>* var_name_index,
8738 Label* if_not_found) {
8739 Comment(
"LookupBinary");
8740 TVARIABLE(Uint32T, var_low, Unsigned(Int32Constant(0)));
8741 TNode<Uint32T> limit =
8742 Unsigned(Int32Sub(NumberOfEntries<Array>(array), Int32Constant(1)));
8743 TVARIABLE(Uint32T, var_high, limit);
8744 TNode<Uint32T> hash = LoadNameHashField(unique_name);
8745 CSA_ASSERT(
this, Word32NotEqual(hash, Int32Constant(0)));
8748 CSA_ASSERT(
this, Uint32LessThanOrEqual(var_low.value(), var_high.value()));
8750 Label binary_loop(
this, {&var_high, &var_low});
8755 TNode<Uint32T> mid = Unsigned(
8756 Int32Add(var_low.value(),
8757 Word32Shr(Int32Sub(var_high.value(), var_low.value()), 1)));
8759 TNode<Uint32T> sorted_key_index = GetSortedKeyIndex<Array>(array, mid);
8760 TNode<Name> mid_name = GetKey<Array>(array, sorted_key_index);
8762 TNode<Uint32T> mid_hash = LoadNameHashField(mid_name);
8764 Label mid_greater(
this), mid_less(
this), merge(
this);
8765 Branch(Uint32GreaterThanOrEqual(mid_hash, hash), &mid_greater, &mid_less);
8773 var_low = Unsigned(Int32Add(mid, Int32Constant(1)));
8777 GotoIf(Word32NotEqual(var_low.value(), var_high.value()), &binary_loop);
8780 Label scan_loop(
this, &var_low);
8784 GotoIf(Int32GreaterThan(var_low.value(), limit), if_not_found);
8786 TNode<Uint32T> sort_index =
8787 GetSortedKeyIndex<Array>(array, var_low.value());
8788 TNode<Name> current_name = GetKey<Array>(array, sort_index);
8789 TNode<Uint32T> current_hash = LoadNameHashField(current_name);
8790 GotoIf(Word32NotEqual(current_hash, hash), if_not_found);
8792 GotoIf(WordNotEqual(current_name, unique_name), &next);
8793 GotoIf(Uint32GreaterThanOrEqual(sort_index, number_of_valid_entries),
8795 *var_name_index = ToKeyIndex<Array>(sort_index);
8799 var_low = Unsigned(Int32Add(var_low.value(), Int32Constant(1)));
8804 void CodeStubAssembler::DescriptorArrayForEach(
8805 VariableList& variable_list, TNode<Uint32T> start_descriptor,
8806 TNode<Uint32T> end_descriptor,
const ForEachDescriptorBodyFunction& body) {
8807 TNode<IntPtrT> start_index = ToKeyIndex<DescriptorArray>(start_descriptor);
8808 TNode<IntPtrT> end_index = ToKeyIndex<DescriptorArray>(end_descriptor);
8810 BuildFastLoop(variable_list, start_index, end_index,
8812 TNode<IntPtrT> descriptor_key_index =
8813 TNode<IntPtrT>::UncheckedCast(index);
8814 body(descriptor_key_index);
8816 DescriptorArray::kEntrySize, INTPTR_PARAMETERS,
8817 IndexAdvanceMode::kPost);
8820 void CodeStubAssembler::ForEachEnumerableOwnProperty(
8821 TNode<Context> context, TNode<Map> map, TNode<JSObject>
object,
8822 const ForEachKeyValueFunction& body, Label* bailout) {
8823 TNode<Int32T> type = LoadMapInstanceType(map);
8824 TNode<Uint32T> bit_field3 = EnsureOnlyHasSimpleProperties(map, type, bailout);
8826 TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
8827 TNode<Uint32T> nof_descriptors =
8828 DecodeWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3);
8830 TVARIABLE(BoolT, var_stable, Int32TrueConstant());
8831 VariableList list({&var_stable}, zone());
8833 DescriptorArrayForEach(
8834 list, Unsigned(Int32Constant(0)), nof_descriptors,
8835 [=, &var_stable](TNode<IntPtrT> descriptor_key_index) {
8836 TNode<Name> next_key =
8837 LoadKeyByKeyIndex(descriptors, descriptor_key_index);
8839 TVARIABLE(Object, var_value, SmiConstant(0));
8840 Label callback(
this), next_iteration(
this);
8843 TVARIABLE(Map, var_map);
8844 TVARIABLE(HeapObject, var_meta_storage);
8845 TVARIABLE(IntPtrT, var_entry);
8846 TVARIABLE(Uint32T, var_details);
8847 Label if_found(
this);
8849 Label if_found_fast(
this), if_found_dict(
this);
8851 Label if_stable(
this), if_not_stable(
this);
8852 Branch(var_stable.value(), &if_stable, &if_not_stable);
8858 var_meta_storage = descriptors;
8859 var_entry = Signed(descriptor_key_index);
8860 Goto(&if_found_fast);
8862 BIND(&if_not_stable);
8867 var_map = LoadMap(
object);
8868 TryLookupPropertyInSimpleObject(
8869 object, var_map.value(), next_key, &if_found_fast,
8870 &if_found_dict, &var_meta_storage, &var_entry, &next_iteration);
8873 BIND(&if_found_fast);
8875 TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
8876 TNode<IntPtrT> name_index = var_entry.value();
8879 var_details = LoadDetailsByKeyIndex(descriptors, name_index);
8880 GotoIf(IsSetWord32(var_details.value(),
8881 PropertyDetails::kAttributesDontEnumMask),
8884 LoadPropertyFromFastObject(
object, var_map.value(), descriptors,
8885 name_index, var_details.value(),
8889 BIND(&if_found_dict);
8891 TNode<NameDictionary> dictionary = CAST(var_meta_storage.value());
8892 TNode<IntPtrT> entry = var_entry.value();
8894 TNode<Uint32T> details =
8895 LoadDetailsByKeyIndex<NameDictionary>(dictionary, entry);
8898 IsSetWord32(details, PropertyDetails::kAttributesDontEnumMask),
8901 var_details = details;
8902 var_value = LoadValueByKeyIndex<NameDictionary>(dictionary, entry);
8909 Label slow_load(
this, Label::kDeferred);
8911 var_value = CallGetterIfAccessor(var_value.value(),
8912 var_details.value(), context,
8913 object, &slow_load, kCallJSGetter);
8918 CallRuntime(Runtime::kGetProperty, context,
object, next_key);
8922 body(next_key, var_value.value());
8927 Select<BoolT>(var_stable.value(),
8928 [=] {
return WordEqual(LoadMap(
object), map); },
8929 [=] {
return Int32FalseConstant(); });
8931 Goto(&next_iteration);
8935 BIND(&next_iteration);
8939 void CodeStubAssembler::DescriptorLookup(
8940 SloppyTNode<Name> unique_name, SloppyTNode<DescriptorArray> descriptors,
8941 SloppyTNode<Uint32T> bitfield3, Label* if_found,
8942 TVariable<IntPtrT>* var_name_index, Label* if_not_found) {
8943 Comment(
"DescriptorArrayLookup");
8944 TNode<Uint32T> nof = DecodeWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
8945 Lookup<DescriptorArray>(unique_name, descriptors, nof, if_found,
8946 var_name_index, if_not_found);
8949 void CodeStubAssembler::TransitionLookup(
8950 SloppyTNode<Name> unique_name, SloppyTNode<TransitionArray> transitions,
8951 Label* if_found, TVariable<IntPtrT>* var_name_index, Label* if_not_found) {
8952 Comment(
"TransitionArrayLookup");
8953 TNode<Uint32T> number_of_valid_transitions =
8954 NumberOfEntries<TransitionArray>(transitions);
8955 Lookup<TransitionArray>(unique_name, transitions, number_of_valid_transitions,
8956 if_found, var_name_index, if_not_found);
8959 template <
typename Array>
8960 void CodeStubAssembler::Lookup(TNode<Name> unique_name, TNode<Array> array,
8961 TNode<Uint32T> number_of_valid_entries,
8963 TVariable<IntPtrT>* var_name_index,
8964 Label* if_not_found) {
8965 Comment(
"ArrayLookup");
8966 if (!number_of_valid_entries) {
8967 number_of_valid_entries = NumberOfEntries(array);
8969 GotoIf(Word32Equal(number_of_valid_entries, Int32Constant(0)), if_not_found);
8970 Label linear_search(
this), binary_search(
this);
8971 const int kMaxElementsForLinearSearch = 32;
8972 Branch(Uint32LessThanOrEqual(number_of_valid_entries,
8973 Int32Constant(kMaxElementsForLinearSearch)),
8974 &linear_search, &binary_search);
8975 BIND(&linear_search);
8977 LookupLinear<Array>(unique_name, array, number_of_valid_entries, if_found,
8978 var_name_index, if_not_found);
8980 BIND(&binary_search);
8982 LookupBinary<Array>(unique_name, array, number_of_valid_entries, if_found,
8983 var_name_index, if_not_found);
8987 TNode<BoolT> CodeStubAssembler::IsSimpleObjectMap(TNode<Map> map) {
8989 Map::HasNamedInterceptorBit::kMask | Map::IsAccessCheckNeededBit::kMask;
8991 return Select<BoolT>(
8992 IsSpecialReceiverInstanceType(LoadMapInstanceType(map)),
8993 [=] {
return Int32FalseConstant(); },
8994 [=] {
return IsClearWord32(LoadMapBitField(map), mask); });
8997 void CodeStubAssembler::TryLookupPropertyInSimpleObject(
8998 TNode<JSObject>
object, TNode<Map> map, TNode<Name> unique_name,
8999 Label* if_found_fast, Label* if_found_dict,
9000 TVariable<HeapObject>* var_meta_storage, TVariable<IntPtrT>* var_name_index,
9001 Label* if_not_found) {
9002 CSA_ASSERT(
this, IsSimpleObjectMap(map));
9004 TNode<Uint32T> bit_field3 = LoadMapBitField3(map);
9005 Label if_isfastmap(
this), if_isslowmap(
this);
9006 Branch(IsSetWord32<Map::IsDictionaryMapBit>(bit_field3), &if_isslowmap,
9008 BIND(&if_isfastmap);
9010 TNode<DescriptorArray> descriptors = LoadMapDescriptors(map);
9011 *var_meta_storage = descriptors;
9013 DescriptorLookup(unique_name, descriptors, bit_field3, if_found_fast,
9014 var_name_index, if_not_found);
9016 BIND(&if_isslowmap);
9018 TNode<NameDictionary> dictionary = CAST(LoadSlowProperties(
object));
9019 *var_meta_storage = dictionary;
9021 NameDictionaryLookup<NameDictionary>(dictionary, unique_name, if_found_dict,
9022 var_name_index, if_not_found);
9026 void CodeStubAssembler::TryLookupProperty(
9027 SloppyTNode<JSObject>
object, SloppyTNode<Map> map,
9028 SloppyTNode<Int32T> instance_type, SloppyTNode<Name> unique_name,
9029 Label* if_found_fast, Label* if_found_dict, Label* if_found_global,
9030 TVariable<HeapObject>* var_meta_storage, TVariable<IntPtrT>* var_name_index,
9031 Label* if_not_found, Label* if_bailout) {
9032 Label if_objectisspecial(
this);
9033 GotoIf(IsSpecialReceiverInstanceType(instance_type), &if_objectisspecial);
9035 TryLookupPropertyInSimpleObject(
object, map, unique_name, if_found_fast,
9036 if_found_dict, var_meta_storage,
9037 var_name_index, if_not_found);
9039 BIND(&if_objectisspecial);
9042 GotoIfNot(InstanceTypeEqual(instance_type, JS_GLOBAL_OBJECT_TYPE),
9046 TNode<Int32T> bit_field = LoadMapBitField(map);
9048 Map::HasNamedInterceptorBit::kMask | Map::IsAccessCheckNeededBit::kMask;
9049 GotoIf(IsSetWord32(bit_field, mask), if_bailout);
9051 TNode<GlobalDictionary> dictionary = CAST(LoadSlowProperties(
object));
9052 *var_meta_storage = dictionary;
9054 NameDictionaryLookup<GlobalDictionary>(
9055 dictionary, unique_name, if_found_global, var_name_index, if_not_found);
9059 void CodeStubAssembler::TryHasOwnProperty(Node*
object, Node* map,
9060 Node* instance_type,
9061 Node* unique_name, Label* if_found,
9062 Label* if_not_found,
9063 Label* if_bailout) {
9064 Comment(
"TryHasOwnProperty");
9065 TVARIABLE(HeapObject, var_meta_storage);
9066 TVARIABLE(IntPtrT, var_name_index);
9068 Label if_found_global(
this);
9069 TryLookupProperty(
object, map, instance_type, unique_name, if_found, if_found,
9070 &if_found_global, &var_meta_storage, &var_name_index,
9071 if_not_found, if_bailout);
9073 BIND(&if_found_global);
9075 VARIABLE(var_value, MachineRepresentation::kTagged);
9076 VARIABLE(var_details, MachineRepresentation::kWord32);
9078 LoadPropertyFromGlobalDictionary(var_meta_storage.value(),
9079 var_name_index.value(), &var_value,
9080 &var_details, if_not_found);
9085 Node* CodeStubAssembler::GetMethod(Node* context, Node*
object,
9087 Label* if_null_or_undefined) {
9088 Node* method = GetProperty(context,
object, name);
9090 GotoIf(IsUndefined(method), if_null_or_undefined);
9091 GotoIf(IsNull(method), if_null_or_undefined);
9096 void CodeStubAssembler::LoadPropertyFromFastObject(
9097 Node*
object, Node* map, TNode<DescriptorArray> descriptors,
9098 Node* name_index, Variable* var_details, Variable* var_value) {
9099 DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep());
9100 DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
9103 LoadDetailsByKeyIndex(descriptors, UncheckedCast<IntPtrT>(name_index));
9104 var_details->Bind(details);
9106 LoadPropertyFromFastObject(
object, map, descriptors, name_index, details,
9110 void CodeStubAssembler::LoadPropertyFromFastObject(
9111 Node*
object, Node* map, TNode<DescriptorArray> descriptors,
9112 Node* name_index, Node* details, Variable* var_value) {
9113 Comment(
"[ LoadPropertyFromFastObject");
9115 Node* location = DecodeWord32<PropertyDetails::LocationField>(details);
9117 Label if_in_field(
this), if_in_descriptor(
this), done(
this);
9118 Branch(Word32Equal(location, Int32Constant(kField)), &if_in_field,
9123 DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
9124 Node* representation =
9125 DecodeWord32<PropertyDetails::RepresentationField>(details);
9128 IntPtrAdd(field_index, LoadMapInobjectPropertiesStartInWords(map));
9129 Node* instance_size_in_words = LoadMapInstanceSizeInWords(map);
9131 Label if_inobject(
this), if_backing_store(
this);
9132 VARIABLE(var_double_value, MachineRepresentation::kFloat64);
9133 Label rebox_double(
this, &var_double_value);
9134 Branch(UintPtrLessThan(field_index, instance_size_in_words), &if_inobject,
9138 Comment(
"if_inobject");
9139 Node* field_offset = TimesPointerSize(field_index);
9141 Label if_double(
this), if_tagged(
this);
9142 Branch(Word32NotEqual(representation,
9143 Int32Constant(Representation::kDouble)),
9144 &if_tagged, &if_double);
9147 var_value->Bind(LoadObjectField(
object, field_offset));
9152 if (FLAG_unbox_double_fields) {
9153 var_double_value.Bind(
9154 LoadObjectField(
object, field_offset, MachineType::Float64()));
9156 Node* mutable_heap_number = LoadObjectField(
object, field_offset);
9157 var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
9159 Goto(&rebox_double);
9162 BIND(&if_backing_store);
9164 Comment(
"if_backing_store");
9165 TNode<HeapObject> properties = LoadFastProperties(
object);
9166 field_index = IntPtrSub(field_index, instance_size_in_words);
9167 Node* value = LoadPropertyArrayElement(CAST(properties), field_index);
9169 Label if_double(
this), if_tagged(
this);
9170 Branch(Word32NotEqual(representation,
9171 Int32Constant(Representation::kDouble)),
9172 &if_tagged, &if_double);
9175 var_value->Bind(value);
9180 var_double_value.Bind(LoadHeapNumberValue(value));
9181 Goto(&rebox_double);
9184 BIND(&rebox_double);
9186 Comment(
"rebox_double");
9187 Node* heap_number = AllocateHeapNumberWithValue(var_double_value.value());
9188 var_value->Bind(heap_number);
9192 BIND(&if_in_descriptor);
9195 LoadValueByKeyIndex(descriptors, UncheckedCast<IntPtrT>(name_index)));
9200 Comment(
"] LoadPropertyFromFastObject");
9203 void CodeStubAssembler::LoadPropertyFromNameDictionary(Node* dictionary,
9205 Variable* var_details,
9206 Variable* var_value) {
9207 Comment(
"LoadPropertyFromNameDictionary");
9208 CSA_ASSERT(
this, IsNameDictionary(dictionary));
9211 LoadDetailsByKeyIndex<NameDictionary>(dictionary, name_index));
9212 var_value->Bind(LoadValueByKeyIndex<NameDictionary>(dictionary, name_index));
9214 Comment(
"] LoadPropertyFromNameDictionary");
9217 void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
9219 Variable* var_details,
9220 Variable* var_value,
9221 Label* if_deleted) {
9222 Comment(
"[ LoadPropertyFromGlobalDictionary");
9223 CSA_ASSERT(
this, IsGlobalDictionary(dictionary));
9225 Node* property_cell = LoadFixedArrayElement(CAST(dictionary), name_index);
9226 CSA_ASSERT(
this, IsPropertyCell(property_cell));
9228 Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
9229 GotoIf(WordEqual(value, TheHoleConstant()), if_deleted);
9231 var_value->Bind(value);
9233 Node* details = LoadAndUntagToWord32ObjectField(property_cell,
9234 PropertyCell::kDetailsOffset);
9235 var_details->Bind(details);
9237 Comment(
"] LoadPropertyFromGlobalDictionary");
9243 TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
9244 Node* value, Node* details, Node* context, Node* receiver,
9245 Label* if_bailout, GetOwnPropertyMode mode) {
9246 VARIABLE(var_value, MachineRepresentation::kTagged, value);
9247 Label done(
this), if_accessor_info(
this, Label::kDeferred);
9249 Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
9250 GotoIf(Word32Equal(kind, Int32Constant(kData)), &done);
9253 GotoIfNot(IsAccessorPair(value), &if_accessor_info);
9257 if (mode == kCallJSGetter) {
9258 Node* accessor_pair = value;
9260 LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
9261 Node* getter_map = LoadMap(getter);
9262 Node* instance_type = LoadMapInstanceType(getter_map);
9264 GotoIf(InstanceTypeEqual(instance_type, FUNCTION_TEMPLATE_INFO_TYPE),
9268 var_value.Bind(UndefinedConstant());
9269 GotoIfNot(IsCallableMap(getter_map), &done);
9272 Callable callable = CodeFactory::Call(isolate());
9273 Node* result = CallJS(callable, context, getter, receiver);
9274 var_value.Bind(result);
9280 BIND(&if_accessor_info);
9282 Node* accessor_info = value;
9283 CSA_ASSERT(
this, IsAccessorInfo(value));
9284 CSA_ASSERT(
this, TaggedIsNotSmi(receiver));
9285 Label if_array(
this), if_function(
this), if_value(
this);
9288 Node* receiver_map = LoadMap(receiver);
9289 Node* receiver_instance_type = LoadMapInstanceType(receiver_map);
9290 GotoIf(IsJSArrayInstanceType(receiver_instance_type), &if_array);
9291 GotoIf(IsJSFunctionInstanceType(receiver_instance_type), &if_function);
9292 Branch(IsJSValueInstanceType(receiver_instance_type), &if_value,
9299 GotoIfNot(IsLengthString(
9300 LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
9302 var_value.Bind(LoadJSArrayLength(receiver));
9310 GotoIfNot(IsPrototypeString(
9311 LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
9314 GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
9316 var_value.Bind(LoadJSFunctionPrototype(receiver, if_bailout));
9324 GotoIfNot(IsLengthString(
9325 LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
9327 Node* receiver_value = LoadJSValueValue(receiver);
9328 GotoIfNot(TaggedIsNotSmi(receiver_value), if_bailout);
9329 GotoIfNot(IsString(receiver_value), if_bailout);
9330 var_value.Bind(LoadStringLengthAsSmi(receiver_value));
9336 return UncheckedCast<Object>(var_value.value());
9339 void CodeStubAssembler::TryGetOwnProperty(
9340 Node* context, Node* receiver, Node*
object, Node* map, Node* instance_type,
9341 Node* unique_name, Label* if_found_value, Variable* var_value,
9342 Label* if_not_found, Label* if_bailout) {
9343 TryGetOwnProperty(context, receiver,
object, map, instance_type, unique_name,
9344 if_found_value, var_value,
nullptr,
nullptr, if_not_found,
9345 if_bailout, kCallJSGetter);
9348 void CodeStubAssembler::TryGetOwnProperty(
9349 Node* context, Node* receiver, Node*
object, Node* map, Node* instance_type,
9350 Node* unique_name, Label* if_found_value, Variable* var_value,
9351 Variable* var_details, Variable* var_raw_value, Label* if_not_found,
9352 Label* if_bailout, GetOwnPropertyMode mode) {
9353 DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
9354 Comment(
"TryGetOwnProperty");
9356 TVARIABLE(HeapObject, var_meta_storage);
9357 TVARIABLE(IntPtrT, var_entry);
9359 Label if_found_fast(
this), if_found_dict(
this), if_found_global(
this);
9361 VARIABLE(local_var_details, MachineRepresentation::kWord32);
9363 var_details = &local_var_details;
9365 Label if_found(
this);
9367 TryLookupProperty(
object, map, instance_type, unique_name, &if_found_fast,
9368 &if_found_dict, &if_found_global, &var_meta_storage,
9369 &var_entry, if_not_found, if_bailout);
9370 BIND(&if_found_fast);
9372 TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
9373 Node* name_index = var_entry.value();
9375 LoadPropertyFromFastObject(
object, map, descriptors, name_index,
9376 var_details, var_value);
9379 BIND(&if_found_dict);
9381 Node* dictionary = var_meta_storage.value();
9382 Node* entry = var_entry.value();
9383 LoadPropertyFromNameDictionary(dictionary, entry, var_details, var_value);
9386 BIND(&if_found_global);
9388 Node* dictionary = var_meta_storage.value();
9389 Node* entry = var_entry.value();
9391 LoadPropertyFromGlobalDictionary(dictionary, entry, var_details, var_value,
9399 if (var_raw_value) {
9400 var_raw_value->Bind(var_value->value());
9402 Node* value = CallGetterIfAccessor(var_value->value(), var_details->value(),
9403 context, receiver, if_bailout, mode);
9404 var_value->Bind(value);
9405 Goto(if_found_value);
9409 void CodeStubAssembler::TryLookupElement(Node*
object, Node* map,
9410 SloppyTNode<Int32T> instance_type,
9411 SloppyTNode<IntPtrT> intptr_index,
9412 Label* if_found, Label* if_absent,
9413 Label* if_not_found,
9414 Label* if_bailout) {
9416 GotoIf(IsSpecialReceiverInstanceType(instance_type), if_bailout);
9418 Node* elements_kind = LoadMapElementsKind(map);
9421 Label if_isobjectorsmi(
this), if_isdouble(
this), if_isdictionary(
this),
9422 if_isfaststringwrapper(
this), if_isslowstringwrapper(
this), if_oob(
this),
9423 if_typedarray(
this);
9425 int32_t values[] = {
9427 PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS,
9430 PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS,
9432 DICTIONARY_ELEMENTS,
9434 FAST_STRING_WRAPPER_ELEMENTS,
9436 SLOW_STRING_WRAPPER_ELEMENTS,
9448 UINT8_CLAMPED_ELEMENTS,
9453 &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi,
9455 &if_isdouble, &if_isdouble,
9457 &if_isfaststringwrapper,
9458 &if_isslowstringwrapper,
9473 STATIC_ASSERT(arraysize(values) == arraysize(labels));
9474 Switch(elements_kind, if_bailout, values, labels, arraysize(values));
9476 BIND(&if_isobjectorsmi);
9478 TNode<FixedArray> elements = CAST(LoadElements(
object));
9479 TNode<IntPtrT> length = LoadAndUntagFixedArrayBaseLength(elements);
9481 GotoIfNot(UintPtrLessThan(intptr_index, length), &if_oob);
9483 TNode<Object> element = LoadFixedArrayElement(elements, intptr_index);
9484 TNode<Oddball> the_hole = TheHoleConstant();
9485 Branch(WordEqual(element, the_hole), if_not_found, if_found);
9489 TNode<FixedArrayBase> elements = LoadElements(
object);
9490 TNode<IntPtrT> length = LoadAndUntagFixedArrayBaseLength(elements);
9492 GotoIfNot(UintPtrLessThan(intptr_index, length), &if_oob);
9495 LoadFixedDoubleArrayElement(CAST(elements), intptr_index,
9496 MachineType::None(), 0, INTPTR_PARAMETERS,
9500 BIND(&if_isdictionary);
9503 GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout);
9505 TVARIABLE(IntPtrT, var_entry);
9506 TNode<NumberDictionary> elements = CAST(LoadElements(
object));
9507 NumberDictionaryLookup(elements, intptr_index, if_found, &var_entry,
9510 BIND(&if_isfaststringwrapper);
9512 CSA_ASSERT(
this, HasInstanceType(
object, JS_VALUE_TYPE));
9513 Node*
string = LoadJSValueValue(
object);
9514 CSA_ASSERT(
this, IsString(
string));
9515 Node* length = LoadStringLengthAsWord(
string);
9516 GotoIf(UintPtrLessThan(intptr_index, length), if_found);
9517 Goto(&if_isobjectorsmi);
9519 BIND(&if_isslowstringwrapper);
9521 CSA_ASSERT(
this, HasInstanceType(
object, JS_VALUE_TYPE));
9522 Node*
string = LoadJSValueValue(
object);
9523 CSA_ASSERT(
this, IsString(
string));
9524 Node* length = LoadStringLengthAsWord(
string);
9525 GotoIf(UintPtrLessThan(intptr_index, length), if_found);
9526 Goto(&if_isdictionary);
9528 BIND(&if_typedarray);
9530 Node* buffer = LoadObjectField(
object, JSArrayBufferView::kBufferOffset);
9531 GotoIf(IsDetachedBuffer(buffer), if_absent);
9533 Node* length = SmiUntag(LoadJSTypedArrayLength(CAST(
object)));
9534 Branch(UintPtrLessThan(intptr_index, length), if_found, if_absent);
9540 GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), if_bailout);
9545 void CodeStubAssembler::BranchIfMaybeSpecialIndex(TNode<String> name_string,
9546 Label* if_maybe_special_index,
9547 Label* if_not_special_index) {
9552 const int kBufferSize = 24;
9553 TNode<Smi> string_length = LoadStringLengthAsSmi(name_string);
9554 GotoIf(SmiEqual(string_length, SmiConstant(0)), if_not_special_index);
9555 GotoIf(SmiGreaterThan(string_length, SmiConstant(kBufferSize)),
9556 if_not_special_index);
9560 TNode<Int32T> first_char = StringCharCodeAt(name_string, IntPtrConstant(0));
9562 GotoIf(Word32Equal(first_char, Int32Constant(
'-')), if_maybe_special_index);
9564 GotoIf(Word32Equal(first_char, Int32Constant(
'I')), if_maybe_special_index);
9566 GotoIf(Word32Equal(first_char, Int32Constant(
'N')), if_maybe_special_index);
9569 GotoIf(Uint32LessThan(first_char, Int32Constant(
'0')), if_not_special_index);
9570 GotoIf(Uint32LessThan(Int32Constant(
'9'), first_char), if_not_special_index);
9571 Goto(if_maybe_special_index);
9574 void CodeStubAssembler::TryPrototypeChainLookup(
9575 Node* receiver, Node* key,
const LookupInHolder& lookup_property_in_holder,
9576 const LookupInHolder& lookup_element_in_holder, Label* if_end,
9577 Label* if_bailout, Label* if_proxy) {
9579 Label if_objectisnotsmi(
this);
9580 Branch(TaggedIsSmi(receiver), if_bailout, &if_objectisnotsmi);
9581 BIND(&if_objectisnotsmi);
9583 Node* map = LoadMap(receiver);
9584 Node* instance_type = LoadMapInstanceType(map);
9586 Label if_objectisreceiver(
this);
9587 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
9588 STATIC_ASSERT(FIRST_JS_RECEIVER_TYPE == JS_PROXY_TYPE);
9589 Branch(IsJSReceiverInstanceType(instance_type), &if_objectisreceiver,
9591 BIND(&if_objectisreceiver);
9594 GotoIf(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), if_proxy);
9598 VARIABLE(var_index, MachineType::PointerRepresentation());
9599 VARIABLE(var_unique, MachineRepresentation::kTagged);
9601 Label if_keyisindex(
this), if_iskeyunique(
this);
9602 TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_unique,
9605 BIND(&if_iskeyunique);
9607 VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
9608 VARIABLE(var_holder_map, MachineRepresentation::kTagged, map);
9609 VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32,
9612 Variable* merged_variables[] = {&var_holder, &var_holder_map,
9613 &var_holder_instance_type};
9614 Label loop(
this, arraysize(merged_variables), merged_variables);
9618 Node* holder_map = var_holder_map.value();
9619 Node* holder_instance_type = var_holder_instance_type.value();
9621 Label next_proto(
this), check_integer_indexed_exotic(
this);
9622 lookup_property_in_holder(receiver, var_holder.value(), holder_map,
9623 holder_instance_type, var_unique.value(),
9624 &check_integer_indexed_exotic, if_bailout);
9626 BIND(&check_integer_indexed_exotic);
9629 GotoIfNot(InstanceTypeEqual(holder_instance_type, JS_TYPED_ARRAY_TYPE),
9631 GotoIfNot(IsString(var_unique.value()), &next_proto);
9632 BranchIfMaybeSpecialIndex(CAST(var_unique.value()), if_bailout,
9638 Node* proto = LoadMapPrototype(holder_map);
9640 GotoIf(IsNull(proto), if_end);
9642 Node* map = LoadMap(proto);
9643 Node* instance_type = LoadMapInstanceType(map);
9645 var_holder.Bind(proto);
9646 var_holder_map.Bind(map);
9647 var_holder_instance_type.Bind(instance_type);
9651 BIND(&if_keyisindex);
9653 VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
9654 VARIABLE(var_holder_map, MachineRepresentation::kTagged, map);
9655 VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32,
9658 Variable* merged_variables[] = {&var_holder, &var_holder_map,
9659 &var_holder_instance_type};
9660 Label loop(
this, arraysize(merged_variables), merged_variables);
9664 Label next_proto(
this);
9665 lookup_element_in_holder(receiver, var_holder.value(),
9666 var_holder_map.value(),
9667 var_holder_instance_type.value(),
9668 var_index.value(), &next_proto, if_bailout);
9671 Node* proto = LoadMapPrototype(var_holder_map.value());
9673 GotoIf(IsNull(proto), if_end);
9675 Node* map = LoadMap(proto);
9676 Node* instance_type = LoadMapInstanceType(map);
9678 var_holder.Bind(proto);
9679 var_holder_map.Bind(map);
9680 var_holder_instance_type.Bind(instance_type);
9686 Node* CodeStubAssembler::HasInPrototypeChain(Node* context, Node*
object,
9688 CSA_ASSERT(
this, TaggedIsNotSmi(
object));
9689 VARIABLE(var_result, MachineRepresentation::kTagged);
9690 Label return_false(
this), return_true(
this),
9691 return_runtime(
this, Label::kDeferred), return_result(
this);
9694 VARIABLE(var_object_map, MachineRepresentation::kTagged, LoadMap(
object));
9695 Label loop(
this, &var_object_map);
9700 Label if_objectisdirect(
this), if_objectisspecial(
this, Label::kDeferred);
9701 Node* object_map = var_object_map.value();
9702 TNode<Int32T> object_instance_type = LoadMapInstanceType(object_map);
9703 Branch(IsSpecialReceiverInstanceType(object_instance_type),
9704 &if_objectisspecial, &if_objectisdirect);
9705 BIND(&if_objectisspecial);
9709 GotoIf(InstanceTypeEqual(object_instance_type, JS_PROXY_TYPE),
9711 Node* object_bitfield = LoadMapBitField(object_map);
9712 int mask = Map::HasNamedInterceptorBit::kMask |
9713 Map::IsAccessCheckNeededBit::kMask;
9714 Branch(IsSetWord32(object_bitfield, mask), &return_runtime,
9715 &if_objectisdirect);
9717 BIND(&if_objectisdirect);
9720 Node* object_prototype = LoadMapPrototype(object_map);
9721 GotoIf(IsNull(object_prototype), &return_false);
9722 GotoIf(WordEqual(object_prototype, prototype), &return_true);
9725 CSA_ASSERT(
this, TaggedIsNotSmi(object_prototype));
9726 var_object_map.Bind(LoadMap(object_prototype));
9731 var_result.Bind(TrueConstant());
9732 Goto(&return_result);
9734 BIND(&return_false);
9735 var_result.Bind(FalseConstant());
9736 Goto(&return_result);
9738 BIND(&return_runtime);
9742 CallRuntime(Runtime::kHasInPrototypeChain, context,
object, prototype));
9744 Goto(&return_result);
9746 BIND(&return_result);
9747 return var_result.value();
9750 Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
9752 VARIABLE(var_result, MachineRepresentation::kTagged);
9753 Label return_runtime(
this, Label::kDeferred), return_result(
this);
9756 GotoIf(TaggedIsSmi(
object), &return_runtime);
9759 GotoIf(TaggedIsSmi(callable), &return_runtime);
9762 Node* callable_map = LoadMap(callable);
9765 Node* callable_instance_type = LoadMapInstanceType(callable_map);
9766 GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE),
9769 GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), CAST(callable_map),
9773 Node* callable_prototype =
9774 LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset);
9776 Label callable_prototype_valid(
this);
9777 VARIABLE(var_callable_prototype, MachineRepresentation::kTagged,
9778 callable_prototype);
9784 Node* callable_prototype_instance_type =
9785 LoadInstanceType(callable_prototype);
9786 GotoIfNot(InstanceTypeEqual(callable_prototype_instance_type, MAP_TYPE),
9787 &callable_prototype_valid);
9788 var_callable_prototype.Bind(
9789 LoadObjectField(callable_prototype, Map::kPrototypeOffset));
9790 Goto(&callable_prototype_valid);
9791 BIND(&callable_prototype_valid);
9792 callable_prototype = var_callable_prototype.value();
9796 var_result.Bind(HasInPrototypeChain(context,
object, callable_prototype));
9797 Goto(&return_result);
9799 BIND(&return_runtime);
9803 CallRuntime(Runtime::kOrdinaryHasInstance, context, callable,
object));
9805 Goto(&return_result);
9807 BIND(&return_result);
9808 return var_result.value();
9811 TNode<IntPtrT> CodeStubAssembler::ElementOffsetFromIndex(Node* index_node,
9815 CSA_SLOW_ASSERT(
this, MatchesParameterMode(index_node, mode));
9816 int element_size_shift = ElementsKindToShiftSize(kind);
9817 int element_size = 1 << element_size_shift;
9818 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize;
9820 bool constant_index =
false;
9821 if (mode == SMI_PARAMETERS) {
9822 element_size_shift -= kSmiShiftBits;
9824 constant_index = ToSmiConstant(index_node, &smi_index);
9825 if (constant_index) index = smi_index->value();
9826 index_node = BitcastTaggedToWord(index_node);
9828 DCHECK(mode == INTPTR_PARAMETERS);
9829 constant_index = ToIntPtrConstant(index_node, index);
9831 if (constant_index) {
9832 return IntPtrConstant(base_size + element_size * index);
9835 TNode<WordT> shifted_index =
9836 (element_size_shift == 0)
9837 ? UncheckedCast<WordT>(index_node)
9838 : ((element_size_shift > 0)
9839 ? WordShl(index_node, IntPtrConstant(element_size_shift))
9840 : WordSar(index_node, IntPtrConstant(-element_size_shift)));
9841 return IntPtrAdd(IntPtrConstant(base_size), Signed(shifted_index));
9844 TNode<BoolT> CodeStubAssembler::IsOffsetInBounds(SloppyTNode<IntPtrT> offset,
9845 SloppyTNode<IntPtrT> length,
9847 ElementsKind kind) {
9849 int element_size = 1 << ElementsKindToShiftSize(kind);
9850 int correction = header_size - kHeapObjectTag - element_size;
9851 TNode<IntPtrT> last_offset =
9852 ElementOffsetFromIndex(length, kind, INTPTR_PARAMETERS, correction);
9853 return IntPtrLessThanOrEqual(offset, last_offset);
9856 TNode<FeedbackVector> CodeStubAssembler::LoadFeedbackVector(
9857 SloppyTNode<JSFunction> closure, Label* if_undefined) {
9858 TNode<Object> maybe_vector = LoadFeedbackVectorUnchecked(closure);
9860 GotoIf(IsUndefined(maybe_vector), if_undefined);
9862 return CAST(maybe_vector);
9865 TNode<Object> CodeStubAssembler::LoadFeedbackVectorUnchecked(
9866 SloppyTNode<JSFunction> closure) {
9867 TNode<FeedbackCell> feedback_cell =
9868 CAST(LoadObjectField(closure, JSFunction::kFeedbackCellOffset));
9869 TNode<Object> maybe_vector =
9870 LoadObjectField(feedback_cell, FeedbackCell::kValueOffset);
9871 return maybe_vector;
9874 TNode<FeedbackVector> CodeStubAssembler::LoadFeedbackVectorForStub() {
9875 TNode<JSFunction>
function =
9876 CAST(LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset));
9877 return LoadFeedbackVector(
function);
9880 void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* maybe_vector,
9884 GotoIf(IsUndefined(maybe_vector), &end);
9889 TNode<FeedbackVector> feedback_vector = CAST(maybe_vector);
9890 TNode<MaybeObject> feedback_element =
9891 LoadFeedbackVectorSlot(feedback_vector, slot_id);
9892 TNode<Smi> previous_feedback = CAST(feedback_element);
9893 TNode<Smi> combined_feedback = SmiOr(previous_feedback, CAST(feedback));
9895 GotoIf(SmiEqual(previous_feedback, combined_feedback), &end);
9897 StoreFeedbackVectorSlot(feedback_vector, slot_id, combined_feedback,
9898 SKIP_WRITE_BARRIER);
9899 ReportFeedbackUpdate(feedback_vector, slot_id,
"UpdateFeedback");
9906 void CodeStubAssembler::ReportFeedbackUpdate(
9907 SloppyTNode<FeedbackVector> feedback_vector, SloppyTNode<IntPtrT> slot_id,
9908 const char* reason) {
9910 StoreObjectFieldNoWriteBarrier(
9911 feedback_vector, FeedbackVector::kProfilerTicksOffset, Int32Constant(0),
9912 MachineRepresentation::kWord32);
9914 #ifdef V8_TRACE_FEEDBACK_UPDATES 9916 CallRuntime(Runtime::kInterpreterTraceUpdateFeedback, NoContextConstant(),
9917 LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset),
9918 SmiTag(slot_id), StringConstant(reason));
9919 #endif // V8_TRACE_FEEDBACK_UPDATES 9922 void CodeStubAssembler::OverwriteFeedback(Variable* existing_feedback,
9924 if (existing_feedback ==
nullptr)
return;
9925 existing_feedback->Bind(SmiConstant(new_feedback));
9928 void CodeStubAssembler::CombineFeedback(Variable* existing_feedback,
9930 if (existing_feedback ==
nullptr)
return;
9931 existing_feedback->Bind(
9932 SmiOr(CAST(existing_feedback->value()), SmiConstant(feedback)));
9935 void CodeStubAssembler::CombineFeedback(Variable* existing_feedback,
9937 if (existing_feedback ==
nullptr)
return;
9938 existing_feedback->Bind(
9939 SmiOr(CAST(existing_feedback->value()), CAST(feedback)));
9942 void CodeStubAssembler::CheckForAssociatedProtector(Node* name,
9943 Label* if_protector) {
9946 GotoIf(WordEqual(name, LoadRoot(RootIndex::kconstructor_string)),
9948 GotoIf(WordEqual(name, LoadRoot(RootIndex::kiterator_symbol)), if_protector);
9949 GotoIf(WordEqual(name, LoadRoot(RootIndex::knext_string)), if_protector);
9950 GotoIf(WordEqual(name, LoadRoot(RootIndex::kspecies_symbol)), if_protector);
9951 GotoIf(WordEqual(name, LoadRoot(RootIndex::kis_concat_spreadable_symbol)),
9953 GotoIf(WordEqual(name, LoadRoot(RootIndex::kresolve_string)), if_protector);
9954 GotoIf(WordEqual(name, LoadRoot(RootIndex::kthen_string)), if_protector);
9958 TNode<Map> CodeStubAssembler::LoadReceiverMap(SloppyTNode<Object> receiver) {
9960 TaggedIsSmi(receiver),
9961 [=] {
return CAST(LoadRoot(RootIndex::kHeapNumberMap)); },
9962 [=] {
return LoadMap(UncheckedCast<HeapObject>(receiver)); });
9965 TNode<IntPtrT> CodeStubAssembler::TryToIntptr(Node* key, Label* miss) {
9966 TVARIABLE(IntPtrT, var_intptr_key);
9967 Label done(
this, &var_intptr_key), key_is_smi(
this);
9968 GotoIf(TaggedIsSmi(key), &key_is_smi);
9970 GotoIfNot(IsHeapNumber(key), miss);
9972 TNode<Float64T> value = LoadHeapNumberValue(key);
9973 TNode<Int32T> int_value = RoundFloat64ToInt32(value);
9974 GotoIfNot(Float64Equal(value, ChangeInt32ToFloat64(int_value)), miss);
9975 var_intptr_key = ChangeInt32ToIntPtr(int_value);
9981 var_intptr_key = SmiUntag(key);
9986 return var_intptr_key.value();
9989 Node* CodeStubAssembler::EmitKeyedSloppyArguments(Node* receiver, Node* key,
9990 Node* value, Label* bailout) {
10017 bool is_load = value ==
nullptr;
10019 GotoIfNot(TaggedIsSmi(key), bailout);
10020 key = SmiUntag(key);
10021 GotoIf(IntPtrLessThan(key, IntPtrConstant(0)), bailout);
10023 TNode<FixedArray> elements = CAST(LoadElements(receiver));
10024 TNode<IntPtrT> elements_length = LoadAndUntagFixedArrayBaseLength(elements);
10026 VARIABLE(var_result, MachineRepresentation::kTagged);
10028 var_result.Bind(value);
10030 Label if_mapped(
this), if_unmapped(
this), end(
this, &var_result);
10031 Node* intptr_two = IntPtrConstant(2);
10032 Node* adjusted_length = IntPtrSub(elements_length, intptr_two);
10034 GotoIf(UintPtrGreaterThanOrEqual(key, adjusted_length), &if_unmapped);
10036 TNode<Object> mapped_index =
10037 LoadFixedArrayElement(elements, IntPtrAdd(key, intptr_two));
10038 Branch(WordEqual(mapped_index, TheHoleConstant()), &if_unmapped, &if_mapped);
10042 TNode<IntPtrT> mapped_index_intptr = SmiUntag(CAST(mapped_index));
10043 TNode<Context> the_context = CAST(LoadFixedArrayElement(elements, 0));
10045 Node* result = LoadContextElement(the_context, mapped_index_intptr);
10046 CSA_ASSERT(
this, WordNotEqual(result, TheHoleConstant()));
10047 var_result.Bind(result);
10049 StoreContextElement(the_context, mapped_index_intptr, value);
10054 BIND(&if_unmapped);
10056 TNode<HeapObject> backing_store_ho =
10057 CAST(LoadFixedArrayElement(elements, 1));
10058 GotoIf(WordNotEqual(LoadMap(backing_store_ho), FixedArrayMapConstant()),
10060 TNode<FixedArray> backing_store = CAST(backing_store_ho);
10062 TNode<IntPtrT> backing_store_length =
10063 LoadAndUntagFixedArrayBaseLength(backing_store);
10064 GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), bailout);
10068 Node* result = LoadFixedArrayElement(backing_store, key);
10069 GotoIf(WordEqual(result, TheHoleConstant()), bailout);
10070 var_result.Bind(result);
10072 StoreFixedArrayElement(backing_store, key, value);
10078 return var_result.value();
10081 TNode<Context> CodeStubAssembler::LoadScriptContext(
10082 TNode<Context> context, TNode<IntPtrT> context_index) {
10083 TNode<Context> native_context = LoadNativeContext(context);
10084 TNode<ScriptContextTable> script_context_table = CAST(
10085 LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX));
10087 TNode<Context> script_context = CAST(LoadFixedArrayElement(
10088 script_context_table, context_index,
10089 ScriptContextTable::kFirstContextSlotIndex * kPointerSize));
10090 return script_context;
10096 MachineRepresentation ElementsKindToMachineRepresentation(ElementsKind kind) {
10098 case UINT8_CLAMPED_ELEMENTS:
10099 case UINT8_ELEMENTS:
10100 case INT8_ELEMENTS:
10101 return MachineRepresentation::kWord8;
10102 case UINT16_ELEMENTS:
10103 case INT16_ELEMENTS:
10104 return MachineRepresentation::kWord16;
10105 case UINT32_ELEMENTS:
10106 case INT32_ELEMENTS:
10107 return MachineRepresentation::kWord32;
10108 case FLOAT32_ELEMENTS:
10109 return MachineRepresentation::kFloat32;
10110 case FLOAT64_ELEMENTS:
10111 return MachineRepresentation::kFloat64;
10119 void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind,
10120 Node* index, Node* value,
10121 ParameterMode mode) {
10122 if (IsFixedTypedArrayElementsKind(kind)) {
10123 if (kind == UINT8_CLAMPED_ELEMENTS) {
10125 Word32Equal(value, Word32And(Int32Constant(0xFF), value)));
10127 Node* offset = ElementOffsetFromIndex(index, kind, mode, 0);
10129 MachineRepresentation rep = ElementsKindToMachineRepresentation(kind);
10130 StoreNoWriteBarrier(rep, elements, offset, value);
10132 }
else if (IsDoubleElementsKind(kind)) {
10134 TNode<Float64T> value_silenced = Float64SilenceNaN(value);
10135 StoreFixedDoubleArrayElement(CAST(elements), index, value_silenced, mode);
10137 WriteBarrierMode barrier_mode =
10138 IsSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
10139 StoreFixedArrayElement(CAST(elements), index, value, barrier_mode, 0, mode);
10143 Node* CodeStubAssembler::Int32ToUint8Clamped(Node* int32_value) {
10145 Node* int32_zero = Int32Constant(0);
10146 Node* int32_255 = Int32Constant(255);
10147 VARIABLE(var_value, MachineRepresentation::kWord32, int32_value);
10148 GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done);
10149 var_value.Bind(int32_zero);
10150 GotoIf(Int32LessThan(int32_value, int32_zero), &done);
10151 var_value.Bind(int32_255);
10154 return var_value.value();
10157 Node* CodeStubAssembler::Float64ToUint8Clamped(Node* float64_value) {
10159 VARIABLE(var_value, MachineRepresentation::kWord32, Int32Constant(0));
10160 GotoIf(Float64LessThanOrEqual(float64_value, Float64Constant(0.0)), &done);
10161 var_value.Bind(Int32Constant(255));
10162 GotoIf(Float64LessThanOrEqual(Float64Constant(255.0), float64_value), &done);
10164 Node* rounded_value = Float64RoundToEven(float64_value);
10165 var_value.Bind(TruncateFloat64ToWord32(rounded_value));
10169 return var_value.value();
10172 Node* CodeStubAssembler::PrepareValueForWriteToTypedArray(
10173 TNode<Object> input, ElementsKind elements_kind, TNode<Context> context) {
10174 DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
10176 MachineRepresentation rep;
10177 switch (elements_kind) {
10178 case UINT8_ELEMENTS:
10179 case INT8_ELEMENTS:
10180 case UINT16_ELEMENTS:
10181 case INT16_ELEMENTS:
10182 case UINT32_ELEMENTS:
10183 case INT32_ELEMENTS:
10184 case UINT8_CLAMPED_ELEMENTS:
10185 rep = MachineRepresentation::kWord32;
10187 case FLOAT32_ELEMENTS:
10188 rep = MachineRepresentation::kFloat32;
10190 case FLOAT64_ELEMENTS:
10191 rep = MachineRepresentation::kFloat64;
10193 case BIGINT64_ELEMENTS:
10194 case BIGUINT64_ELEMENTS:
10195 return ToBigInt(context, input);
10200 VARIABLE(var_result, rep);
10201 VARIABLE(var_input, MachineRepresentation::kTagged, input);
10202 Label done(
this, &var_result), if_smi(
this), if_heapnumber_or_oddball(
this),
10203 convert(
this), loop(
this, &var_input);
10206 GotoIf(TaggedIsSmi(var_input.value()), &if_smi);
10210 GotoIf(IsHeapNumber(var_input.value()), &if_heapnumber_or_oddball);
10211 STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
10212 Branch(HasInstanceType(var_input.value(), ODDBALL_TYPE),
10213 &if_heapnumber_or_oddball, &convert);
10215 BIND(&if_heapnumber_or_oddball);
10217 Node* value = UncheckedCast<Float64T>(LoadObjectField(
10218 var_input.value(), HeapNumber::kValueOffset, MachineType::Float64()));
10219 if (rep == MachineRepresentation::kWord32) {
10220 if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
10221 value = Float64ToUint8Clamped(value);
10223 value = TruncateFloat64ToWord32(value);
10225 }
else if (rep == MachineRepresentation::kFloat32) {
10226 value = TruncateFloat64ToFloat32(value);
10228 DCHECK_EQ(MachineRepresentation::kFloat64, rep);
10230 var_result.Bind(value);
10236 Node* value = SmiToInt32(var_input.value());
10237 if (rep == MachineRepresentation::kFloat32) {
10238 value = RoundInt32ToFloat32(value);
10239 }
else if (rep == MachineRepresentation::kFloat64) {
10240 value = ChangeInt32ToFloat64(value);
10242 DCHECK_EQ(MachineRepresentation::kWord32, rep);
10243 if (elements_kind == UINT8_CLAMPED_ELEMENTS) {
10244 value = Int32ToUint8Clamped(value);
10247 var_result.Bind(value);
10253 var_input.Bind(CallBuiltin(Builtins::kNonNumberToNumber, context, input));
10258 return var_result.value();
10261 void CodeStubAssembler::EmitBigTypedArrayElementStore(
10262 TNode<JSTypedArray>
object, TNode<FixedTypedArrayBase> elements,
10263 TNode<IntPtrT> intptr_key, TNode<Object> value, TNode<Context> context,
10264 Label* opt_if_neutered) {
10265 TNode<BigInt> bigint_value = ToBigInt(context, value);
10267 if (opt_if_neutered !=
nullptr) {
10269 Node* buffer = LoadObjectField(
object, JSArrayBufferView::kBufferOffset);
10270 GotoIf(IsDetachedBuffer(buffer), opt_if_neutered);
10273 TNode<RawPtrT> backing_store = LoadFixedTypedArrayBackingStore(elements);
10274 TNode<IntPtrT> offset = ElementOffsetFromIndex(intptr_key, BIGINT64_ELEMENTS,
10275 INTPTR_PARAMETERS, 0);
10276 EmitBigTypedArrayElementStore(elements, backing_store, offset, bigint_value);
10279 void CodeStubAssembler::BigIntToRawBytes(TNode<BigInt> bigint,
10280 TVariable<UintPtrT>* var_low,
10281 TVariable<UintPtrT>* var_high) {
10283 *var_low = Unsigned(IntPtrConstant(0));
10284 *var_high = Unsigned(IntPtrConstant(0));
10285 TNode<WordT> bitfield = LoadBigIntBitfield(bigint);
10286 TNode<UintPtrT> length = DecodeWord<BigIntBase::LengthBits>(bitfield);
10287 TNode<UintPtrT> sign = DecodeWord<BigIntBase::SignBits>(bitfield);
10288 GotoIf(WordEqual(length, IntPtrConstant(0)), &done);
10289 *var_low = LoadBigIntDigit(bigint, 0);
10291 Label load_done(
this);
10292 GotoIf(WordEqual(length, IntPtrConstant(1)), &load_done);
10293 *var_high = LoadBigIntDigit(bigint, 1);
10297 GotoIf(WordEqual(sign, IntPtrConstant(0)), &done);
10300 *var_high = Unsigned(IntPtrSub(IntPtrConstant(0), var_high->value()));
10301 Label no_carry(
this);
10302 GotoIf(WordEqual(var_low->value(), IntPtrConstant(0)), &no_carry);
10303 *var_high = Unsigned(IntPtrSub(var_high->value(), IntPtrConstant(1)));
10307 *var_low = Unsigned(IntPtrSub(IntPtrConstant(0), var_low->value()));
10312 void CodeStubAssembler::EmitBigTypedArrayElementStore(
10313 TNode<FixedTypedArrayBase> elements, TNode<RawPtrT> backing_store,
10314 TNode<IntPtrT> offset, TNode<BigInt> bigint_value) {
10315 TVARIABLE(UintPtrT, var_low);
10317 TVARIABLE(UintPtrT, var_high);
10318 BigIntToRawBytes(bigint_value, &var_low, &var_high);
10323 this, IsOffsetInBounds(offset, LoadAndUntagFixedArrayBaseLength(elements),
10324 kHeapObjectTag, BIGINT64_ELEMENTS));
10326 MachineRepresentation rep = WordT::kMachineRepresentation;
10327 #if defined(V8_TARGET_BIG_ENDIAN) 10329 StoreNoWriteBarrier(rep, backing_store, offset, var_high.value());
10330 StoreNoWriteBarrier(rep, backing_store,
10331 IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
10334 StoreNoWriteBarrier(rep, backing_store, offset, var_low.value());
10337 StoreNoWriteBarrier(rep, backing_store, offset, var_low.value());
10339 StoreNoWriteBarrier(rep, backing_store,
10340 IntPtrAdd(offset, IntPtrConstant(kPointerSize)),
10346 void CodeStubAssembler::EmitElementStore(Node*
object, Node* key, Node* value,
10347 ElementsKind elements_kind,
10348 KeyedAccessStoreMode store_mode,
10349 Label* bailout, Node* context) {
10350 CSA_ASSERT(
this, Word32BinaryNot(IsJSProxy(
object)));
10352 Node* elements = LoadElements(
object);
10353 if (!IsSmiOrObjectElementsKind(elements_kind)) {
10354 CSA_ASSERT(
this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
10355 }
else if (!IsCOWHandlingStoreMode(store_mode)) {
10356 GotoIf(IsFixedCOWArrayMap(LoadMap(elements)), bailout);
10360 ParameterMode parameter_mode = INTPTR_PARAMETERS;
10361 TNode<IntPtrT> intptr_key = TryToIntptr(key, bailout);
10363 if (IsFixedTypedArrayElementsKind(elements_kind)) {
10368 value = PrepareValueForWriteToTypedArray(CAST(value), elements_kind,
10377 Node* buffer = LoadObjectField(
object, JSArrayBufferView::kBufferOffset);
10378 GotoIf(IsDetachedBuffer(buffer), bailout);
10382 TaggedToParameter(LoadJSTypedArrayLength(CAST(
object)), parameter_mode);
10384 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
10387 GotoIfNot(UintPtrLessThan(intptr_key, length), &done);
10388 }
else if (store_mode == STANDARD_STORE) {
10389 GotoIfNot(UintPtrLessThan(intptr_key, length), bailout);
10398 if (elements_kind == BIGINT64_ELEMENTS ||
10399 elements_kind == BIGUINT64_ELEMENTS) {
10400 TNode<BigInt> bigint_value = UncheckedCast<BigInt>(value);
10402 TNode<RawPtrT> backing_store =
10403 LoadFixedTypedArrayBackingStore(CAST(elements));
10404 TNode<IntPtrT> offset = ElementOffsetFromIndex(
10405 intptr_key, BIGINT64_ELEMENTS, INTPTR_PARAMETERS, 0);
10406 EmitBigTypedArrayElementStore(CAST(elements), backing_store, offset,
10409 Node* backing_store = LoadFixedTypedArrayBackingStore(CAST(elements));
10410 StoreElement(backing_store, elements_kind, intptr_key, value,
10418 DCHECK(IsFastElementsKind(elements_kind));
10421 SelectImpl(IsJSArray(
object), [=]() {
return LoadJSArrayLength(
object); },
10422 [=]() {
return LoadFixedArrayBaseLength(elements); },
10423 MachineRepresentation::kTagged);
10424 length = TaggedToParameter(length, parameter_mode);
10429 if (IsSmiElementsKind(elements_kind)) {
10430 GotoIfNot(TaggedIsSmi(value), bailout);
10431 }
else if (IsDoubleElementsKind(elements_kind)) {
10432 value = TryTaggedToFloat64(value, bailout);
10435 if (IsGrowStoreMode(store_mode)) {
10436 elements = CheckForCapacityGrow(
object, elements, elements_kind, length,
10437 intptr_key, parameter_mode, bailout);
10439 GotoIfNot(UintPtrLessThan(intptr_key, length), bailout);
10444 if (!IsSmiOrObjectElementsKind(elements_kind)) {
10445 CSA_ASSERT(
this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
10446 }
else if (IsCOWHandlingStoreMode(store_mode)) {
10447 elements = CopyElementsOnWrite(
object, elements, elements_kind, length,
10448 parameter_mode, bailout);
10451 CSA_ASSERT(
this, Word32BinaryNot(IsFixedCOWArrayMap(LoadMap(elements))));
10452 StoreElement(elements, elements_kind, intptr_key, value, parameter_mode);
10455 Node* CodeStubAssembler::CheckForCapacityGrow(Node*
object, Node* elements,
10456 ElementsKind kind, Node* length,
10457 Node* key, ParameterMode mode,
10459 DCHECK(IsFastElementsKind(kind));
10460 VARIABLE(checked_elements, MachineRepresentation::kTagged);
10461 Label grow_case(
this), no_grow_case(
this), done(
this),
10462 grow_bailout(
this, Label::kDeferred);
10465 if (IsHoleyElementsKind(kind)) {
10466 condition = UintPtrGreaterThanOrEqual(key, length);
10469 condition = WordEqual(key, length);
10471 Branch(condition, &grow_case, &no_grow_case);
10475 Node* current_capacity =
10476 TaggedToParameter(LoadFixedArrayBaseLength(elements), mode);
10477 checked_elements.Bind(elements);
10478 Label fits_capacity(
this);
10480 GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity);
10483 Node* new_elements = TryGrowElementsCapacity(
10484 object, elements, kind, key, current_capacity, mode, &grow_bailout);
10485 checked_elements.Bind(new_elements);
10486 Goto(&fits_capacity);
10489 BIND(&grow_bailout);
10491 Node* tagged_key = mode == SMI_PARAMETERS
10493 : ChangeInt32ToTagged(TruncateIntPtrToInt32(key));
10494 Node* maybe_elements = CallRuntime(
10495 Runtime::kGrowArrayElements, NoContextConstant(),
object, tagged_key);
10496 GotoIf(TaggedIsSmi(maybe_elements), bailout);
10497 CSA_ASSERT(
this, IsFixedArrayWithKind(maybe_elements, kind));
10498 checked_elements.Bind(maybe_elements);
10499 Goto(&fits_capacity);
10502 BIND(&fits_capacity);
10503 GotoIfNot(IsJSArray(
object), &done);
10505 Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode));
10506 StoreObjectFieldNoWriteBarrier(
object, JSArray::kLengthOffset,
10507 ParameterToTagged(new_length, mode));
10511 BIND(&no_grow_case);
10513 GotoIfNot(UintPtrLessThan(key, length), bailout);
10514 checked_elements.Bind(elements);
10519 return checked_elements.value();
10522 Node* CodeStubAssembler::CopyElementsOnWrite(Node*
object, Node* elements,
10523 ElementsKind kind, Node* length,
10524 ParameterMode mode,
10526 VARIABLE(new_elements_var, MachineRepresentation::kTagged, elements);
10529 GotoIfNot(IsFixedCOWArrayMap(LoadMap(elements)), &done);
10532 TaggedToParameter(LoadFixedArrayBaseLength(elements), mode);
10533 Node* new_elements = GrowElementsCapacity(
object, elements, kind, kind,
10534 length, capacity, mode, bailout);
10535 new_elements_var.Bind(new_elements);
10540 return new_elements_var.value();
10543 void CodeStubAssembler::TransitionElementsKind(Node*
object, Node* map,
10544 ElementsKind from_kind,
10545 ElementsKind to_kind,
10547 DCHECK(!IsHoleyElementsKind(from_kind) || IsHoleyElementsKind(to_kind));
10548 if (AllocationSite::ShouldTrack(from_kind, to_kind)) {
10549 TrapAllocationMemento(
object, bailout);
10552 if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
10553 Comment(
"Non-simple map transition");
10554 Node* elements = LoadElements(
object);
10557 GotoIf(WordEqual(elements, EmptyFixedArrayConstant()), &done);
10560 ParameterMode mode = INTPTR_PARAMETERS;
10561 Node* elements_length = SmiUntag(LoadFixedArrayBaseLength(elements));
10562 Node* array_length = SelectImpl(
10565 CSA_ASSERT(
this, IsFastElementsKind(LoadElementsKind(
object)));
10566 return SmiUntag(LoadFastJSArrayLength(
object));
10568 [=]() {
return elements_length; },
10569 MachineType::PointerRepresentation());
10571 CSA_ASSERT(
this, WordNotEqual(elements_length, IntPtrConstant(0)));
10573 GrowElementsCapacity(
object, elements, from_kind, to_kind, array_length,
10574 elements_length, mode, bailout);
10579 StoreMap(
object, map);
10582 void CodeStubAssembler::TrapAllocationMemento(Node*
object,
10583 Label* memento_found) {
10584 Comment(
"[ TrapAllocationMemento");
10585 Label no_memento_found(
this);
10586 Label top_check(
this), map_check(
this);
10588 TNode<ExternalReference> new_space_top_address = ExternalConstant(
10589 ExternalReference::new_space_allocation_top_address(isolate()));
10590 const int kMementoMapOffset = JSArray::kSize;
10591 const int kMementoLastWordOffset =
10592 kMementoMapOffset + AllocationMemento::kSize - kPointerSize;
10595 TNode<IntPtrT> object_word = BitcastTaggedToWord(
object);
10596 TNode<IntPtrT> object_page = PageFromAddress(object_word);
10598 TNode<IntPtrT> page_flags =
10599 UncheckedCast<IntPtrT>(Load(MachineType::IntPtr(), object_page,
10600 IntPtrConstant(Page::kFlagsOffset)));
10601 GotoIf(WordEqual(WordAnd(page_flags,
10602 IntPtrConstant(MemoryChunk::kIsInNewSpaceMask)),
10603 IntPtrConstant(0)),
10604 &no_memento_found);
10607 TNode<IntPtrT> memento_last_word = IntPtrAdd(
10608 object_word, IntPtrConstant(kMementoLastWordOffset - kHeapObjectTag));
10609 TNode<IntPtrT> memento_last_word_page = PageFromAddress(memento_last_word);
10611 TNode<IntPtrT> new_space_top = UncheckedCast<IntPtrT>(
10612 Load(MachineType::Pointer(), new_space_top_address));
10613 TNode<IntPtrT> new_space_top_page = PageFromAddress(new_space_top);
10617 GotoIf(WordEqual(memento_last_word_page, new_space_top_page), &top_check);
10622 Branch(WordEqual(object_page, memento_last_word_page), &map_check,
10623 &no_memento_found);
10629 Branch(UintPtrGreaterThanOrEqual(memento_last_word, new_space_top),
10630 &no_memento_found, &map_check);
10636 TNode<Object> memento_map = LoadObjectField(
object, kMementoMapOffset);
10637 Branch(WordEqual(memento_map, LoadRoot(RootIndex::kAllocationMementoMap)),
10638 memento_found, &no_memento_found);
10640 BIND(&no_memento_found);
10641 Comment(
"] TrapAllocationMemento");
10644 TNode<IntPtrT> CodeStubAssembler::PageFromAddress(TNode<IntPtrT> address) {
10645 return WordAnd(address, IntPtrConstant(~kPageAlignmentMask));
10648 TNode<AllocationSite> CodeStubAssembler::CreateAllocationSiteInFeedbackVector(
10649 SloppyTNode<FeedbackVector> feedback_vector, TNode<Smi> slot) {
10650 TNode<IntPtrT> size = IntPtrConstant(AllocationSite::kSizeWithWeakNext);
10651 Node* site = Allocate(size, CodeStubAssembler::kPretenured);
10652 StoreMapNoWriteBarrier(site, RootIndex::kAllocationSiteWithWeakNextMap);
10654 TNode<WordT> field = UpdateWord<AllocationSite::ElementsKindBits>(
10655 IntPtrConstant(0), IntPtrConstant(GetInitialFastElementsKind()));
10656 StoreObjectFieldNoWriteBarrier(
10657 site, AllocationSite::kTransitionInfoOrBoilerplateOffset,
10658 SmiTag(Signed(field)));
10661 TNode<Smi> zero = SmiConstant(0);
10662 StoreObjectFieldNoWriteBarrier(site, AllocationSite::kNestedSiteOffset, zero);
10665 StoreObjectFieldNoWriteBarrier(site, AllocationSite::kPretenureDataOffset,
10667 MachineRepresentation::kWord32);
10670 StoreObjectFieldNoWriteBarrier(
10671 site, AllocationSite::kPretenureCreateCountOffset, Int32Constant(0),
10672 MachineRepresentation::kWord32);
10675 StoreObjectFieldRoot(site, AllocationSite::kDependentCodeOffset,
10676 RootIndex::kEmptyWeakFixedArray);
10679 TNode<ExternalReference> site_list = ExternalConstant(
10680 ExternalReference::allocation_sites_list_address(isolate()));
10681 TNode<Object> next_site = CAST(LoadBufferObject(site_list, 0));
10688 StoreObjectField(site, AllocationSite::kWeakNextOffset, next_site);
10689 StoreNoWriteBarrier(MachineRepresentation::kTagged, site_list, site);
10691 StoreFeedbackVectorSlot(feedback_vector, slot, site, UPDATE_WRITE_BARRIER, 0,
10696 TNode<MaybeObject> CodeStubAssembler::StoreWeakReferenceInFeedbackVector(
10697 SloppyTNode<FeedbackVector> feedback_vector, Node* slot,
10698 SloppyTNode<HeapObject> value,
int additional_offset,
10699 ParameterMode parameter_mode) {
10700 TNode<MaybeObject> weak_value = MakeWeak(value);
10701 StoreFeedbackVectorSlot(feedback_vector, slot, weak_value,
10702 UPDATE_WRITE_BARRIER, additional_offset,
10707 TNode<BoolT> CodeStubAssembler::NotHasBoilerplate(
10708 TNode<Object> maybe_literal_site) {
10709 return TaggedIsSmi(maybe_literal_site);
10712 TNode<Smi> CodeStubAssembler::LoadTransitionInfo(
10713 TNode<AllocationSite> allocation_site) {
10714 TNode<Smi> transition_info = CAST(LoadObjectField(
10715 allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset));
10716 return transition_info;
10719 TNode<JSObject> CodeStubAssembler::LoadBoilerplate(
10720 TNode<AllocationSite> allocation_site) {
10721 TNode<JSObject> boilerplate = CAST(LoadObjectField(
10722 allocation_site, AllocationSite::kTransitionInfoOrBoilerplateOffset));
10723 return boilerplate;
10726 TNode<Int32T> CodeStubAssembler::LoadElementsKind(
10727 TNode<AllocationSite> allocation_site) {
10728 TNode<Smi> transition_info = LoadTransitionInfo(allocation_site);
10729 TNode<Int32T> elements_kind =
10730 Signed(DecodeWord32<AllocationSite::ElementsKindBits>(
10731 SmiToInt32(transition_info)));
10732 CSA_ASSERT(
this, IsFastElementsKind(elements_kind));
10733 return elements_kind;
10736 Node* CodeStubAssembler::BuildFastLoop(
10737 const CodeStubAssembler::VariableList& vars, Node* start_index,
10738 Node* end_index,
const FastLoopBody& body,
int increment,
10739 ParameterMode parameter_mode, IndexAdvanceMode advance_mode) {
10740 CSA_SLOW_ASSERT(
this, MatchesParameterMode(start_index, parameter_mode));
10741 CSA_SLOW_ASSERT(
this, MatchesParameterMode(end_index, parameter_mode));
10742 MachineRepresentation index_rep = (parameter_mode == INTPTR_PARAMETERS)
10743 ? MachineType::PointerRepresentation()
10744 : MachineRepresentation::kTaggedSigned;
10745 VARIABLE(var, index_rep, start_index);
10746 VariableList vars_copy(vars.begin(), vars.end(), zone());
10747 vars_copy.push_back(&var);
10748 Label loop(
this, vars_copy);
10749 Label after_loop(
this);
10757 Node* first_check = WordEqual(var.value(), end_index);
10758 int32_t first_check_val;
10759 if (ToInt32Constant(first_check, first_check_val)) {
10760 if (first_check_val)
return var.value();
10763 Branch(first_check, &after_loop, &loop);
10768 if (advance_mode == IndexAdvanceMode::kPre) {
10769 Increment(&var, increment, parameter_mode);
10772 if (advance_mode == IndexAdvanceMode::kPost) {
10773 Increment(&var, increment, parameter_mode);
10775 Branch(WordNotEqual(var.value(), end_index), &loop, &after_loop);
10778 return var.value();
10781 void CodeStubAssembler::BuildFastFixedArrayForEach(
10782 const CodeStubAssembler::VariableList& vars, Node* fixed_array,
10783 ElementsKind kind, Node* first_element_inclusive,
10784 Node* last_element_exclusive,
const FastFixedArrayForEachBody& body,
10785 ParameterMode mode, ForEachDirection direction) {
10786 STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
10787 CSA_SLOW_ASSERT(
this, MatchesParameterMode(first_element_inclusive, mode));
10788 CSA_SLOW_ASSERT(
this, MatchesParameterMode(last_element_exclusive, mode));
10789 CSA_SLOW_ASSERT(
this, Word32Or(IsFixedArrayWithKind(fixed_array, kind),
10790 IsPropertyArray(fixed_array)));
10792 bool constant_first = ToInt32Constant(first_element_inclusive, first_val);
10794 bool constent_last = ToInt32Constant(last_element_exclusive, last_val);
10795 if (constant_first && constent_last) {
10796 int delta = last_val - first_val;
10797 DCHECK_GE(delta, 0);
10798 if (delta <= kElementLoopUnrollThreshold) {
10799 if (direction == ForEachDirection::kForward) {
10800 for (
int i = first_val;
i < last_val; ++
i) {
10801 Node* index = IntPtrConstant(
i);
10803 ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS,
10804 FixedArray::kHeaderSize - kHeapObjectTag);
10805 body(fixed_array, offset);
10808 for (
int i = last_val - 1;
i >= first_val; --
i) {
10809 Node* index = IntPtrConstant(
i);
10811 ElementOffsetFromIndex(index, kind, INTPTR_PARAMETERS,
10812 FixedArray::kHeaderSize - kHeapObjectTag);
10813 body(fixed_array, offset);
10821 ElementOffsetFromIndex(first_element_inclusive, kind, mode,
10822 FixedArray::kHeaderSize - kHeapObjectTag);
10824 ElementOffsetFromIndex(last_element_exclusive, kind, mode,
10825 FixedArray::kHeaderSize - kHeapObjectTag);
10826 if (direction == ForEachDirection::kReverse) std::swap(start, limit);
10828 int increment = IsDoubleElementsKind(kind) ? kDoubleSize : kPointerSize;
10830 vars, start, limit,
10831 [fixed_array, &body](Node* offset) { body(fixed_array, offset); },
10832 direction == ForEachDirection::kReverse ? -increment : increment,
10834 direction == ForEachDirection::kReverse ? IndexAdvanceMode::kPre
10835 : IndexAdvanceMode::kPost);
10838 void CodeStubAssembler::GotoIfFixedArraySizeDoesntFitInNewSpace(
10839 Node* element_count, Label* doesnt_fit,
int base_size, ParameterMode mode) {
10840 GotoIf(FixedArraySizeDoesntFitInNewSpace(element_count, base_size, mode),
10844 void CodeStubAssembler::InitializeFieldsWithRoot(Node*
object,
10845 Node* start_offset,
10847 RootIndex root_index) {
10848 CSA_SLOW_ASSERT(
this, TaggedIsNotSmi(
object));
10849 start_offset = IntPtrAdd(start_offset, IntPtrConstant(-kHeapObjectTag));
10850 end_offset = IntPtrAdd(end_offset, IntPtrConstant(-kHeapObjectTag));
10851 Node* root_value = LoadRoot(root_index);
10852 BuildFastLoop(end_offset, start_offset,
10853 [
this,
object, root_value](Node* current) {
10854 StoreNoWriteBarrier(MachineRepresentation::kTagged,
object,
10855 current, root_value);
10857 -kPointerSize, INTPTR_PARAMETERS,
10858 CodeStubAssembler::IndexAdvanceMode::kPre);
10861 void CodeStubAssembler::BranchIfNumberRelationalComparison(
10862 Operation op, Node* left, Node* right, Label* if_true, Label* if_false) {
10863 CSA_SLOW_ASSERT(
this, IsNumber(left));
10864 CSA_SLOW_ASSERT(
this, IsNumber(right));
10866 Label do_float_comparison(
this);
10867 TVARIABLE(Float64T, var_left_float);
10868 TVARIABLE(Float64T, var_right_float);
10870 Branch(TaggedIsSmi(left),
10872 TNode<Smi> smi_left = CAST(left);
10874 Branch(TaggedIsSmi(right),
10876 TNode<Smi> smi_right = CAST(right);
10881 case Operation::kEqual:
10882 BranchIfSmiEqual(smi_left, smi_right, if_true,
10885 case Operation::kLessThan:
10886 BranchIfSmiLessThan(smi_left, smi_right, if_true,
10889 case Operation::kLessThanOrEqual:
10890 BranchIfSmiLessThanOrEqual(smi_left, smi_right, if_true,
10893 case Operation::kGreaterThan:
10894 BranchIfSmiLessThan(smi_right, smi_left, if_true,
10897 case Operation::kGreaterThanOrEqual:
10898 BranchIfSmiLessThanOrEqual(smi_right, smi_left, if_true,
10906 CSA_ASSERT(
this, IsHeapNumber(right));
10907 var_left_float = SmiToFloat64(smi_left);
10908 var_right_float = LoadHeapNumberValue(right);
10909 Goto(&do_float_comparison);
10913 CSA_ASSERT(
this, IsHeapNumber(left));
10914 var_left_float = LoadHeapNumberValue(left);
10916 Branch(TaggedIsSmi(right),
10918 var_right_float = SmiToFloat64(right);
10919 Goto(&do_float_comparison);
10922 CSA_ASSERT(
this, IsHeapNumber(right));
10923 var_right_float = LoadHeapNumberValue(right);
10924 Goto(&do_float_comparison);
10928 BIND(&do_float_comparison);
10931 case Operation::kEqual:
10932 Branch(Float64Equal(var_left_float.value(), var_right_float.value()),
10933 if_true, if_false);
10935 case Operation::kLessThan:
10936 Branch(Float64LessThan(var_left_float.value(), var_right_float.value()),
10937 if_true, if_false);
10939 case Operation::kLessThanOrEqual:
10940 Branch(Float64LessThanOrEqual(var_left_float.value(),
10941 var_right_float.value()),
10942 if_true, if_false);
10944 case Operation::kGreaterThan:
10946 Float64GreaterThan(var_left_float.value(), var_right_float.value()),
10947 if_true, if_false);
10949 case Operation::kGreaterThanOrEqual:
10950 Branch(Float64GreaterThanOrEqual(var_left_float.value(),
10951 var_right_float.value()),
10952 if_true, if_false);
10960 void CodeStubAssembler::GotoIfNumberGreaterThanOrEqual(Node* left, Node* right,
10962 Label if_false(
this);
10963 BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, left,
10964 right, if_true, &if_false);
10969 Operation Reverse(Operation op) {
10971 case Operation::kLessThan:
10972 return Operation::kGreaterThan;
10973 case Operation::kLessThanOrEqual:
10974 return Operation::kGreaterThanOrEqual;
10975 case Operation::kGreaterThan:
10976 return Operation::kLessThan;
10977 case Operation::kGreaterThanOrEqual:
10978 return Operation::kLessThanOrEqual;
10986 Node* CodeStubAssembler::RelationalComparison(Operation op, Node* left,
10987 Node* right, Node* context,
10988 Variable* var_type_feedback) {
10989 Label return_true(
this), return_false(
this), do_float_comparison(
this),
10991 TVARIABLE(Oddball, var_result);
10992 TVARIABLE(Float64T, var_left_float);
10993 TVARIABLE(Float64T, var_right_float);
10997 VARIABLE(var_left, MachineRepresentation::kTagged, left);
10998 VARIABLE(var_right, MachineRepresentation::kTagged, right);
10999 VariableList loop_variable_list({&var_left, &var_right}, zone());
11000 if (var_type_feedback !=
nullptr) {
11003 var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kNone));
11004 loop_variable_list.push_back(var_type_feedback);
11006 Label loop(
this, loop_variable_list);
11010 left = var_left.value();
11011 right = var_right.value();
11013 Label if_left_smi(
this), if_left_not_smi(
this);
11014 Branch(TaggedIsSmi(left), &if_left_smi, &if_left_not_smi);
11016 BIND(&if_left_smi);
11018 TNode<Smi> smi_left = CAST(left);
11019 Label if_right_smi(
this), if_right_heapnumber(
this),
11020 if_right_bigint(
this, Label::kDeferred),
11021 if_right_not_numeric(
this, Label::kDeferred);
11022 GotoIf(TaggedIsSmi(right), &if_right_smi);
11023 Node* right_map = LoadMap(right);
11024 GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber);
11025 Node* right_instance_type = LoadMapInstanceType(right_map);
11026 Branch(IsBigIntInstanceType(right_instance_type), &if_right_bigint,
11027 &if_right_not_numeric);
11029 BIND(&if_right_smi);
11031 TNode<Smi> smi_right = CAST(right);
11032 CombineFeedback(var_type_feedback,
11033 CompareOperationFeedback::kSignedSmall);
11035 case Operation::kLessThan:
11036 BranchIfSmiLessThan(smi_left, smi_right, &return_true,
11039 case Operation::kLessThanOrEqual:
11040 BranchIfSmiLessThanOrEqual(smi_left, smi_right, &return_true,
11043 case Operation::kGreaterThan:
11044 BranchIfSmiLessThan(smi_right, smi_left, &return_true,
11047 case Operation::kGreaterThanOrEqual:
11048 BranchIfSmiLessThanOrEqual(smi_right, smi_left, &return_true,
11056 BIND(&if_right_heapnumber);
11058 CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
11059 var_left_float = SmiToFloat64(smi_left);
11060 var_right_float = LoadHeapNumberValue(right);
11061 Goto(&do_float_comparison);
11064 BIND(&if_right_bigint);
11066 OverwriteFeedback(var_type_feedback, CompareOperationFeedback::kAny);
11067 var_result = CAST(CallRuntime(Runtime::kBigIntCompareToNumber,
11068 NoContextConstant(),
11069 SmiConstant(Reverse(op)), right, left));
11073 BIND(&if_right_not_numeric);
11075 OverwriteFeedback(var_type_feedback, CompareOperationFeedback::kAny);
11081 CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
11086 BIND(&if_left_not_smi);
11088 Node* left_map = LoadMap(left);
11090 Label if_right_smi(
this), if_right_not_smi(
this);
11091 Branch(TaggedIsSmi(right), &if_right_smi, &if_right_not_smi);
11093 BIND(&if_right_smi);
11095 Label if_left_heapnumber(
this), if_left_bigint(
this, Label::kDeferred),
11096 if_left_not_numeric(
this, Label::kDeferred);
11097 GotoIf(IsHeapNumberMap(left_map), &if_left_heapnumber);
11098 Node* left_instance_type = LoadMapInstanceType(left_map);
11099 Branch(IsBigIntInstanceType(left_instance_type), &if_left_bigint,
11100 &if_left_not_numeric);
11102 BIND(&if_left_heapnumber);
11104 CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
11105 var_left_float = LoadHeapNumberValue(left);
11106 var_right_float = SmiToFloat64(right);
11107 Goto(&do_float_comparison);
11110 BIND(&if_left_bigint);
11112 OverwriteFeedback(var_type_feedback, CompareOperationFeedback::kAny);
11113 var_result = CAST(CallRuntime(Runtime::kBigIntCompareToNumber,
11114 NoContextConstant(), SmiConstant(op),
11119 BIND(&if_left_not_numeric);
11121 OverwriteFeedback(var_type_feedback, CompareOperationFeedback::kAny);
11127 CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
11132 BIND(&if_right_not_smi);
11134 Node* right_map = LoadMap(right);
11136 Label if_left_heapnumber(
this), if_left_bigint(
this, Label::kDeferred),
11137 if_left_string(
this), if_left_other(
this, Label::kDeferred);
11138 GotoIf(IsHeapNumberMap(left_map), &if_left_heapnumber);
11139 Node* left_instance_type = LoadMapInstanceType(left_map);
11140 GotoIf(IsBigIntInstanceType(left_instance_type), &if_left_bigint);
11141 Branch(IsStringInstanceType(left_instance_type), &if_left_string,
11144 BIND(&if_left_heapnumber);
11146 Label if_right_heapnumber(
this),
11147 if_right_bigint(
this, Label::kDeferred),
11148 if_right_not_numeric(
this, Label::kDeferred);
11149 GotoIf(WordEqual(right_map, left_map), &if_right_heapnumber);
11150 Node* right_instance_type = LoadMapInstanceType(right_map);
11151 Branch(IsBigIntInstanceType(right_instance_type), &if_right_bigint,
11152 &if_right_not_numeric);
11154 BIND(&if_right_heapnumber);
11156 CombineFeedback(var_type_feedback,
11157 CompareOperationFeedback::kNumber);
11158 var_left_float = LoadHeapNumberValue(left);
11159 var_right_float = LoadHeapNumberValue(right);
11160 Goto(&do_float_comparison);
11163 BIND(&if_right_bigint);
11165 OverwriteFeedback(var_type_feedback,
11166 CompareOperationFeedback::kAny);
11167 var_result = CAST(CallRuntime(
11168 Runtime::kBigIntCompareToNumber, NoContextConstant(),
11169 SmiConstant(Reverse(op)), right, left));
11173 BIND(&if_right_not_numeric);
11175 OverwriteFeedback(var_type_feedback,
11176 CompareOperationFeedback::kAny);
11182 CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
11187 BIND(&if_left_bigint);
11189 Label if_right_heapnumber(
this), if_right_bigint(
this),
11190 if_right_string(
this), if_right_other(
this);
11191 GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber);
11192 Node* right_instance_type = LoadMapInstanceType(right_map);
11193 GotoIf(IsBigIntInstanceType(right_instance_type), &if_right_bigint);
11194 Branch(IsStringInstanceType(right_instance_type), &if_right_string,
11197 BIND(&if_right_heapnumber);
11199 OverwriteFeedback(var_type_feedback,
11200 CompareOperationFeedback::kAny);
11201 var_result = CAST(CallRuntime(Runtime::kBigIntCompareToNumber,
11202 NoContextConstant(), SmiConstant(op),
11207 BIND(&if_right_bigint);
11209 CombineFeedback(var_type_feedback,
11210 CompareOperationFeedback::kBigInt);
11211 var_result = CAST(CallRuntime(Runtime::kBigIntCompareToBigInt,
11212 NoContextConstant(), SmiConstant(op),
11217 BIND(&if_right_string);
11219 OverwriteFeedback(var_type_feedback,
11220 CompareOperationFeedback::kAny);
11221 var_result = CAST(CallRuntime(Runtime::kBigIntCompareToString,
11222 NoContextConstant(), SmiConstant(op),
11228 BIND(&if_right_other);
11230 OverwriteFeedback(var_type_feedback,
11231 CompareOperationFeedback::kAny);
11237 CallBuiltin(Builtins::kNonNumberToNumeric, context, right));
11242 BIND(&if_left_string);
11244 Node* right_instance_type = LoadMapInstanceType(right_map);
11246 Label if_right_not_string(
this, Label::kDeferred);
11247 GotoIfNot(IsStringInstanceType(right_instance_type),
11248 &if_right_not_string);
11251 CombineFeedback(var_type_feedback, CompareOperationFeedback::kString);
11252 Builtins::Name builtin;
11254 case Operation::kLessThan:
11255 builtin = Builtins::kStringLessThan;
11257 case Operation::kLessThanOrEqual:
11258 builtin = Builtins::kStringLessThanOrEqual;
11260 case Operation::kGreaterThan:
11261 builtin = Builtins::kStringGreaterThan;
11263 case Operation::kGreaterThanOrEqual:
11264 builtin = Builtins::kStringGreaterThanOrEqual;
11269 var_result = CAST(CallBuiltin(builtin, context, left, right));
11272 BIND(&if_right_not_string);
11274 OverwriteFeedback(var_type_feedback,
11275 CompareOperationFeedback::kAny);
11280 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
11281 Label if_right_bigint(
this),
11282 if_right_receiver(
this, Label::kDeferred);
11283 GotoIf(IsBigIntInstanceType(right_instance_type), &if_right_bigint);
11284 GotoIf(IsJSReceiverInstanceType(right_instance_type),
11285 &if_right_receiver);
11288 CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
11289 var_right.Bind(CallBuiltin(Builtins::kToNumeric, context, right));
11292 BIND(&if_right_bigint);
11294 var_result = CAST(CallRuntime(
11295 Runtime::kBigIntCompareToString, NoContextConstant(),
11296 SmiConstant(Reverse(op)), right, left));
11300 BIND(&if_right_receiver);
11302 Callable callable = CodeFactory::NonPrimitiveToPrimitive(
11303 isolate(), ToPrimitiveHint::kNumber);
11304 var_right.Bind(CallStub(callable, context, right));
11310 BIND(&if_left_other);
11313 if (var_type_feedback !=
nullptr) {
11317 Label collect_any_feedback(
this), collect_oddball_feedback(
this),
11318 collect_feedback_done(
this);
11319 GotoIfNot(InstanceTypeEqual(left_instance_type, ODDBALL_TYPE),
11320 &collect_any_feedback);
11322 GotoIf(IsHeapNumberMap(right_map), &collect_oddball_feedback);
11323 Node* right_instance_type = LoadMapInstanceType(right_map);
11324 Branch(InstanceTypeEqual(right_instance_type, ODDBALL_TYPE),
11325 &collect_oddball_feedback, &collect_any_feedback);
11327 BIND(&collect_oddball_feedback);
11329 CombineFeedback(var_type_feedback,
11330 CompareOperationFeedback::kNumberOrOddball);
11331 Goto(&collect_feedback_done);
11334 BIND(&collect_any_feedback);
11336 OverwriteFeedback(var_type_feedback,
11337 CompareOperationFeedback::kAny);
11338 Goto(&collect_feedback_done);
11341 BIND(&collect_feedback_done);
11347 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
11348 Label if_left_receiver(
this, Label::kDeferred);
11349 GotoIf(IsJSReceiverInstanceType(left_instance_type),
11350 &if_left_receiver);
11352 var_right.Bind(CallBuiltin(Builtins::kToNumeric, context, right));
11354 CallBuiltin(Builtins::kNonNumberToNumeric, context, left));
11357 BIND(&if_left_receiver);
11359 Callable callable = CodeFactory::NonPrimitiveToPrimitive(
11360 isolate(), ToPrimitiveHint::kNumber);
11361 var_left.Bind(CallStub(callable, context, left));
11369 BIND(&do_float_comparison);
11372 case Operation::kLessThan:
11373 Branch(Float64LessThan(var_left_float.value(), var_right_float.value()),
11374 &return_true, &return_false);
11376 case Operation::kLessThanOrEqual:
11377 Branch(Float64LessThanOrEqual(var_left_float.value(),
11378 var_right_float.value()),
11379 &return_true, &return_false);
11381 case Operation::kGreaterThan:
11383 Float64GreaterThan(var_left_float.value(), var_right_float.value()),
11384 &return_true, &return_false);
11386 case Operation::kGreaterThanOrEqual:
11387 Branch(Float64GreaterThanOrEqual(var_left_float.value(),
11388 var_right_float.value()),
11389 &return_true, &return_false);
11396 BIND(&return_true);
11398 var_result = TrueConstant();
11402 BIND(&return_false);
11404 var_result = FalseConstant();
11409 return var_result.value();
11412 TNode<Smi> CodeStubAssembler::CollectFeedbackForString(
11413 SloppyTNode<Int32T> instance_type) {
11414 TNode<Smi> feedback = SelectSmiConstant(
11416 Word32And(instance_type, Int32Constant(kIsNotInternalizedMask)),
11417 Int32Constant(kInternalizedTag)),
11418 CompareOperationFeedback::kInternalizedString,
11419 CompareOperationFeedback::kString);
11423 void CodeStubAssembler::GenerateEqual_Same(Node* value, Label* if_equal,
11424 Label* if_notequal,
11425 Variable* var_type_feedback) {
11430 Label if_smi(
this), if_heapnumber(
this);
11431 GotoIf(TaggedIsSmi(value), &if_smi);
11433 Node* value_map = LoadMap(value);
11434 GotoIf(IsHeapNumberMap(value_map), &if_heapnumber);
11437 if (var_type_feedback !=
nullptr) {
11438 Node* instance_type = LoadMapInstanceType(value_map);
11440 Label if_string(
this), if_receiver(
this), if_oddball(
this), if_symbol(
this),
11442 GotoIf(IsStringInstanceType(instance_type), &if_string);
11443 GotoIf(IsJSReceiverInstanceType(instance_type), &if_receiver);
11444 GotoIf(IsOddballInstanceType(instance_type), &if_oddball);
11445 Branch(IsBigIntInstanceType(instance_type), &if_bigint, &if_symbol);
11449 CSA_ASSERT(
this, IsString(value));
11450 CombineFeedback(var_type_feedback,
11451 CollectFeedbackForString(instance_type));
11457 CSA_ASSERT(
this, IsSymbol(value));
11458 CombineFeedback(var_type_feedback, CompareOperationFeedback::kSymbol);
11462 BIND(&if_receiver);
11464 CSA_ASSERT(
this, IsJSReceiver(value));
11465 CombineFeedback(var_type_feedback, CompareOperationFeedback::kReceiver);
11471 CSA_ASSERT(
this, IsBigInt(value));
11472 CombineFeedback(var_type_feedback, CompareOperationFeedback::kBigInt);
11478 CSA_ASSERT(
this, IsOddball(value));
11479 Label if_boolean(
this), if_not_boolean(
this);
11480 Branch(IsBooleanMap(value_map), &if_boolean, &if_not_boolean);
11484 CombineFeedback(var_type_feedback, CompareOperationFeedback::kAny);
11488 BIND(&if_not_boolean);
11490 CSA_ASSERT(
this, IsNullOrUndefined(value));
11491 CombineFeedback(var_type_feedback,
11492 CompareOperationFeedback::kReceiverOrNullOrUndefined);
11500 BIND(&if_heapnumber);
11502 CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
11503 Node* number_value = LoadHeapNumberValue(value);
11504 BranchIfFloat64IsNaN(number_value, if_notequal, if_equal);
11509 CombineFeedback(var_type_feedback, CompareOperationFeedback::kSignedSmall);
11515 Node* CodeStubAssembler::Equal(Node* left, Node* right, Node* context,
11516 Variable* var_type_feedback) {
11521 Label if_equal(
this), if_notequal(
this), do_float_comparison(
this),
11522 do_right_stringtonumber(
this, Label::kDeferred), end(
this);
11523 VARIABLE(result, MachineRepresentation::kTagged);
11524 TVARIABLE(Float64T, var_left_float);
11525 TVARIABLE(Float64T, var_right_float);
11529 Label use_symmetry(
this);
11533 VARIABLE(var_left, MachineRepresentation::kTagged, left);
11534 VARIABLE(var_right, MachineRepresentation::kTagged, right);
11535 VariableList loop_variable_list({&var_left, &var_right}, zone());
11536 if (var_type_feedback !=
nullptr) {
11539 OverwriteFeedback(var_type_feedback, CompareOperationFeedback::kNone);
11540 loop_variable_list.push_back(var_type_feedback);
11542 Label loop(
this, loop_variable_list);
11546 left = var_left.value();
11547 right = var_right.value();
11549 Label if_notsame(
this);
11550 GotoIf(WordNotEqual(left, right), &if_notsame);
11554 GenerateEqual_Same(left, &if_equal, &if_notequal, var_type_feedback);
11558 Label if_left_smi(
this), if_left_not_smi(
this);
11559 Branch(TaggedIsSmi(left), &if_left_smi, &if_left_not_smi);
11561 BIND(&if_left_smi);
11563 Label if_right_smi(
this), if_right_not_smi(
this);
11564 Branch(TaggedIsSmi(right), &if_right_smi, &if_right_not_smi);
11566 BIND(&if_right_smi);
11570 CombineFeedback(var_type_feedback,
11571 CompareOperationFeedback::kSignedSmall);
11572 Goto(&if_notequal);
11575 BIND(&if_right_not_smi);
11576 Node* right_map = LoadMap(right);
11577 Label if_right_heapnumber(
this), if_right_boolean(
this),
11578 if_right_bigint(
this, Label::kDeferred),
11579 if_right_receiver(
this, Label::kDeferred);
11580 GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber);
11582 if (var_type_feedback !=
nullptr) {
11583 var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny));
11585 GotoIf(IsBooleanMap(right_map), &if_right_boolean);
11586 Node* right_type = LoadMapInstanceType(right_map);
11587 GotoIf(IsStringInstanceType(right_type), &do_right_stringtonumber);
11588 GotoIf(IsBigIntInstanceType(right_type), &if_right_bigint);
11589 Branch(IsJSReceiverInstanceType(right_type), &if_right_receiver,
11592 BIND(&if_right_heapnumber);
11594 var_left_float = SmiToFloat64(left);
11595 var_right_float = LoadHeapNumberValue(right);
11596 CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
11597 Goto(&do_float_comparison);
11600 BIND(&if_right_boolean);
11602 var_right.Bind(LoadObjectField(right, Oddball::kToNumberOffset));
11606 BIND(&if_right_bigint);
11608 result.Bind(CallRuntime(Runtime::kBigIntEqualToNumber,
11609 NoContextConstant(), right, left));
11613 BIND(&if_right_receiver);
11615 Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
11616 var_right.Bind(CallStub(callable, context, right));
11621 BIND(&if_left_not_smi);
11623 GotoIf(TaggedIsSmi(right), &use_symmetry);
11625 Label if_left_symbol(
this), if_left_number(
this), if_left_string(
this),
11626 if_left_bigint(
this, Label::kDeferred), if_left_oddball(
this),
11627 if_left_receiver(
this);
11629 Node* left_map = LoadMap(left);
11630 Node* right_map = LoadMap(right);
11631 Node* left_type = LoadMapInstanceType(left_map);
11632 Node* right_type = LoadMapInstanceType(right_map);
11634 GotoIf(IsStringInstanceType(left_type), &if_left_string);
11635 GotoIf(IsSymbolInstanceType(left_type), &if_left_symbol);
11636 GotoIf(IsHeapNumberInstanceType(left_type), &if_left_number);
11637 GotoIf(IsOddballInstanceType(left_type), &if_left_oddball);
11638 Branch(IsBigIntInstanceType(left_type), &if_left_bigint,
11639 &if_left_receiver);
11641 BIND(&if_left_string);
11643 GotoIfNot(IsStringInstanceType(right_type), &use_symmetry);
11644 result.Bind(CallBuiltin(Builtins::kStringEqual, context, left, right));
11645 CombineFeedback(var_type_feedback,
11646 SmiOr(CollectFeedbackForString(left_type),
11647 CollectFeedbackForString(right_type)));
11651 BIND(&if_left_number);
11653 Label if_right_not_number(
this);
11654 GotoIf(Word32NotEqual(left_type, right_type), &if_right_not_number);
11656 var_left_float = LoadHeapNumberValue(left);
11657 var_right_float = LoadHeapNumberValue(right);
11658 CombineFeedback(var_type_feedback, CompareOperationFeedback::kNumber);
11659 Goto(&do_float_comparison);
11661 BIND(&if_right_not_number);
11663 Label if_right_boolean(
this);
11664 if (var_type_feedback !=
nullptr) {
11665 var_type_feedback->Bind(
11666 SmiConstant(CompareOperationFeedback::kAny));
11668 GotoIf(IsStringInstanceType(right_type), &do_right_stringtonumber);
11669 GotoIf(IsBooleanMap(right_map), &if_right_boolean);
11670 GotoIf(IsBigIntInstanceType(right_type), &use_symmetry);
11671 Branch(IsJSReceiverInstanceType(right_type), &use_symmetry,
11674 BIND(&if_right_boolean);
11676 var_right.Bind(LoadObjectField(right, Oddball::kToNumberOffset));
11682 BIND(&if_left_bigint);
11684 Label if_right_heapnumber(
this), if_right_bigint(
this),
11685 if_right_string(
this), if_right_boolean(
this);
11686 GotoIf(IsHeapNumberMap(right_map), &if_right_heapnumber);
11687 GotoIf(IsBigIntInstanceType(right_type), &if_right_bigint);
11688 GotoIf(IsStringInstanceType(right_type), &if_right_string);
11689 GotoIf(IsBooleanMap(right_map), &if_right_boolean);
11690 Branch(IsJSReceiverInstanceType(right_type), &use_symmetry,
11693 BIND(&if_right_heapnumber);
11695 if (var_type_feedback !=
nullptr) {
11696 var_type_feedback->Bind(
11697 SmiConstant(CompareOperationFeedback::kAny));
11699 result.Bind(CallRuntime(Runtime::kBigIntEqualToNumber,
11700 NoContextConstant(), left, right));
11704 BIND(&if_right_bigint);
11706 CombineFeedback(var_type_feedback, CompareOperationFeedback::kBigInt);
11707 result.Bind(CallRuntime(Runtime::kBigIntEqualToBigInt,
11708 NoContextConstant(), left, right));
11712 BIND(&if_right_string);
11714 if (var_type_feedback !=
nullptr) {
11715 var_type_feedback->Bind(
11716 SmiConstant(CompareOperationFeedback::kAny));
11718 result.Bind(CallRuntime(Runtime::kBigIntEqualToString,
11719 NoContextConstant(), left, right));
11723 BIND(&if_right_boolean);
11725 if (var_type_feedback !=
nullptr) {
11726 var_type_feedback->Bind(
11727 SmiConstant(CompareOperationFeedback::kAny));
11729 var_right.Bind(LoadObjectField(right, Oddball::kToNumberOffset));
11734 BIND(&if_left_oddball);
11736 Label if_left_boolean(
this), if_left_not_boolean(
this);
11737 Branch(IsBooleanMap(left_map), &if_left_boolean, &if_left_not_boolean);
11739 BIND(&if_left_not_boolean);
11743 Label if_right_undetectable(
this), if_right_not_undetectable(
this);
11744 Branch(IsUndetectableMap(right_map), &if_right_undetectable,
11745 &if_right_not_undetectable);
11747 BIND(&if_right_undetectable);
11749 if (var_type_feedback !=
nullptr) {
11752 var_type_feedback->Bind(SmiConstant(
11753 CompareOperationFeedback::kReceiverOrNullOrUndefined));
11758 BIND(&if_right_not_undetectable);
11760 if (var_type_feedback !=
nullptr) {
11762 var_type_feedback->Bind(SmiConstant(
11763 CompareOperationFeedback::kReceiverOrNullOrUndefined));
11764 GotoIf(IsJSReceiverInstanceType(right_type), &if_notequal);
11765 GotoIfNot(IsBooleanMap(right_map), &if_notequal);
11766 var_type_feedback->Bind(
11767 SmiConstant(CompareOperationFeedback::kAny));
11769 Goto(&if_notequal);
11773 BIND(&if_left_boolean);
11775 if (var_type_feedback !=
nullptr) {
11776 var_type_feedback->Bind(
11777 SmiConstant(CompareOperationFeedback::kAny));
11781 GotoIf(WordEqual(right_map, left_map), &if_notequal);
11784 var_left.Bind(LoadObjectField(left, Oddball::kToNumberOffset));
11789 BIND(&if_left_symbol);
11791 Label if_right_receiver(
this);
11792 GotoIf(IsJSReceiverInstanceType(right_type), &if_right_receiver);
11795 if (var_type_feedback !=
nullptr) {
11796 Label if_right_symbol(
this);
11797 GotoIf(IsSymbolInstanceType(right_type), &if_right_symbol);
11798 var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny));
11799 Goto(&if_notequal);
11801 BIND(&if_right_symbol);
11803 CombineFeedback(var_type_feedback,
11804 CompareOperationFeedback::kSymbol);
11805 Goto(&if_notequal);
11808 Goto(&if_notequal);
11811 BIND(&if_right_receiver);
11815 if (var_type_feedback !=
nullptr) {
11816 var_type_feedback->Bind(
11817 SmiConstant(CompareOperationFeedback::kAny));
11819 Goto(&use_symmetry);
11823 BIND(&if_left_receiver);
11825 CSA_ASSERT(
this, IsJSReceiverInstanceType(left_type));
11826 Label if_right_receiver(
this), if_right_not_receiver(
this);
11827 Branch(IsJSReceiverInstanceType(right_type), &if_right_receiver,
11828 &if_right_not_receiver);
11830 BIND(&if_right_receiver);
11833 CombineFeedback(var_type_feedback,
11834 CompareOperationFeedback::kReceiver);
11835 Goto(&if_notequal);
11838 BIND(&if_right_not_receiver);
11842 Label if_right_undetectable(
this),
11843 if_right_not_undetectable(
this, Label::kDeferred);
11844 Branch(IsUndetectableMap(right_map), &if_right_undetectable,
11845 &if_right_not_undetectable);
11847 BIND(&if_right_undetectable);
11850 CSA_ASSERT(
this, IsNullOrUndefined(right));
11851 if (var_type_feedback !=
nullptr) {
11852 var_type_feedback->Bind(SmiConstant(
11853 CompareOperationFeedback::kReceiverOrNullOrUndefined));
11855 Branch(IsUndetectableMap(left_map), &if_equal, &if_notequal);
11858 BIND(&if_right_not_undetectable);
11862 if (var_type_feedback !=
nullptr) {
11863 var_type_feedback->Bind(
11864 SmiConstant(CompareOperationFeedback::kAny));
11866 Callable callable = CodeFactory::NonPrimitiveToPrimitive(isolate());
11867 var_left.Bind(CallStub(callable, context, left));
11874 BIND(&do_right_stringtonumber);
11876 var_right.Bind(CallBuiltin(Builtins::kStringToNumber, context, right));
11880 BIND(&use_symmetry);
11882 var_left.Bind(right);
11883 var_right.Bind(left);
11888 BIND(&do_float_comparison);
11890 Branch(Float64Equal(var_left_float.value(), var_right_float.value()),
11891 &if_equal, &if_notequal);
11896 result.Bind(TrueConstant());
11900 BIND(&if_notequal);
11902 result.Bind(FalseConstant());
11907 return result.value();
11910 Node* CodeStubAssembler::StrictEqual(Node* lhs, Node* rhs,
11911 Variable* var_type_feedback) {
11961 Label if_equal(
this), if_notequal(
this), end(
this);
11962 VARIABLE(result, MachineRepresentation::kTagged);
11965 Label if_same(
this), if_notsame(
this);
11966 Branch(WordEqual(lhs, rhs), &if_same, &if_notsame);
11972 if (var_type_feedback !=
nullptr) {
11973 var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kNone));
11975 GenerateEqual_Same(lhs, &if_equal, &if_notequal, var_type_feedback);
11983 if (var_type_feedback !=
nullptr) {
11984 var_type_feedback->Bind(SmiConstant(CompareOperationFeedback::kAny));
11988 Label if_lhsissmi(
this), if_lhsisnotsmi(
this);
11989 Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
11991 BIND(&if_lhsisnotsmi);
11994 Node* lhs_map = LoadMap(lhs);
11997 Label if_lhsisnumber(
this), if_lhsisnotnumber(
this);
11998 Branch(IsHeapNumberMap(lhs_map), &if_lhsisnumber, &if_lhsisnotnumber);
12000 BIND(&if_lhsisnumber);
12003 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
12004 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
12006 BIND(&if_rhsissmi);
12009 Node* lhs_value = LoadHeapNumberValue(lhs);
12010 Node* rhs_value = SmiToFloat64(rhs);
12012 if (var_type_feedback !=
nullptr) {
12013 var_type_feedback->Bind(
12014 SmiConstant(CompareOperationFeedback::kNumber));
12018 Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
12021 BIND(&if_rhsisnotsmi);
12024 Node* rhs_map = LoadMap(rhs);
12027 Label if_rhsisnumber(
this), if_rhsisnotnumber(
this);
12028 Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber);
12030 BIND(&if_rhsisnumber);
12033 Node* lhs_value = LoadHeapNumberValue(lhs);
12034 Node* rhs_value = LoadHeapNumberValue(rhs);
12036 if (var_type_feedback !=
nullptr) {
12037 var_type_feedback->Bind(
12038 SmiConstant(CompareOperationFeedback::kNumber));
12042 Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
12045 BIND(&if_rhsisnotnumber);
12046 Goto(&if_notequal);
12050 BIND(&if_lhsisnotnumber);
12053 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
12054 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
12056 BIND(&if_rhsissmi);
12057 Goto(&if_notequal);
12059 BIND(&if_rhsisnotsmi);
12062 Node* lhs_instance_type = LoadMapInstanceType(lhs_map);
12065 Label if_lhsisstring(
this), if_lhsisnotstring(
this);
12066 Branch(IsStringInstanceType(lhs_instance_type), &if_lhsisstring,
12067 &if_lhsisnotstring);
12069 BIND(&if_lhsisstring);
12072 Node* rhs_instance_type = LoadInstanceType(rhs);
12075 Label if_rhsisstring(
this, Label::kDeferred),
12076 if_rhsisnotstring(
this);
12077 Branch(IsStringInstanceType(rhs_instance_type), &if_rhsisstring,
12078 &if_rhsisnotstring);
12080 BIND(&if_rhsisstring);
12082 if (var_type_feedback !=
nullptr) {
12083 TNode<Smi> lhs_feedback =
12084 CollectFeedbackForString(lhs_instance_type);
12085 TNode<Smi> rhs_feedback =
12086 CollectFeedbackForString(rhs_instance_type);
12087 var_type_feedback->Bind(SmiOr(lhs_feedback, rhs_feedback));
12089 result.Bind(CallBuiltin(Builtins::kStringEqual,
12090 NoContextConstant(), lhs, rhs));
12094 BIND(&if_rhsisnotstring);
12095 Goto(&if_notequal);
12098 BIND(&if_lhsisnotstring);
12101 Label if_lhsisbigint(
this), if_lhsisnotbigint(
this);
12102 Branch(IsBigIntInstanceType(lhs_instance_type), &if_lhsisbigint,
12103 &if_lhsisnotbigint);
12105 BIND(&if_lhsisbigint);
12108 Node* rhs_instance_type = LoadInstanceType(rhs);
12111 Label if_rhsisbigint(
this, Label::kDeferred),
12112 if_rhsisnotbigint(
this);
12113 Branch(IsBigIntInstanceType(rhs_instance_type), &if_rhsisbigint,
12114 &if_rhsisnotbigint);
12116 BIND(&if_rhsisbigint);
12118 if (var_type_feedback !=
nullptr) {
12119 var_type_feedback->Bind(
12120 SmiConstant(CompareOperationFeedback::kBigInt));
12122 result.Bind(CallRuntime(Runtime::kBigIntEqualToBigInt,
12123 NoContextConstant(), lhs, rhs));
12127 BIND(&if_rhsisnotbigint);
12128 Goto(&if_notequal);
12131 BIND(&if_lhsisnotbigint);
12132 if (var_type_feedback !=
nullptr) {
12134 Node* rhs_map = LoadMap(rhs);
12135 Node* rhs_instance_type = LoadMapInstanceType(rhs_map);
12137 Label if_lhsissymbol(
this), if_lhsisreceiver(
this),
12138 if_lhsisoddball(
this);
12139 GotoIf(IsJSReceiverInstanceType(lhs_instance_type),
12140 &if_lhsisreceiver);
12141 GotoIf(IsBooleanMap(lhs_map), &if_notequal);
12142 GotoIf(IsOddballInstanceType(lhs_instance_type), &if_lhsisoddball);
12143 Branch(IsSymbolInstanceType(lhs_instance_type), &if_lhsissymbol,
12146 BIND(&if_lhsisreceiver);
12148 GotoIf(IsBooleanMap(rhs_map), &if_notequal);
12149 var_type_feedback->Bind(
12150 SmiConstant(CompareOperationFeedback::kReceiver));
12151 GotoIf(IsJSReceiverInstanceType(rhs_instance_type), &if_notequal);
12152 var_type_feedback->Bind(SmiConstant(
12153 CompareOperationFeedback::kReceiverOrNullOrUndefined));
12154 GotoIf(IsOddballInstanceType(rhs_instance_type), &if_notequal);
12155 var_type_feedback->Bind(
12156 SmiConstant(CompareOperationFeedback::kAny));
12157 Goto(&if_notequal);
12160 BIND(&if_lhsisoddball);
12162 STATIC_ASSERT(LAST_PRIMITIVE_TYPE == ODDBALL_TYPE);
12163 GotoIf(IsBooleanMap(rhs_map), &if_notequal);
12165 Int32LessThan(rhs_instance_type, Int32Constant(ODDBALL_TYPE)),
12167 var_type_feedback->Bind(SmiConstant(
12168 CompareOperationFeedback::kReceiverOrNullOrUndefined));
12169 Goto(&if_notequal);
12172 BIND(&if_lhsissymbol);
12174 GotoIfNot(IsSymbolInstanceType(rhs_instance_type), &if_notequal);
12175 var_type_feedback->Bind(
12176 SmiConstant(CompareOperationFeedback::kSymbol));
12177 Goto(&if_notequal);
12180 Goto(&if_notequal);
12186 BIND(&if_lhsissmi);
12193 Label if_rhsissmi(
this), if_rhsisnotsmi(
this);
12194 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
12196 BIND(&if_rhsissmi);
12197 if (var_type_feedback !=
nullptr) {
12198 var_type_feedback->Bind(
12199 SmiConstant(CompareOperationFeedback::kSignedSmall));
12201 Goto(&if_notequal);
12203 BIND(&if_rhsisnotsmi);
12206 Node* rhs_map = LoadMap(rhs);
12209 Label if_rhsisnumber(
this), if_rhsisnotnumber(
this);
12210 Branch(IsHeapNumberMap(rhs_map), &if_rhsisnumber, &if_rhsisnotnumber);
12212 BIND(&if_rhsisnumber);
12215 Node* lhs_value = SmiToFloat64(lhs);
12216 Node* rhs_value = LoadHeapNumberValue(rhs);
12218 if (var_type_feedback !=
nullptr) {
12219 var_type_feedback->Bind(
12220 SmiConstant(CompareOperationFeedback::kNumber));
12224 Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
12227 BIND(&if_rhsisnotnumber);
12228 Goto(&if_notequal);
12235 result.Bind(TrueConstant());
12239 BIND(&if_notequal);
12241 result.Bind(FalseConstant());
12246 return result.value();
12252 void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
12254 VARIABLE(var_lhs_value, MachineRepresentation::kFloat64);
12255 VARIABLE(var_rhs_value, MachineRepresentation::kFloat64);
12256 Label do_fcmp(
this);
12260 GotoIf(WordEqual(lhs, rhs), if_true);
12263 Label if_lhsissmi(
this), if_lhsisheapobject(
this);
12264 Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisheapobject);
12266 BIND(&if_lhsissmi);
12270 Branch(TaggedIsSmi(rhs), if_false, [&] {
12271 GotoIfNot(IsHeapNumber(rhs), if_false);
12272 var_lhs_value.Bind(SmiToFloat64(lhs));
12273 var_rhs_value.Bind(LoadHeapNumberValue(rhs));
12278 BIND(&if_lhsisheapobject);
12281 Branch(TaggedIsSmi(rhs),
12285 GotoIfNot(IsHeapNumber(lhs), if_false);
12286 var_lhs_value.Bind(LoadHeapNumberValue(lhs));
12287 var_rhs_value.Bind(SmiToFloat64(rhs));
12295 Label if_lhsisheapnumber(
this), if_lhsisstring(
this),
12296 if_lhsisbigint(
this);
12297 Node*
const lhs_map = LoadMap(lhs);
12298 GotoIf(IsHeapNumberMap(lhs_map), &if_lhsisheapnumber);
12299 Node*
const lhs_instance_type = LoadMapInstanceType(lhs_map);
12300 GotoIf(IsStringInstanceType(lhs_instance_type), &if_lhsisstring);
12301 Branch(IsBigIntInstanceType(lhs_instance_type), &if_lhsisbigint,
12304 BIND(&if_lhsisheapnumber);
12306 GotoIfNot(IsHeapNumber(rhs), if_false);
12307 var_lhs_value.Bind(LoadHeapNumberValue(lhs));
12308 var_rhs_value.Bind(LoadHeapNumberValue(rhs));
12312 BIND(&if_lhsisstring);
12316 GotoIfNot(IsString(rhs), if_false);
12317 Node*
const result = CallBuiltin(Builtins::kStringEqual,
12318 NoContextConstant(), lhs, rhs);
12319 Branch(IsTrue(result), if_true, if_false);
12322 BIND(&if_lhsisbigint);
12324 GotoIfNot(IsBigInt(rhs), if_false);
12325 Node*
const result = CallRuntime(Runtime::kBigIntEqualToBigInt,
12326 NoContextConstant(), lhs, rhs);
12327 Branch(IsTrue(result), if_true, if_false);
12334 Node*
const lhs_value = var_lhs_value.value();
12335 Node*
const rhs_value = var_rhs_value.value();
12337 Label if_equal(
this), if_notequal(
this);
12338 Branch(Float64Equal(lhs_value, rhs_value), &if_equal, &if_notequal);
12345 Node*
const lhs_hi_word = Float64ExtractHighWord32(lhs_value);
12346 Node*
const rhs_hi_word = Float64ExtractHighWord32(rhs_value);
12350 Branch(Word32Equal(lhs_hi_word, rhs_hi_word), if_true, if_false);
12353 BIND(&if_notequal);
12356 GotoIf(Float64Equal(lhs_value, lhs_value), if_false);
12357 Branch(Float64Equal(rhs_value, rhs_value), if_false, if_true);
12362 TNode<Oddball> CodeStubAssembler::HasProperty(SloppyTNode<Context> context,
12363 SloppyTNode<Object>
object,
12364 SloppyTNode<Object> key,
12365 HasPropertyLookupMode mode) {
12366 Label call_runtime(
this, Label::kDeferred), return_true(
this),
12367 return_false(
this), end(
this), if_proxy(
this, Label::kDeferred);
12369 CodeStubAssembler::LookupInHolder lookup_property_in_holder =
12370 [
this, &return_true](Node* receiver, Node* holder, Node* holder_map,
12371 Node* holder_instance_type, Node* unique_name,
12372 Label* next_holder, Label* if_bailout) {
12373 TryHasOwnProperty(holder, holder_map, holder_instance_type, unique_name,
12374 &return_true, next_holder, if_bailout);
12377 CodeStubAssembler::LookupInHolder lookup_element_in_holder =
12378 [
this, &return_true, &return_false](
12379 Node* receiver, Node* holder, Node* holder_map,
12380 Node* holder_instance_type, Node* index, Label* next_holder,
12381 Label* if_bailout) {
12382 TryLookupElement(holder, holder_map, holder_instance_type, index,
12383 &return_true, &return_false, next_holder, if_bailout);
12386 TryPrototypeChainLookup(
object, key, lookup_property_in_holder,
12387 lookup_element_in_holder, &return_false,
12388 &call_runtime, &if_proxy);
12390 TVARIABLE(Oddball, result);
12394 TNode<Name> name = CAST(CallBuiltin(Builtins::kToName, context, key));
12397 GotoIf(IsPrivateSymbol(name), &return_false);
12400 CallBuiltin(Builtins::kProxyHasProperty, context,
object, name));
12403 case kForInHasProperty:
12404 Goto(&call_runtime);
12409 BIND(&return_true);
12411 result = TrueConstant();
12415 BIND(&return_false);
12417 result = FalseConstant();
12421 BIND(&call_runtime);
12423 Runtime::FunctionId fallback_runtime_function_id;
12426 fallback_runtime_function_id = Runtime::kHasProperty;
12428 case kForInHasProperty:
12429 fallback_runtime_function_id = Runtime::kForInHasProperty;
12434 CAST(CallRuntime(fallback_runtime_function_id, context,
object, key));
12439 CSA_ASSERT(
this, IsBoolean(result.value()));
12440 return result.value();
12443 Node* CodeStubAssembler::Typeof(Node* value) {
12444 VARIABLE(result_var, MachineRepresentation::kTagged);
12446 Label return_number(
this, Label::kDeferred), if_oddball(
this),
12447 return_function(
this), return_undefined(
this), return_object(
this),
12448 return_string(
this), return_bigint(
this), return_result(
this);
12450 GotoIf(TaggedIsSmi(value), &return_number);
12452 Node* map = LoadMap(value);
12454 GotoIf(IsHeapNumberMap(map), &return_number);
12456 Node* instance_type = LoadMapInstanceType(map);
12458 GotoIf(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &if_oddball);
12460 Node* callable_or_undetectable_mask = Word32And(
12461 LoadMapBitField(map),
12462 Int32Constant(Map::IsCallableBit::kMask | Map::IsUndetectableBit::kMask));
12464 GotoIf(Word32Equal(callable_or_undetectable_mask,
12465 Int32Constant(Map::IsCallableBit::kMask)),
12468 GotoIfNot(Word32Equal(callable_or_undetectable_mask, Int32Constant(0)),
12469 &return_undefined);
12471 GotoIf(IsJSReceiverInstanceType(instance_type), &return_object);
12473 GotoIf(IsStringInstanceType(instance_type), &return_string);
12475 GotoIf(IsBigIntInstanceType(instance_type), &return_bigint);
12477 CSA_ASSERT(
this, InstanceTypeEqual(instance_type, SYMBOL_TYPE));
12478 result_var.Bind(HeapConstant(isolate()->factory()->symbol_string()));
12479 Goto(&return_result);
12481 BIND(&return_number);
12483 result_var.Bind(HeapConstant(isolate()->factory()->number_string()));
12484 Goto(&return_result);
12489 Node* type = LoadObjectField(value, Oddball::kTypeOfOffset);
12490 result_var.Bind(type);
12491 Goto(&return_result);
12494 BIND(&return_function);
12496 result_var.Bind(HeapConstant(isolate()->factory()->function_string()));
12497 Goto(&return_result);
12500 BIND(&return_undefined);
12502 result_var.Bind(HeapConstant(isolate()->factory()->undefined_string()));
12503 Goto(&return_result);
12506 BIND(&return_object);
12508 result_var.Bind(HeapConstant(isolate()->factory()->object_string()));
12509 Goto(&return_result);
12512 BIND(&return_string);
12514 result_var.Bind(HeapConstant(isolate()->factory()->string_string()));
12515 Goto(&return_result);
12518 BIND(&return_bigint);
12520 result_var.Bind(HeapConstant(isolate()->factory()->bigint_string()));
12521 Goto(&return_result);
12524 BIND(&return_result);
12525 return result_var.value();
12528 TNode<Object> CodeStubAssembler::GetSuperConstructor(
12529 SloppyTNode<Context> context, SloppyTNode<JSFunction> active_function) {
12530 Label is_not_constructor(
this, Label::kDeferred), out(
this);
12531 TVARIABLE(Object, result);
12533 TNode<Map> map = LoadMap(active_function);
12534 TNode<Object> prototype = LoadMapPrototype(map);
12535 TNode<Map> prototype_map = LoadMap(CAST(prototype));
12536 GotoIfNot(IsConstructorMap(prototype_map), &is_not_constructor);
12538 result = prototype;
12541 BIND(&is_not_constructor);
12543 CallRuntime(Runtime::kThrowNotSuperConstructor, context, prototype,
12549 return result.value();
12552 TNode<JSReceiver> CodeStubAssembler::SpeciesConstructor(
12553 SloppyTNode<Context> context, SloppyTNode<Object>
object,
12554 SloppyTNode<JSReceiver> default_constructor) {
12555 Isolate* isolate = this->isolate();
12556 TVARIABLE(JSReceiver, var_result, default_constructor);
12559 TNode<Object> constructor =
12560 GetProperty(context,
object, isolate->factory()->constructor_string());
12564 GotoIf(IsUndefined(constructor), &out);
12567 ThrowIfNotJSReceiver(context, constructor,
12568 MessageTemplate::kConstructorNotReceiver);
12571 TNode<Object> species =
12572 GetProperty(context, constructor, isolate->factory()->species_symbol());
12575 GotoIf(IsNullOrUndefined(species), &out);
12578 Label throw_error(
this);
12579 GotoIf(TaggedIsSmi(species), &throw_error);
12580 GotoIfNot(IsConstructorMap(LoadMap(CAST(species))), &throw_error);
12581 var_result = CAST(species);
12585 BIND(&throw_error);
12586 ThrowTypeError(context, MessageTemplate::kSpeciesNotConstructor);
12589 return var_result.value();
12592 Node* CodeStubAssembler::InstanceOf(Node*
object, Node* callable,
12594 VARIABLE(var_result, MachineRepresentation::kTagged);
12595 Label if_notcallable(
this, Label::kDeferred),
12596 if_notreceiver(
this, Label::kDeferred), if_otherhandler(
this),
12597 if_nohandler(
this, Label::kDeferred), return_true(
this),
12598 return_false(
this), return_result(
this, &var_result);
12601 GotoIf(TaggedIsSmi(callable), &if_notreceiver);
12602 GotoIfNot(IsJSReceiver(callable), &if_notreceiver);
12605 Node* inst_of_handler =
12606 GetProperty(context, callable, HasInstanceSymbolConstant());
12611 Node* native_context = LoadNativeContext(context);
12612 Node* function_has_instance =
12613 LoadContextElement(native_context, Context::FUNCTION_HAS_INSTANCE_INDEX);
12614 GotoIfNot(WordEqual(inst_of_handler, function_has_instance),
12618 Callable builtin(BUILTIN_CODE(isolate(), FunctionPrototypeHasInstance),
12619 CallTrampolineDescriptor{});
12620 Node* result = CallJS(builtin, context, inst_of_handler, callable,
object);
12621 var_result.Bind(result);
12622 Goto(&return_result);
12625 BIND(&if_otherhandler);
12628 GotoIf(IsNull(inst_of_handler), &if_nohandler);
12629 GotoIf(IsUndefined(inst_of_handler), &if_nohandler);
12632 Node* result = CallJS(
12633 CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
12634 context, inst_of_handler, callable,
object);
12637 BranchIfToBooleanIsTrue(result, &return_true, &return_false);
12640 BIND(&if_nohandler);
12643 GotoIfNot(IsCallable(callable), &if_notcallable);
12647 CallBuiltin(Builtins::kOrdinaryHasInstance, context, callable,
object);
12648 var_result.Bind(result);
12649 Goto(&return_result);
12652 BIND(&if_notcallable);
12653 { ThrowTypeError(context, MessageTemplate::kNonCallableInInstanceOfCheck); }
12655 BIND(&if_notreceiver);
12656 { ThrowTypeError(context, MessageTemplate::kNonObjectInInstanceOfCheck); }
12658 BIND(&return_true);
12659 var_result.Bind(TrueConstant());
12660 Goto(&return_result);
12662 BIND(&return_false);
12663 var_result.Bind(FalseConstant());
12664 Goto(&return_result);
12666 BIND(&return_result);
12667 return var_result.value();
12670 TNode<Number> CodeStubAssembler::NumberInc(SloppyTNode<Number> value) {
12671 TVARIABLE(Number, var_result);
12672 TVARIABLE(Float64T, var_finc_value);
12673 Label if_issmi(
this), if_isnotsmi(
this), do_finc(
this), end(
this);
12674 Branch(TaggedIsSmi(value), &if_issmi, &if_isnotsmi);
12678 Label if_overflow(
this);
12679 TNode<Smi> smi_value = CAST(value);
12680 TNode<Smi> one = SmiConstant(1);
12681 var_result = TrySmiAdd(smi_value, one, &if_overflow);
12684 BIND(&if_overflow);
12686 var_finc_value = SmiToFloat64(smi_value);
12691 BIND(&if_isnotsmi);
12693 TNode<HeapNumber> heap_number_value = CAST(value);
12696 var_finc_value = LoadHeapNumberValue(heap_number_value);
12702 TNode<Float64T> finc_value = var_finc_value.value();
12703 TNode<Float64T> one = Float64Constant(1.0);
12704 TNode<Float64T> finc_result = Float64Add(finc_value, one);
12705 var_result = AllocateHeapNumberWithValue(finc_result);
12710 return var_result.value();
12713 TNode<Number> CodeStubAssembler::NumberDec(SloppyTNode<Number> value) {
12714 TVARIABLE(Number, var_result);
12715 TVARIABLE(Float64T, var_fdec_value);
12716 Label if_issmi(
this), if_isnotsmi(
this), do_fdec(
this), end(
this);
12717 Branch(TaggedIsSmi(value), &if_issmi, &if_isnotsmi);
12721 TNode<Smi> smi_value = CAST(value);
12722 TNode<Smi> one = SmiConstant(1);
12723 Label if_overflow(
this);
12724 var_result = TrySmiSub(smi_value, one, &if_overflow);
12727 BIND(&if_overflow);
12729 var_fdec_value = SmiToFloat64(smi_value);
12734 BIND(&if_isnotsmi);
12736 TNode<HeapNumber> heap_number_value = CAST(value);
12739 var_fdec_value = LoadHeapNumberValue(heap_number_value);
12745 TNode<Float64T> fdec_value = var_fdec_value.value();
12746 TNode<Float64T> minus_one = Float64Constant(-1.0);
12747 TNode<Float64T> fdec_result = Float64Add(fdec_value, minus_one);
12748 var_result = AllocateHeapNumberWithValue(fdec_result);
12753 return var_result.value();
12756 TNode<Number> CodeStubAssembler::NumberAdd(SloppyTNode<Number> a,
12757 SloppyTNode<Number> b) {
12758 TVARIABLE(Number, var_result);
12759 Label float_add(
this, Label::kDeferred), end(
this);
12760 GotoIf(TaggedIsNotSmi(a), &float_add);
12761 GotoIf(TaggedIsNotSmi(b), &float_add);
12764 var_result = TrySmiAdd(CAST(a), CAST(b), &float_add);
12769 var_result = ChangeFloat64ToTagged(
12770 Float64Add(ChangeNumberToFloat64(a), ChangeNumberToFloat64(b)));
12775 return var_result.value();
12778 TNode<Number> CodeStubAssembler::NumberSub(SloppyTNode<Number> a,
12779 SloppyTNode<Number> b) {
12780 TVARIABLE(Number, var_result);
12781 Label float_sub(
this, Label::kDeferred), end(
this);
12782 GotoIf(TaggedIsNotSmi(a), &float_sub);
12783 GotoIf(TaggedIsNotSmi(b), &float_sub);
12786 var_result = TrySmiSub(CAST(a), CAST(b), &float_sub);
12791 var_result = ChangeFloat64ToTagged(
12792 Float64Sub(ChangeNumberToFloat64(a), ChangeNumberToFloat64(b)));
12797 return var_result.value();
12800 void CodeStubAssembler::GotoIfNotNumber(Node* input, Label* is_not_number) {
12801 Label is_number(
this);
12802 GotoIf(TaggedIsSmi(input), &is_number);
12803 Branch(IsHeapNumber(input), &is_number, is_not_number);
12807 void CodeStubAssembler::GotoIfNumber(Node* input, Label* is_number) {
12808 GotoIf(TaggedIsSmi(input), is_number);
12809 GotoIf(IsHeapNumber(input), is_number);
12812 TNode<Number> CodeStubAssembler::BitwiseOp(Node* left32, Node* right32,
12813 Operation bitwise_op) {
12814 switch (bitwise_op) {
12815 case Operation::kBitwiseAnd:
12816 return ChangeInt32ToTagged(Signed(Word32And(left32, right32)));
12817 case Operation::kBitwiseOr:
12818 return ChangeInt32ToTagged(Signed(Word32Or(left32, right32)));
12819 case Operation::kBitwiseXor:
12820 return ChangeInt32ToTagged(Signed(Word32Xor(left32, right32)));
12821 case Operation::kShiftLeft:
12822 if (!Word32ShiftIsSafe()) {
12823 right32 = Word32And(right32, Int32Constant(0x1F));
12825 return ChangeInt32ToTagged(Signed(Word32Shl(left32, right32)));
12826 case Operation::kShiftRight:
12827 if (!Word32ShiftIsSafe()) {
12828 right32 = Word32And(right32, Int32Constant(0x1F));
12830 return ChangeInt32ToTagged(Signed(Word32Sar(left32, right32)));
12831 case Operation::kShiftRightLogical:
12832 if (!Word32ShiftIsSafe()) {
12833 right32 = Word32And(right32, Int32Constant(0x1F));
12835 return ChangeUint32ToTagged(Unsigned(Word32Shr(left32, right32)));
12843 TNode<JSArrayIterator> CodeStubAssembler::CreateArrayIterator(
12844 TNode<Context> context, TNode<Object>
object, IterationKind kind) {
12845 TNode<Context> native_context = LoadNativeContext(context);
12846 TNode<Map> iterator_map = CAST(LoadContextElement(
12847 native_context, Context::INITIAL_ARRAY_ITERATOR_MAP_INDEX));
12848 Node* iterator = Allocate(JSArrayIterator::kSize);
12849 StoreMapNoWriteBarrier(iterator, iterator_map);
12850 StoreObjectFieldRoot(iterator, JSArrayIterator::kPropertiesOrHashOffset,
12851 RootIndex::kEmptyFixedArray);
12852 StoreObjectFieldRoot(iterator, JSArrayIterator::kElementsOffset,
12853 RootIndex::kEmptyFixedArray);
12854 StoreObjectFieldNoWriteBarrier(
12855 iterator, JSArrayIterator::kIteratedObjectOffset,
object);
12856 StoreObjectFieldNoWriteBarrier(iterator, JSArrayIterator::kNextIndexOffset,
12858 StoreObjectFieldNoWriteBarrier(
12859 iterator, JSArrayIterator::kKindOffset,
12860 SmiConstant(Smi::FromInt(static_cast<int>(kind))));
12861 return CAST(iterator);
12864 Node* CodeStubAssembler::AllocateJSIteratorResult(Node* context, Node* value,
12866 CSA_ASSERT(
this, IsBoolean(done));
12867 Node* native_context = LoadNativeContext(context);
12869 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
12870 Node* result = Allocate(JSIteratorResult::kSize);
12871 StoreMapNoWriteBarrier(result, map);
12872 StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset,
12873 RootIndex::kEmptyFixedArray);
12874 StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
12875 RootIndex::kEmptyFixedArray);
12876 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
12877 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
12881 Node* CodeStubAssembler::AllocateJSIteratorResultForEntry(Node* context,
12884 Node* native_context = LoadNativeContext(context);
12885 Node* length = SmiConstant(2);
12886 int const elements_size = FixedArray::SizeFor(2);
12887 TNode<FixedArray> elements = UncheckedCast<FixedArray>(
12888 Allocate(elements_size + JSArray::kSize + JSIteratorResult::kSize));
12889 StoreObjectFieldRoot(elements, FixedArray::kMapOffset,
12890 RootIndex::kFixedArrayMap);
12891 StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
12892 StoreFixedArrayElement(elements, 0, key);
12893 StoreFixedArrayElement(elements, 1, value);
12894 Node* array_map = LoadContextElement(
12895 native_context, Context::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
12896 TNode<HeapObject> array = InnerAllocate(elements, elements_size);
12897 StoreMapNoWriteBarrier(array, array_map);
12898 StoreObjectFieldRoot(array, JSArray::kPropertiesOrHashOffset,
12899 RootIndex::kEmptyFixedArray);
12900 StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset, elements);
12901 StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
12902 Node* iterator_map =
12903 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
12904 TNode<HeapObject> result = InnerAllocate(array, JSArray::kSize);
12905 StoreMapNoWriteBarrier(result, iterator_map);
12906 StoreObjectFieldRoot(result, JSIteratorResult::kPropertiesOrHashOffset,
12907 RootIndex::kEmptyFixedArray);
12908 StoreObjectFieldRoot(result, JSIteratorResult::kElementsOffset,
12909 RootIndex::kEmptyFixedArray);
12910 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, array);
12911 StoreObjectFieldRoot(result, JSIteratorResult::kDoneOffset,
12912 RootIndex::kFalseValue);
12916 TNode<JSReceiver> CodeStubAssembler::ArraySpeciesCreate(TNode<Context> context,
12918 TNode<Number> len) {
12919 TNode<JSReceiver> constructor =
12920 CAST(CallRuntime(Runtime::kArraySpeciesConstructor, context, o));
12921 return Construct(context, constructor, len);
12924 TNode<JSReceiver> CodeStubAssembler::InternalArrayCreate(TNode<Context> context,
12925 TNode<Number> len) {
12926 TNode<Context> native_context = LoadNativeContext(context);
12927 TNode<JSReceiver> constructor = CAST(LoadContextElement(
12928 native_context, Context::INTERNAL_ARRAY_FUNCTION_INDEX));
12929 return Construct(context, constructor, len);
12932 Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
12933 CSA_ASSERT(
this, HasInstanceType(buffer, JS_ARRAY_BUFFER_TYPE));
12934 TNode<Uint32T> buffer_bit_field = LoadJSArrayBufferBitField(CAST(buffer));
12935 return IsSetWord32<JSArrayBuffer::WasNeuteredBit>(buffer_bit_field);
12938 void CodeStubAssembler::ThrowIfArrayBufferIsDetached(
12939 SloppyTNode<Context> context, TNode<JSArrayBuffer> array_buffer,
12940 const char* method_name) {
12941 Label if_detached(
this, Label::kDeferred), if_not_detached(
this);
12942 Branch(IsDetachedBuffer(array_buffer), &if_detached, &if_not_detached);
12943 BIND(&if_detached);
12944 ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
12945 BIND(&if_not_detached);
12948 void CodeStubAssembler::ThrowIfArrayBufferViewBufferIsDetached(
12949 SloppyTNode<Context> context, TNode<JSArrayBufferView> array_buffer_view,
12950 const char* method_name) {
12951 TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(array_buffer_view);
12952 ThrowIfArrayBufferIsDetached(context, buffer, method_name);
12955 TNode<Uint32T> CodeStubAssembler::LoadJSArrayBufferBitField(
12956 TNode<JSArrayBuffer> array_buffer) {
12957 return LoadObjectField<Uint32T>(array_buffer, JSArrayBuffer::kBitFieldOffset);
12960 TNode<RawPtrT> CodeStubAssembler::LoadJSArrayBufferBackingStore(
12961 TNode<JSArrayBuffer> array_buffer) {
12962 return LoadObjectField<RawPtrT>(array_buffer,
12963 JSArrayBuffer::kBackingStoreOffset);
12966 TNode<JSArrayBuffer> CodeStubAssembler::LoadJSArrayBufferViewBuffer(
12967 TNode<JSArrayBufferView> array_buffer_view) {
12968 return LoadObjectField<JSArrayBuffer>(array_buffer_view,
12969 JSArrayBufferView::kBufferOffset);
12972 TNode<UintPtrT> CodeStubAssembler::LoadJSArrayBufferViewByteLength(
12973 TNode<JSArrayBufferView> array_buffer_view) {
12974 return LoadObjectField<UintPtrT>(array_buffer_view,
12975 JSArrayBufferView::kByteLengthOffset);
12978 TNode<UintPtrT> CodeStubAssembler::LoadJSArrayBufferViewByteOffset(
12979 TNode<JSArrayBufferView> array_buffer_view) {
12980 return LoadObjectField<UintPtrT>(array_buffer_view,
12981 JSArrayBufferView::kByteOffsetOffset);
12984 TNode<Smi> CodeStubAssembler::LoadJSTypedArrayLength(
12985 TNode<JSTypedArray> typed_array) {
12986 return LoadObjectField<Smi>(typed_array, JSTypedArray::kLengthOffset);
12989 CodeStubArguments::CodeStubArguments(
12990 CodeStubAssembler* assembler, Node* argc, Node* fp,
12991 CodeStubAssembler::ParameterMode param_mode, ReceiverMode receiver_mode)
12992 : assembler_(assembler),
12993 argc_mode_(param_mode),
12994 receiver_mode_(receiver_mode),
12997 fp_(fp != nullptr ? fp : assembler_->LoadFramePointer()) {
12998 Node* offset = assembler_->ElementOffsetFromIndex(
12999 argc_, PACKED_ELEMENTS, param_mode,
13000 (StandardFrameConstants::kFixedSlotCountAboveFp - 1) * kPointerSize);
13001 arguments_ = assembler_->UncheckedCast<RawPtr<Object>>(
13002 assembler_->IntPtrAdd(fp_, offset));
13005 TNode<Object> CodeStubArguments::GetReceiver()
const {
13006 DCHECK_EQ(receiver_mode_, ReceiverMode::kHasReceiver);
13007 return assembler_->UncheckedCast<Object>(
13008 assembler_->Load(MachineType::AnyTagged(), arguments_,
13009 assembler_->IntPtrConstant(kPointerSize)));
13012 void CodeStubArguments::SetReceiver(TNode<Object>
object)
const {
13013 DCHECK_EQ(receiver_mode_, ReceiverMode::kHasReceiver);
13014 assembler_->StoreNoWriteBarrier(MachineRepresentation::kTagged, arguments_,
13015 assembler_->IntPtrConstant(kPointerSize),
13019 TNode<RawPtr<Object>> CodeStubArguments::AtIndexPtr(
13020 Node* index, CodeStubAssembler::ParameterMode mode)
const {
13021 typedef compiler::Node Node;
13022 Node* negated_index = assembler_->IntPtrOrSmiSub(
13023 assembler_->IntPtrOrSmiConstant(0, mode), index, mode);
13024 Node* offset = assembler_->ElementOffsetFromIndex(negated_index,
13025 PACKED_ELEMENTS, mode, 0);
13026 return assembler_->UncheckedCast<RawPtr<Object>>(assembler_->IntPtrAdd(
13027 assembler_->UncheckedCast<IntPtrT>(arguments_), offset));
13030 TNode<Object> CodeStubArguments::AtIndex(
13031 Node* index, CodeStubAssembler::ParameterMode mode)
const {
13032 DCHECK_EQ(argc_mode_, mode);
13033 CSA_ASSERT(assembler_,
13034 assembler_->UintPtrOrSmiLessThan(index, GetLength(mode), mode));
13035 return assembler_->UncheckedCast<Object>(
13036 assembler_->Load(MachineType::AnyTagged(), AtIndexPtr(index, mode)));
13039 TNode<Object> CodeStubArguments::AtIndex(
int index)
const {
13040 return AtIndex(assembler_->IntPtrConstant(index));
13043 TNode<Object> CodeStubArguments::GetOptionalArgumentValue(
13044 int index, TNode<Object> default_value) {
13045 CodeStubAssembler::TVariable<Object> result(assembler_);
13046 CodeStubAssembler::Label argument_missing(assembler_),
13047 argument_done(assembler_, &result);
13049 assembler_->GotoIf(assembler_->UintPtrOrSmiGreaterThanOrEqual(
13050 assembler_->IntPtrOrSmiConstant(index, argc_mode_),
13051 argc_, argc_mode_),
13052 &argument_missing);
13053 result = AtIndex(index);
13054 assembler_->Goto(&argument_done);
13056 assembler_->BIND(&argument_missing);
13057 result = default_value;
13058 assembler_->Goto(&argument_done);
13060 assembler_->BIND(&argument_done);
13061 return result.value();
13064 TNode<Object> CodeStubArguments::GetOptionalArgumentValue(
13065 TNode<IntPtrT> index, TNode<Object> default_value) {
13066 CodeStubAssembler::TVariable<Object> result(assembler_);
13067 CodeStubAssembler::Label argument_missing(assembler_),
13068 argument_done(assembler_, &result);
13070 assembler_->GotoIf(
13071 assembler_->UintPtrOrSmiGreaterThanOrEqual(
13072 assembler_->IntPtrToParameter(index, argc_mode_), argc_, argc_mode_),
13073 &argument_missing);
13074 result = AtIndex(index);
13075 assembler_->Goto(&argument_done);
13077 assembler_->BIND(&argument_missing);
13078 result = default_value;
13079 assembler_->Goto(&argument_done);
13081 assembler_->BIND(&argument_done);
13082 return result.value();
13085 void CodeStubArguments::ForEach(
13086 const CodeStubAssembler::VariableList& vars,
13087 const CodeStubArguments::ForEachBodyFunction& body, Node* first, Node* last,
13088 CodeStubAssembler::ParameterMode mode) {
13089 assembler_->Comment(
"CodeStubArguments::ForEach");
13090 if (first ==
nullptr) {
13091 first = assembler_->IntPtrOrSmiConstant(0, mode);
13093 if (last ==
nullptr) {
13094 DCHECK_EQ(mode, argc_mode_);
13097 Node* start = assembler_->IntPtrSub(
13098 assembler_->UncheckedCast<IntPtrT>(arguments_),
13099 assembler_->ElementOffsetFromIndex(first, PACKED_ELEMENTS, mode));
13100 Node* end = assembler_->IntPtrSub(
13101 assembler_->UncheckedCast<IntPtrT>(arguments_),
13102 assembler_->ElementOffsetFromIndex(last, PACKED_ELEMENTS, mode));
13103 assembler_->BuildFastLoop(vars, start, end,
13104 [
this, &body](Node* current) {
13105 Node* arg = assembler_->Load(
13106 MachineType::AnyTagged(), current);
13109 -kPointerSize, CodeStubAssembler::INTPTR_PARAMETERS,
13110 CodeStubAssembler::IndexAdvanceMode::kPost);
13113 void CodeStubArguments::PopAndReturn(Node* value) {
13115 if (receiver_mode_ == ReceiverMode::kHasReceiver) {
13116 pop_count = assembler_->IntPtrOrSmiAdd(
13117 argc_, assembler_->IntPtrOrSmiConstant(1, argc_mode_), argc_mode_);
13122 assembler_->PopAndReturn(assembler_->ParameterToIntPtr(pop_count, argc_mode_),
13126 Node* CodeStubAssembler::IsFastElementsKind(Node* elements_kind) {
13127 STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND);
13128 return Uint32LessThanOrEqual(elements_kind,
13129 Int32Constant(LAST_FAST_ELEMENTS_KIND));
13132 TNode<BoolT> CodeStubAssembler::IsDoubleElementsKind(
13133 TNode<Int32T> elements_kind) {
13134 STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND);
13135 STATIC_ASSERT((PACKED_DOUBLE_ELEMENTS & 1) == 0);
13136 STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS + 1 == HOLEY_DOUBLE_ELEMENTS);
13137 return Word32Equal(Word32Shr(elements_kind, Int32Constant(1)),
13138 Int32Constant(PACKED_DOUBLE_ELEMENTS / 2));
13141 Node* CodeStubAssembler::IsFastSmiOrTaggedElementsKind(Node* elements_kind) {
13142 STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND);
13143 STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS > TERMINAL_FAST_ELEMENTS_KIND);
13144 STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS > TERMINAL_FAST_ELEMENTS_KIND);
13145 return Uint32LessThanOrEqual(elements_kind,
13146 Int32Constant(TERMINAL_FAST_ELEMENTS_KIND));
13149 Node* CodeStubAssembler::IsFastSmiElementsKind(Node* elements_kind) {
13150 return Uint32LessThanOrEqual(elements_kind,
13151 Int32Constant(HOLEY_SMI_ELEMENTS));
13154 Node* CodeStubAssembler::IsHoleyFastElementsKind(Node* elements_kind) {
13155 CSA_ASSERT(
this, IsFastElementsKind(elements_kind));
13157 STATIC_ASSERT(HOLEY_SMI_ELEMENTS == (PACKED_SMI_ELEMENTS | 1));
13158 STATIC_ASSERT(HOLEY_ELEMENTS == (PACKED_ELEMENTS | 1));
13159 STATIC_ASSERT(HOLEY_DOUBLE_ELEMENTS == (PACKED_DOUBLE_ELEMENTS | 1));
13160 return IsSetWord32(elements_kind, 1);
13163 Node* CodeStubAssembler::IsElementsKindGreaterThan(
13164 Node* target_kind, ElementsKind reference_kind) {
13165 return Int32GreaterThan(target_kind, Int32Constant(reference_kind));
13168 TNode<BoolT> CodeStubAssembler::IsElementsKindLessThanOrEqual(
13169 TNode<Int32T> target_kind, ElementsKind reference_kind) {
13170 return Int32LessThanOrEqual(target_kind, Int32Constant(reference_kind));
13173 Node* CodeStubAssembler::IsDebugActive() {
13174 Node* is_debug_active = Load(
13175 MachineType::Uint8(),
13176 ExternalConstant(ExternalReference::debug_is_active_address(isolate())));
13177 return Word32NotEqual(is_debug_active, Int32Constant(0));
13180 TNode<BoolT> CodeStubAssembler::IsRuntimeCallStatsEnabled() {
13181 TNode<Word32T> flag_value = UncheckedCast<Word32T>(Load(
13182 MachineType::Int32(),
13183 ExternalConstant(ExternalReference::address_of_runtime_stats_flag())));
13184 return Word32NotEqual(flag_value, Int32Constant(0));
13187 Node* CodeStubAssembler::IsPromiseHookEnabled() {
13188 Node*
const promise_hook = Load(
13189 MachineType::Pointer(),
13190 ExternalConstant(ExternalReference::promise_hook_address(isolate())));
13191 return WordNotEqual(promise_hook, IntPtrConstant(0));
13194 Node* CodeStubAssembler::HasAsyncEventDelegate() {
13195 Node*
const async_event_delegate =
13196 Load(MachineType::Pointer(),
13198 ExternalReference::async_event_delegate_address(isolate())));
13199 return WordNotEqual(async_event_delegate, IntPtrConstant(0));
13202 Node* CodeStubAssembler::IsPromiseHookEnabledOrHasAsyncEventDelegate() {
13203 Node*
const promise_hook_or_async_event_delegate =
13204 Load(MachineType::Uint8(),
13206 ExternalReference::promise_hook_or_async_event_delegate_address(
13208 return Word32NotEqual(promise_hook_or_async_event_delegate, Int32Constant(0));
13211 Node* CodeStubAssembler::
13212 IsPromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate() {
13213 Node*
const promise_hook_or_debug_is_active_or_async_event_delegate = Load(
13214 MachineType::Uint8(),
13216 ExternalReference::
13217 promise_hook_or_debug_is_active_or_async_event_delegate_address(
13219 return Word32NotEqual(promise_hook_or_debug_is_active_or_async_event_delegate,
13223 TNode<Code> CodeStubAssembler::LoadBuiltin(TNode<Smi> builtin_id) {
13224 CSA_ASSERT(
this, SmiGreaterThanOrEqual(builtin_id, SmiConstant(0)));
13226 SmiLessThan(builtin_id, SmiConstant(Builtins::builtin_count)));
13228 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize;
13229 int index_shift = kPointerSizeLog2 - kSmiShiftBits;
13230 TNode<WordT> table_index =
13231 index_shift >= 0 ? WordShl(BitcastTaggedToWord(builtin_id), index_shift)
13232 : WordSar(BitcastTaggedToWord(builtin_id), -index_shift);
13235 Load(MachineType::TaggedPointer(),
13236 ExternalConstant(ExternalReference::builtins_address(isolate())),
13240 TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
13241 SloppyTNode<SharedFunctionInfo> shared_info, Label* if_compile_lazy) {
13242 TNode<Object> sfi_data =
13243 LoadObjectField(shared_info, SharedFunctionInfo::kFunctionDataOffset);
13245 TVARIABLE(Code, sfi_code);
13248 Label check_instance_type(
this);
13251 GotoIf(TaggedIsNotSmi(sfi_data), &check_instance_type);
13252 if (if_compile_lazy) {
13253 GotoIf(SmiEqual(CAST(sfi_data), SmiConstant(Builtins::kCompileLazy)),
13256 sfi_code = LoadBuiltin(CAST(sfi_data));
13260 BIND(&check_instance_type);
13261 TNode<Int32T> data_type = LoadInstanceType(CAST(sfi_data));
13263 int32_t case_values[] = {BYTECODE_ARRAY_TYPE,
13264 WASM_EXPORTED_FUNCTION_DATA_TYPE,
13265 ASM_WASM_DATA_TYPE,
13266 UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE,
13267 UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE,
13268 FUNCTION_TEMPLATE_INFO_TYPE};
13269 Label check_is_bytecode_array(
this);
13270 Label check_is_exported_function_data(
this);
13271 Label check_is_asm_wasm_data(
this);
13272 Label check_is_uncompiled_data_without_pre_parsed_scope(
this);
13273 Label check_is_uncompiled_data_with_pre_parsed_scope(
this);
13274 Label check_is_function_template_info(
this);
13275 Label check_is_interpreter_data(
this);
13276 Label* case_labels[] = {&check_is_bytecode_array,
13277 &check_is_exported_function_data,
13278 &check_is_asm_wasm_data,
13279 &check_is_uncompiled_data_without_pre_parsed_scope,
13280 &check_is_uncompiled_data_with_pre_parsed_scope,
13281 &check_is_function_template_info};
13282 STATIC_ASSERT(arraysize(case_values) == arraysize(case_labels));
13283 Switch(data_type, &check_is_interpreter_data, case_values, case_labels,
13284 arraysize(case_labels));
13287 BIND(&check_is_bytecode_array);
13288 sfi_code = HeapConstant(BUILTIN_CODE(isolate(), InterpreterEntryTrampoline));
13292 BIND(&check_is_exported_function_data);
13293 sfi_code = CAST(LoadObjectField(
13294 CAST(sfi_data), WasmExportedFunctionData::kWrapperCodeOffset));
13298 BIND(&check_is_asm_wasm_data);
13299 sfi_code = HeapConstant(BUILTIN_CODE(isolate(), InstantiateAsmJs));
13304 BIND(&check_is_uncompiled_data_with_pre_parsed_scope);
13305 Goto(&check_is_uncompiled_data_without_pre_parsed_scope);
13306 BIND(&check_is_uncompiled_data_without_pre_parsed_scope);
13307 sfi_code = HeapConstant(BUILTIN_CODE(isolate(), CompileLazy));
13308 Goto(if_compile_lazy ? if_compile_lazy : &done);
13311 BIND(&check_is_function_template_info);
13312 sfi_code = HeapConstant(BUILTIN_CODE(isolate(), HandleApiCall));
13316 BIND(&check_is_interpreter_data);
13319 Word32Equal(data_type, Int32Constant(INTERPRETER_DATA_TYPE)));
13320 sfi_code = CAST(LoadObjectField(
13321 CAST(sfi_data), InterpreterData::kInterpreterTrampolineOffset));
13325 return sfi_code.value();
13328 Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map,
13331 CSA_SLOW_ASSERT(
this, IsMap(map));
13333 Node*
const code = GetSharedFunctionInfoCode(shared_info);
13338 CSA_ASSERT(
this, Word32BinaryNot(IsConstructorMap(map)));
13339 CSA_ASSERT(
this, Word32BinaryNot(IsFunctionWithPrototypeSlotMap(map)));
13340 Node*
const fun = Allocate(JSFunction::kSizeWithoutPrototype);
13341 STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
13342 StoreMapNoWriteBarrier(fun, map);
13343 StoreObjectFieldRoot(fun, JSObject::kPropertiesOrHashOffset,
13344 RootIndex::kEmptyFixedArray);
13345 StoreObjectFieldRoot(fun, JSObject::kElementsOffset,
13346 RootIndex::kEmptyFixedArray);
13347 StoreObjectFieldRoot(fun, JSFunction::kFeedbackCellOffset,
13348 RootIndex::kManyClosuresCell);
13349 StoreObjectFieldNoWriteBarrier(fun, JSFunction::kSharedFunctionInfoOffset,
13351 StoreObjectFieldNoWriteBarrier(fun, JSFunction::kContextOffset, context);
13352 StoreObjectFieldNoWriteBarrier(fun, JSFunction::kCodeOffset, code);
13356 Node* CodeStubAssembler::MarkerIsFrameType(Node* marker_or_function,
13357 StackFrame::Type frame_type) {
13358 return WordEqual(marker_or_function,
13359 IntPtrConstant(StackFrame::TypeToMarker(frame_type)));
13362 Node* CodeStubAssembler::MarkerIsNotFrameType(Node* marker_or_function,
13363 StackFrame::Type frame_type) {
13364 return WordNotEqual(marker_or_function,
13365 IntPtrConstant(StackFrame::TypeToMarker(frame_type)));
13368 void CodeStubAssembler::CheckPrototypeEnumCache(Node* receiver,
13369 Node* receiver_map,
13372 VARIABLE(var_object, MachineRepresentation::kTagged, receiver);
13373 VARIABLE(var_object_map, MachineRepresentation::kTagged, receiver_map);
13375 Label loop(
this, {&var_object, &var_object_map}), done_loop(
this);
13380 Label if_no_elements(
this);
13381 Node*
object = var_object.value();
13382 Node* object_map = var_object_map.value();
13387 STATIC_ASSERT(JSObject::kElementsOffset == JSProxy::kTargetOffset);
13388 Node* object_elements = LoadObjectField(
object, JSObject::kElementsOffset);
13389 GotoIf(IsEmptyFixedArray(object_elements), &if_no_elements);
13390 GotoIf(IsEmptySlowElementDictionary(object_elements), &if_no_elements);
13393 GotoIfNot(IsJSArrayMap(object_map), if_slow);
13394 Node* object_length = LoadJSArrayLength(
object);
13395 Branch(WordEqual(object_length, SmiConstant(0)), &if_no_elements, if_slow);
13398 BIND(&if_no_elements);
13399 object = LoadMapPrototype(object_map);
13400 GotoIf(IsNull(
object), if_fast);
13403 var_object.Bind(
object);
13404 object_map = LoadMap(
object);
13405 var_object_map.Bind(object_map);
13406 Node* object_enum_length = LoadMapEnumLength(object_map);
13407 Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &loop, if_slow);
13411 Node* CodeStubAssembler::CheckEnumCache(Node* receiver, Label* if_empty,
13412 Label* if_runtime) {
13413 Label if_fast(
this), if_cache(
this), if_no_cache(
this, Label::kDeferred);
13414 Node* receiver_map = LoadMap(receiver);
13418 Node* receiver_enum_length = LoadMapEnumLength(receiver_map);
13419 Branch(WordEqual(receiver_enum_length,
13420 IntPtrConstant(kInvalidEnumCacheSentinel)),
13421 &if_no_cache, &if_cache);
13423 BIND(&if_no_cache);
13426 GotoIfNot(IsDictionaryMap(receiver_map), if_runtime);
13427 TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver));
13428 TNode<Smi> length = GetNumberOfElements(properties);
13429 GotoIfNot(WordEqual(length, SmiConstant(0)), if_runtime);
13434 CheckPrototypeEnumCache(receiver, receiver_map, if_empty, if_runtime);
13440 CheckPrototypeEnumCache(receiver, receiver_map, &if_fast, if_runtime);
13443 return receiver_map;
13446 TNode<IntPtrT> CodeStubAssembler::GetArgumentsLength(CodeStubArguments* args) {
13447 return args->GetLength();
13450 TNode<Object> CodeStubAssembler::GetArgumentValue(CodeStubArguments* args,
13451 TNode<IntPtrT> index) {
13452 return args->GetOptionalArgumentValue(index);
13455 void CodeStubAssembler::Print(
const char* s) {
13456 std::string formatted(s);
13458 CallRuntime(Runtime::kGlobalPrint, NoContextConstant(),
13459 StringConstant(formatted.c_str()));
13462 void CodeStubAssembler::Print(
const char* prefix, Node* tagged_value) {
13463 if (prefix !=
nullptr) {
13464 std::string formatted(prefix);
13466 Handle<String>
string = isolate()->factory()->NewStringFromAsciiChecked(
13467 formatted.c_str(), TENURED);
13468 CallRuntime(Runtime::kGlobalPrint, NoContextConstant(),
13469 HeapConstant(
string));
13471 CallRuntime(Runtime::kDebugPrint, NoContextConstant(), tagged_value);
13474 void CodeStubAssembler::PerformStackCheck(TNode<Context> context) {
13475 Label ok(
this), stack_check_interrupt(
this, Label::kDeferred);
13481 TNode<UintPtrT> sp = UncheckedCast<UintPtrT>(LoadStackPointer());
13482 TNode<UintPtrT> stack_limit = UncheckedCast<UintPtrT>(Load(
13483 MachineType::Pointer(),
13484 ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))));
13485 TNode<BoolT> sp_within_limit = UintPtrLessThan(stack_limit, sp);
13487 Branch(sp_within_limit, &ok, &stack_check_interrupt);
13489 BIND(&stack_check_interrupt);
13490 CallRuntime(Runtime::kStackGuard, context);
13496 void CodeStubAssembler::InitializeFunctionContext(Node* native_context,
13497 Node* context,
int slots) {
13498 DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
13499 StoreMapNoWriteBarrier(context, RootIndex::kFunctionContextMap);
13500 StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
13501 SmiConstant(slots));
13503 Node*
const empty_scope_info =
13504 LoadContextElement(native_context, Context::SCOPE_INFO_INDEX);
13505 StoreContextElementNoWriteBarrier(context, Context::SCOPE_INFO_INDEX,
13507 StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX,
13508 UndefinedConstant());
13509 StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX,
13510 TheHoleConstant());
13511 StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
13515 TNode<JSArray> CodeStubAssembler::ArrayCreate(TNode<Context> context,
13516 TNode<Number> length) {
13517 TVARIABLE(JSArray, array);
13518 Label allocate_js_array(
this);
13520 Label done(
this), next(
this), runtime(
this, Label::kDeferred);
13521 TNode<Smi> limit = SmiConstant(JSArray::kInitialMaxFastElementArray);
13522 CSA_ASSERT_BRANCH(
this, [=](Label* ok, Label* not_ok) {
13523 BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, length,
13524 SmiConstant(0), ok, not_ok);
13529 BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual, length,
13530 limit, &runtime, &next);
13534 TNode<Context> native_context = LoadNativeContext(context);
13535 TNode<JSFunction> array_function =
13536 CAST(LoadContextElement(native_context, Context::ARRAY_FUNCTION_INDEX));
13537 array = CAST(CallRuntime(Runtime::kNewArray, context, array_function,
13538 length, array_function, UndefinedConstant()));
13543 CSA_ASSERT(
this, TaggedIsSmi(length));
13545 TNode<Map> array_map = CAST(LoadContextElement(
13546 context, Context::JS_ARRAY_PACKED_SMI_ELEMENTS_MAP_INDEX));
13552 AllocateJSArray(PACKED_SMI_ELEMENTS, array_map, length, SmiConstant(0),
13553 nullptr, ParameterMode::SMI_PARAMETERS);
13557 return array.value();
13560 void CodeStubAssembler::SetPropertyLength(TNode<Context> context,
13561 TNode<Object> array,
13562 TNode<Number> length) {
13563 Label fast(
this), runtime(
this), done(
this);
13574 BranchIfFastJSArray(array, context, &fast, &runtime);
13578 TNode<JSArray> fast_array = CAST(array);
13580 TNode<Smi> length_smi = CAST(length);
13581 TNode<Smi> old_length = LoadFastJSArrayLength(fast_array);
13582 CSA_ASSERT(
this, TaggedIsPositiveSmi(old_length));
13588 Branch(SmiNotEqual(length_smi, old_length), &runtime, &done);
13593 SetPropertyStrict(context, array, CodeStubAssembler::LengthStringConstant(),
13601 void CodeStubAssembler::GotoIfInitialPrototypePropertyModified(
13602 TNode<Map> object_map, TNode<Map> initial_prototype_map,
int descriptor,
13603 RootIndex field_name_root_index, Label* if_modified) {
13604 DescriptorIndexAndName index_name{descriptor, field_name_root_index};
13605 GotoIfInitialPrototypePropertiesModified(
13606 object_map, initial_prototype_map,
13607 Vector<DescriptorIndexAndName>(&index_name, 1), if_modified);
13610 void CodeStubAssembler::GotoIfInitialPrototypePropertiesModified(
13611 TNode<Map> object_map, TNode<Map> initial_prototype_map,
13612 Vector<DescriptorIndexAndName> properties, Label* if_modified) {
13613 TNode<Map> prototype_map = LoadMap(LoadMapPrototype(object_map));
13614 GotoIfNot(WordEqual(prototype_map, initial_prototype_map), if_modified);
13616 if (FLAG_track_constant_fields) {
13621 TNode<DescriptorArray> descriptors = LoadMapDescriptors(prototype_map);
13623 TNode<Uint32T> combined_details;
13624 for (
int i = 0;
i < properties.length();
i++) {
13626 int descriptor = properties[
i].descriptor_index;
13627 CSA_ASSERT(
this, Int32LessThan(Int32Constant(descriptor),
13628 LoadNumberOfDescriptors(descriptors)));
13633 WordEqual(LoadKeyByDescriptorEntry(descriptors, descriptor),
13634 LoadRoot(properties[
i].name_root_index)));
13636 TNode<Uint32T> details =
13637 DescriptorArrayGetDetails(descriptors, Uint32Constant(descriptor));
13639 combined_details = details;
13641 combined_details = Unsigned(Word32And(combined_details, details));
13645 TNode<Uint32T> constness =
13646 DecodeWord32<PropertyDetails::ConstnessField>(combined_details);
13649 Word32Equal(constness,
13650 Int32Constant(static_cast<int>(PropertyConstness::kConst))),