v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
binary-op-assembler.cc
Go to the documentation of this file.
1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
9#include "src/flags/flags.h"
11
12namespace v8 {
13namespace internal {
14
16
17namespace {
18
19inline bool IsBigInt64OpSupported(BinaryOpAssembler* assembler, Operation op) {
20 return assembler->Is64() && op != Operation::kExponentiate &&
21 op != Operation::kShiftLeft && op != Operation::kShiftRight &&
22 op != Operation::kShiftRightLogical;
23}
24
25} // namespace
26
28 const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
29 TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
30 UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
31 // Shared entry for floating point addition.
32 Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred),
33 check_rhsisoddball(this, Label::kDeferred),
34 call_with_oddball_feedback(this), call_with_any_feedback(this),
35 call_add_stub(this), end(this), bigint(this, Label::kDeferred),
36 bigint64(this);
37 TVARIABLE(Float64T, var_fadd_lhs);
38 TVARIABLE(Float64T, var_fadd_rhs);
39 TVARIABLE(Smi, var_type_feedback);
40 TVARIABLE(Object, var_result);
41
42 // Check if the {lhs} is a Smi or a HeapObject.
43 Label if_lhsissmi(this);
44 // If rhs is known to be an Smi we want to fast path Smi operation. This is
45 // for AddSmi operation. For the normal Add operation, we want to fast path
46 // both Smi and Number operations, so this path should not be marked as
47 // Deferred.
48 Label if_lhsisnotsmi(this,
49 rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
50 Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
51
52 auto IsAdditiveSafeIntegerFeedback = [&](TNode<Float64T> value) {
53 return Select<BoolT>(
55 [&] { return IsAdditiveSafeInteger(value); },
56 [&] { return BoolConstant(false); });
57 };
58
59 BIND(&if_lhsissmi);
60 {
61 Comment("lhs is Smi");
62 TNode<Smi> lhs_smi = CAST(lhs);
63 if (!rhs_known_smi) {
64 // Check if the {rhs} is also a Smi.
65 Label if_rhsissmi(this), if_rhsisnotsmi(this);
66 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
67
68 BIND(&if_rhsisnotsmi);
69 {
70 // Check if the {rhs} is a HeapNumber.
71 TNode<HeapObject> rhs_heap_object = CAST(rhs);
72 GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
73
74 var_fadd_lhs = SmiToFloat64(lhs_smi);
75 var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object);
76 var_type_feedback = SelectSmiConstant(
77 IsAdditiveSafeIntegerFeedback(var_fadd_rhs.value()),
80 Goto(&do_fadd);
81 }
82
83 BIND(&if_rhsissmi);
84 }
85
86 {
87 Comment("perform smi operation");
88 // If rhs is known to be an Smi we want to fast path Smi operation. This
89 // is for AddSmi operation. For the normal Add operation, we want to fast
90 // path both Smi and Number operations, so this path should not be marked
91 // as Deferred.
92 TNode<Smi> rhs_smi = CAST(rhs);
93 Label if_overflow(this,
94 rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
95 TNode<Smi> smi_result = TrySmiAdd(lhs_smi, rhs_smi, &if_overflow);
96 // Not overflowed.
97 {
99 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
100 slot_id, update_feedback_mode);
101 var_result = smi_result;
102 Goto(&end);
103 }
104
105 BIND(&if_overflow);
106 {
107 var_fadd_lhs = SmiToFloat64(lhs_smi);
108 var_fadd_rhs = SmiToFloat64(rhs_smi);
109 var_type_feedback =
113 Goto(&do_fadd);
114 }
115 }
116 }
117
118 BIND(&if_lhsisnotsmi);
119 {
120 // Check if {lhs} is a HeapNumber.
121 TNode<HeapObject> lhs_heap_object = CAST(lhs);
122 GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber);
123
124 if (!rhs_known_smi) {
125 // Check if the {rhs} is Smi.
126 Label if_rhsissmi(this), if_rhsisnotsmi(this);
127 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
128
129 BIND(&if_rhsisnotsmi);
130 {
131 // Check if the {rhs} is a HeapNumber.
132 TNode<HeapObject> rhs_heap_object = CAST(rhs);
133 GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
134
135 var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object);
136 var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object);
138 GotoIfNot(IsAdditiveSafeIntegerFeedback(var_fadd_lhs.value()),
139 &do_fadd);
140 GotoIfNot(IsAdditiveSafeIntegerFeedback(var_fadd_rhs.value()),
141 &do_fadd);
142 var_type_feedback =
144 Goto(&do_fadd);
145 }
146
147 BIND(&if_rhsissmi);
148 }
149 {
150 var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object);
151 var_fadd_rhs = SmiToFloat64(CAST(rhs));
152 var_type_feedback =
153 SelectSmiConstant(IsAdditiveSafeIntegerFeedback(var_fadd_lhs.value()),
156 Goto(&do_fadd);
157 }
158 }
159
160 BIND(&do_fadd);
161 {
162 TNode<Float64T> value =
163 Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
165 var_result = result;
166
167 Label AdditiveSafeInteger_overflow_check_done(this);
169 &AdditiveSafeInteger_overflow_check_done);
170 {
171 GotoIfNot(
172 SmiEqual(var_type_feedback.value(),
174 &AdditiveSafeInteger_overflow_check_done);
175 GotoIf(IsAdditiveSafeIntegerFeedback(value),
176 &AdditiveSafeInteger_overflow_check_done);
178 Goto(&AdditiveSafeInteger_overflow_check_done);
179 }
180 BIND(&AdditiveSafeInteger_overflow_check_done);
181
182 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
183 update_feedback_mode);
184 Goto(&end);
185 }
186
187 BIND(&if_lhsisnotnumber);
188 {
189 // No checks on rhs are done yet. We just know lhs is not a number or Smi.
190 Label if_lhsisoddball(this), if_lhsisnotoddball(this);
191 TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs));
192 TNode<BoolT> lhs_is_oddball =
193 InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
194 Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);
195
196 BIND(&if_lhsisoddball);
197 {
198 GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
199
200 // Check if {rhs} is a HeapNumber.
201 Branch(IsHeapNumber(CAST(rhs)), &call_with_oddball_feedback,
202 &check_rhsisoddball);
203 }
204
205 BIND(&if_lhsisnotoddball);
206 {
207 // Check if the {rhs} is a smi, and exit the string and bigint check early
208 // if it is.
209 GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
210 TNode<HeapObject> rhs_heap_object = CAST(rhs);
211
212 Label lhs_is_string(this), lhs_is_bigint(this);
213 GotoIf(IsStringInstanceType(lhs_instance_type), &lhs_is_string);
214 GotoIf(IsBigIntInstanceType(lhs_instance_type), &lhs_is_bigint);
215 Goto(&call_with_any_feedback);
216
217 BIND(&lhs_is_bigint);
218 {
219 GotoIfNot(IsBigInt(rhs_heap_object), &call_with_any_feedback);
220 if (Is64()) {
221 GotoIfLargeBigInt(CAST(lhs), &bigint);
222 GotoIfLargeBigInt(CAST(rhs), &bigint);
223 Goto(&bigint64);
224 } else {
225 Goto(&bigint);
226 }
227 }
228
229 BIND(&lhs_is_string);
230 {
231 Label lhs_is_string_rhs_is_not_string(this);
232
233 TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs_heap_object);
234
235 // Fast path where both {lhs} and {rhs} are strings. Since {lhs} is a
236 // string we no longer need an Oddball check.
237 GotoIfNot(IsStringInstanceType(rhs_instance_type),
238 &lhs_is_string_rhs_is_not_string);
239
241 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
242 slot_id, update_feedback_mode);
243 var_result =
244 CallBuiltin(Builtin::kStringAdd_CheckNone, context(), lhs, rhs);
245
246 Goto(&end);
247
248 BIND(&lhs_is_string_rhs_is_not_string);
249
250 GotoIfNot(IsStringWrapper(rhs_heap_object), &call_with_any_feedback);
251
252 // lhs is a string and rhs is a string wrapper.
253
254 TNode<PropertyCell> to_primitive_protector =
255 StringWrapperToPrimitiveProtectorConstant();
256 GotoIf(TaggedEqual(LoadObjectField(to_primitive_protector,
257 PropertyCell::kValueOffset),
259 &call_with_any_feedback);
260
261 var_type_feedback =
263 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
264 slot_id, update_feedback_mode);
265 TNode<String> rhs_string =
266 CAST(LoadJSPrimitiveWrapperValue(CAST(rhs_heap_object)));
267 var_result = CallBuiltin(Builtin::kStringAdd_CheckNone, context(), lhs,
268 rhs_string);
269 Goto(&end);
270 }
271 }
272 }
273 // TODO(v8:12199): Support "string wrapper + string" concatenation too.
274
275 BIND(&check_rhsisoddball);
276 {
277 // Check if rhs is an oddball. At this point we know lhs is either a
278 // Smi or number or oddball and rhs is not a number or Smi.
279 TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
280 TNode<BoolT> rhs_is_oddball =
281 InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
282 GotoIf(rhs_is_oddball, &call_with_oddball_feedback);
283 Goto(&call_with_any_feedback);
284 }
285
286 if (Is64()) {
287 BIND(&bigint64);
288 {
289 // Both {lhs} and {rhs} are of BigInt type and can fit in 64-bit
290 // registers.
291 Label if_overflow(this);
292 TVARIABLE(UintPtrT, lhs_raw);
293 TVARIABLE(UintPtrT, rhs_raw);
294 BigIntToRawBytes(CAST(lhs), &lhs_raw, &lhs_raw);
295 BigIntToRawBytes(CAST(rhs), &rhs_raw, &rhs_raw);
296 var_result = BigIntFromInt64(
297 TryIntPtrAdd(UncheckedCast<IntPtrT>(lhs_raw.value()),
298 UncheckedCast<IntPtrT>(rhs_raw.value()), &if_overflow));
299
301 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
302 slot_id, update_feedback_mode);
303 Goto(&end);
304
305 BIND(&if_overflow);
306 Goto(&bigint);
307 }
308 }
309
310 BIND(&bigint);
311 {
312 // Both {lhs} and {rhs} are of BigInt type.
313 Label bigint_too_big(this);
314 var_result = CallBuiltin(Builtin::kBigIntAddNoThrow, context(), lhs, rhs);
315 // Check for sentinel that signals BigIntTooBig exception.
316 GotoIf(TaggedIsSmi(var_result.value()), &bigint_too_big);
317
319 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
320 update_feedback_mode);
321 Goto(&end);
322
323 BIND(&bigint_too_big);
324 {
325 // Update feedback to prevent deopt loop.
327 maybe_feedback_vector(), slot_id, update_feedback_mode);
328 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
329 }
330 }
331
332 BIND(&call_with_oddball_feedback);
333 {
335 Goto(&call_add_stub);
336 }
337
338 BIND(&call_with_any_feedback);
339 {
340 var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny);
341 Goto(&call_add_stub);
342 }
343
344 BIND(&call_add_stub);
345 {
346 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
347 update_feedback_mode);
348 var_result = CallBuiltin(Builtin::kAdd, context(), lhs, rhs);
349 Goto(&end);
350 }
351
352 BIND(&end);
353 return var_result.value();
354}
355
357 const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
358 TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
359 const SmiOperation& smiOperation, const FloatOperation& floatOperation,
360 Operation op, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
361 Label do_float_operation(this), end(this), call_stub(this),
362 check_rhsisoddball(this, Label::kDeferred), call_with_any_feedback(this),
363 if_lhsisnotnumber(this, Label::kDeferred),
364 if_both_bigint(this, Label::kDeferred), if_both_bigint64(this);
365 TVARIABLE(Float64T, var_float_lhs);
366 TVARIABLE(Float64T, var_float_rhs);
367 TVARIABLE(Smi, var_type_feedback);
368 TVARIABLE(Object, var_result);
369
370 Label if_lhsissmi(this);
371 // If rhs is known to be an Smi (in the SubSmi, MulSmi, DivSmi, ModSmi
372 // bytecode handlers) we want to fast path Smi operation. For the normal
373 // operation, we want to fast path both Smi and Number operations, so this
374 // path should not be marked as Deferred.
375 Label if_lhsisnotsmi(this,
376 rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
377 Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
378
379 // Check if the {lhs} is a Smi or a HeapObject.
380 BIND(&if_lhsissmi);
381 {
382 Comment("lhs is Smi");
383 TNode<Smi> lhs_smi = CAST(lhs);
384 if (!rhs_known_smi) {
385 // Check if the {rhs} is also a Smi.
386 Label if_rhsissmi(this), if_rhsisnotsmi(this);
387 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
388
389 BIND(&if_rhsisnotsmi);
390 {
391 // Check if {rhs} is a HeapNumber.
392 TNode<HeapObject> rhs_heap_object = CAST(rhs);
393 GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
394
395 // Perform a floating point operation.
396 var_float_lhs = SmiToFloat64(lhs_smi);
397 var_float_rhs = LoadHeapNumberValue(rhs_heap_object);
398 Goto(&do_float_operation);
399 }
400
401 BIND(&if_rhsissmi);
402 }
403
404 {
405 Comment("perform smi operation");
406 var_result = smiOperation(lhs_smi, CAST(rhs), &var_type_feedback);
407 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(),
408 slot_id, update_feedback_mode);
409 Goto(&end);
410 }
411 }
412
413 BIND(&if_lhsisnotsmi);
414 {
415 Comment("lhs is not Smi");
416 // Check if the {lhs} is a HeapNumber.
417 TNode<HeapObject> lhs_heap_object = CAST(lhs);
418 GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber);
419
420 if (!rhs_known_smi) {
421 // Check if the {rhs} is a Smi.
422 Label if_rhsissmi(this), if_rhsisnotsmi(this);
423 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
424
425 BIND(&if_rhsisnotsmi);
426 {
427 // Check if the {rhs} is a HeapNumber.
428 TNode<HeapObject> rhs_heap_object = CAST(rhs);
429 GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
430
431 // Perform a floating point operation.
432 var_float_lhs = LoadHeapNumberValue(lhs_heap_object);
433 var_float_rhs = LoadHeapNumberValue(rhs_heap_object);
434 Goto(&do_float_operation);
435 }
436
437 BIND(&if_rhsissmi);
438 }
439
440 {
441 // Perform floating point operation.
442 var_float_lhs = LoadHeapNumberValue(lhs_heap_object);
443 var_float_rhs = SmiToFloat64(CAST(rhs));
444 Goto(&do_float_operation);
445 }
446 }
447
448 BIND(&do_float_operation);
449 {
451 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
452 update_feedback_mode);
453 TNode<Float64T> lhs_value = var_float_lhs.value();
454 TNode<Float64T> rhs_value = var_float_rhs.value();
455 TNode<Float64T> value = floatOperation(lhs_value, rhs_value);
456 var_result = AllocateHeapNumberWithValue(value);
457 Goto(&end);
458 }
459
460 BIND(&if_lhsisnotnumber);
461 {
462 // No checks on rhs are done yet. We just know lhs is not a number or Smi.
463 Label if_left_bigint(this), if_left_oddball(this);
464 TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs));
465 GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
466 TNode<BoolT> lhs_is_oddball =
467 InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
468 Branch(lhs_is_oddball, &if_left_oddball, &call_with_any_feedback);
469
470 BIND(&if_left_oddball);
471 {
472 Label if_rhsissmi(this), if_rhsisnotsmi(this);
473 Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
474
475 BIND(&if_rhsissmi);
476 {
477 var_type_feedback =
479 Goto(&call_stub);
480 }
481
482 BIND(&if_rhsisnotsmi);
483 {
484 // Check if {rhs} is a HeapNumber.
485 GotoIfNot(IsHeapNumber(CAST(rhs)), &check_rhsisoddball);
486
487 var_type_feedback =
489 Goto(&call_stub);
490 }
491 }
492
493 BIND(&if_left_bigint);
494 {
495 GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
496 GotoIfNot(IsBigInt(CAST(rhs)), &call_with_any_feedback);
497 if (IsBigInt64OpSupported(this, op)) {
498 GotoIfLargeBigInt(CAST(lhs), &if_both_bigint);
499 GotoIfLargeBigInt(CAST(rhs), &if_both_bigint);
500 Goto(&if_both_bigint64);
501 } else {
502 Goto(&if_both_bigint);
503 }
504 }
505 }
506
507 BIND(&check_rhsisoddball);
508 {
509 // Check if rhs is an oddball. At this point we know lhs is either a
510 // Smi or number or oddball and rhs is not a number or Smi.
511 TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
512 TNode<BoolT> rhs_is_oddball =
513 InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
514 GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
515
517 Goto(&call_stub);
518 }
519
520 if (IsBigInt64OpSupported(this, op)) {
521 BIND(&if_both_bigint64);
523 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
524 update_feedback_mode);
525
526 TVARIABLE(UintPtrT, lhs_raw);
527 TVARIABLE(UintPtrT, rhs_raw);
528 BigIntToRawBytes(CAST(lhs), &lhs_raw, &lhs_raw);
529 BigIntToRawBytes(CAST(rhs), &rhs_raw, &rhs_raw);
530
531 switch (op) {
532 case Operation::kSubtract: {
533 var_result = BigIntFromInt64(TryIntPtrSub(
534 UncheckedCast<IntPtrT>(lhs_raw.value()),
535 UncheckedCast<IntPtrT>(rhs_raw.value()), &if_both_bigint));
536 Goto(&end);
537 break;
538 }
539 case Operation::kMultiply: {
540 var_result = BigIntFromInt64(TryIntPtrMul(
541 UncheckedCast<IntPtrT>(lhs_raw.value()),
542 UncheckedCast<IntPtrT>(rhs_raw.value()), &if_both_bigint));
543 Goto(&end);
544 break;
545 }
546 case Operation::kDivide: {
547 // No need to check overflow because INT_MIN is excluded
548 // from the range of small BigInts.
549 Label if_div_zero(this);
550 var_result = BigIntFromInt64(TryIntPtrDiv(
551 UncheckedCast<IntPtrT>(lhs_raw.value()),
552 UncheckedCast<IntPtrT>(rhs_raw.value()), &if_div_zero));
553 Goto(&end);
554
555 BIND(&if_div_zero);
556 {
557 // Update feedback to prevent deopt loop.
559 maybe_feedback_vector(), slot_id,
560 update_feedback_mode);
561 ThrowRangeError(context(), MessageTemplate::kBigIntDivZero);
562 }
563 break;
564 }
565 case Operation::kModulus: {
566 Label if_div_zero(this);
567 var_result = BigIntFromInt64(TryIntPtrMod(
568 UncheckedCast<IntPtrT>(lhs_raw.value()),
569 UncheckedCast<IntPtrT>(rhs_raw.value()), &if_div_zero));
570 Goto(&end);
571
572 BIND(&if_div_zero);
573 {
574 // Update feedback to prevent deopt loop.
576 maybe_feedback_vector(), slot_id,
577 update_feedback_mode);
578 ThrowRangeError(context(), MessageTemplate::kBigIntDivZero);
579 }
580 break;
581 }
582 default:
583 UNREACHABLE();
584 }
585 }
586
587 BIND(&if_both_bigint);
588 {
590 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
591 update_feedback_mode);
592 switch (op) {
593 case Operation::kSubtract: {
594 var_result =
595 CallBuiltin(Builtin::kBigIntSubtractNoThrow, context(), lhs, rhs);
596
597 // Check for sentinel that signals BigIntTooBig exception.
598 GotoIfNot(TaggedIsSmi(var_result.value()), &end);
599
600 // Update feedback to prevent deopt loop.
602 maybe_feedback_vector(), slot_id, update_feedback_mode);
603 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
604 break;
605 }
606 case Operation::kMultiply: {
607 Label termination_requested(this, Label::kDeferred);
608 var_result =
609 CallBuiltin(Builtin::kBigIntMultiplyNoThrow, context(), lhs, rhs);
610
611 GotoIfNot(TaggedIsSmi(var_result.value()), &end);
612
613 // Check for sentinel that signals TerminationRequested exception.
614 GotoIf(TaggedEqual(var_result.value(), SmiConstant(1)),
615 &termination_requested);
616
617 // Handles BigIntTooBig exception.
618 // Update feedback to prevent deopt loop.
620 maybe_feedback_vector(), slot_id, update_feedback_mode);
621 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
622
623 BIND(&termination_requested);
625 break;
626 }
627 case Operation::kDivide: {
628 Label termination_requested(this, Label::kDeferred);
629 var_result =
630 CallBuiltin(Builtin::kBigIntDivideNoThrow, context(), lhs, rhs);
631
632 GotoIfNot(TaggedIsSmi(var_result.value()), &end);
633
634 // Check for sentinel that signals TerminationRequested exception.
635 GotoIf(TaggedEqual(var_result.value(), SmiConstant(1)),
636 &termination_requested);
637
638 // Handles BigIntDivZero exception.
639 // Update feedback to prevent deopt loop.
641 maybe_feedback_vector(), slot_id, update_feedback_mode);
642 ThrowRangeError(context(), MessageTemplate::kBigIntDivZero);
643
644 BIND(&termination_requested);
646 break;
647 }
648 case Operation::kModulus: {
649 Label termination_requested(this, Label::kDeferred);
650 var_result =
651 CallBuiltin(Builtin::kBigIntModulusNoThrow, context(), lhs, rhs);
652
653 GotoIfNot(TaggedIsSmi(var_result.value()), &end);
654
655 // Check for sentinel that signals TerminationRequested exception.
656 GotoIf(TaggedEqual(var_result.value(), SmiConstant(1)),
657 &termination_requested);
658
659 // Handles BigIntDivZero exception.
660 // Update feedback to prevent deopt loop.
662 maybe_feedback_vector(), slot_id, update_feedback_mode);
663 ThrowRangeError(context(), MessageTemplate::kBigIntDivZero);
664
665 BIND(&termination_requested);
667 break;
668 }
669 case Operation::kExponentiate: {
670 // TODO(panq): replace the runtime with builtin once it is implemented.
671 var_result =
672 CallRuntime(Runtime::kBigIntExponentiate, context(), lhs, rhs);
673 Goto(&end);
674 break;
675 }
676 default:
677 UNREACHABLE();
678 }
679 }
680
681 BIND(&call_with_any_feedback);
682 {
683 var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny);
684 Goto(&call_stub);
685 }
686
687 BIND(&call_stub);
688 {
689 UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector(), slot_id,
690 update_feedback_mode);
692 switch (op) {
693 case Operation::kSubtract:
694 result = CallBuiltin(Builtin::kSubtract, context(), lhs, rhs);
695 break;
696 case Operation::kMultiply:
697 result = CallBuiltin(Builtin::kMultiply, context(), lhs, rhs);
698 break;
699 case Operation::kDivide:
700 result = CallBuiltin(Builtin::kDivide, context(), lhs, rhs);
701 break;
702 case Operation::kModulus:
703 result = CallBuiltin(Builtin::kModulus, context(), lhs, rhs);
704 break;
705 case Operation::kExponentiate:
706 result = CallBuiltin(Builtin::kExponentiate, context(), lhs, rhs);
707 break;
708 default:
709 UNREACHABLE();
710 }
711 var_result = result;
712 Goto(&end);
713 }
714
715 BIND(&end);
716 return var_result.value();
717}
718
720 const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
721 TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
722 UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
723 auto smiFunction = [=, this](TNode<Smi> lhs, TNode<Smi> rhs,
724 TVariable<Smi>* var_type_feedback) {
725 Label end(this);
726 TVARIABLE(Number, var_result);
727 // If rhs is known to be an Smi (for SubSmi) we want to fast path Smi
728 // operation. For the normal Sub operation, we want to fast path both
729 // Smi and Number operations, so this path should not be marked as Deferred.
730 Label if_overflow(this,
731 rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
732 var_result = TrySmiSub(lhs, rhs, &if_overflow);
734 Goto(&end);
735
736 BIND(&if_overflow);
737 {
738 *var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
739 TNode<Float64T> value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs));
740 var_result = AllocateHeapNumberWithValue(value);
741 Goto(&end);
742 }
743
744 BIND(&end);
745 return var_result.value();
746 };
747 auto floatFunction = [=, this](TNode<Float64T> lhs, TNode<Float64T> rhs) {
748 return Float64Sub(lhs, rhs);
749 };
751 context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction,
752 floatFunction, Operation::kSubtract, update_feedback_mode, rhs_known_smi);
753}
754
756 const LazyNode<Context>& context, TNode<Object> lhs, TNode<Object> rhs,
757 TNode<UintPtrT> slot_id, const LazyNode<HeapObject>& maybe_feedback_vector,
758 UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
759 auto smiFunction = [=, this](TNode<Smi> lhs, TNode<Smi> rhs,
760 TVariable<Smi>* var_type_feedback) {
761 TNode<Number> result = SmiMul(lhs, rhs);
762 *var_type_feedback = SelectSmiConstant(
765 return result;
766 };
767 auto floatFunction = [=, this](TNode<Float64T> lhs, TNode<Float64T> rhs) {
768 return Float64Mul(lhs, rhs);
769 };
771 context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction,
772 floatFunction, Operation::kMultiply, update_feedback_mode, rhs_known_smi);
773}
774
776 const LazyNode<Context>& context, TNode<Object> dividend,
777 TNode<Object> divisor, TNode<UintPtrT> slot_id,
778 const LazyNode<HeapObject>& maybe_feedback_vector,
779 UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
780 auto smiFunction = [=, this](TNode<Smi> lhs, TNode<Smi> rhs,
781 TVariable<Smi>* var_type_feedback) {
782 TVARIABLE(Object, var_result);
783 // If rhs is known to be an Smi (for DivSmi) we want to fast path Smi
784 // operation. For the normal Div operation, we want to fast path both
785 // Smi and Number operations, so this path should not be marked as Deferred.
786 Label bailout(this, rhs_known_smi ? Label::kDeferred : Label::kNonDeferred),
787 end(this);
788 var_result = TrySmiDiv(lhs, rhs, &bailout);
790 Goto(&end);
791
792 BIND(&bailout);
793 {
794 *var_type_feedback =
796 TNode<Float64T> value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
797 var_result = AllocateHeapNumberWithValue(value);
798 Goto(&end);
799 }
800
801 BIND(&end);
802 return var_result.value();
803 };
804 auto floatFunction = [=, this](TNode<Float64T> lhs, TNode<Float64T> rhs) {
805 return Float64Div(lhs, rhs);
806 };
808 context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction,
809 floatFunction, Operation::kDivide, update_feedback_mode, rhs_known_smi);
810}
811
813 const LazyNode<Context>& context, TNode<Object> dividend,
814 TNode<Object> divisor, TNode<UintPtrT> slot_id,
815 const LazyNode<HeapObject>& maybe_feedback_vector,
816 UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
817 auto smiFunction = [=, this](TNode<Smi> lhs, TNode<Smi> rhs,
818 TVariable<Smi>* var_type_feedback) {
819 TNode<Number> result = SmiMod(lhs, rhs);
820 *var_type_feedback = SelectSmiConstant(
823 return result;
824 };
825 auto floatFunction = [=, this](TNode<Float64T> lhs, TNode<Float64T> rhs) {
826 return Float64Mod(lhs, rhs);
827 };
829 context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction,
830 floatFunction, Operation::kModulus, update_feedback_mode, rhs_known_smi);
831}
832
834 const LazyNode<Context>& context, TNode<Object> base,
835 TNode<Object> exponent, TNode<UintPtrT> slot_id,
836 const LazyNode<HeapObject>& maybe_feedback_vector,
837 UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi) {
838 auto smiFunction = [=, this](TNode<Smi> base, TNode<Smi> exponent,
839 TVariable<Smi>* var_type_feedback) {
840 *var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
842 Float64Pow(SmiToFloat64(base), SmiToFloat64(exponent)));
843 };
844 auto floatFunction = [=, this](TNode<Float64T> base,
845 TNode<Float64T> exponent) {
846 return Float64Pow(base, exponent);
847 };
849 context, base, exponent, slot_id, maybe_feedback_vector, smiFunction,
850 floatFunction, Operation::kExponentiate, update_feedback_mode,
851 rhs_known_smi);
852}
853
855 Operation bitwise_op, TNode<Object> left, TNode<Object> right,
856 const LazyNode<Context>& context, TNode<UintPtrT>* slot,
857 const LazyNode<HeapObject>* maybe_feedback_vector,
858 UpdateFeedbackMode update_feedback_mode) {
860 TVARIABLE(Smi, var_left_feedback);
861 TVARIABLE(Smi, var_right_feedback);
862 TVARIABLE(Word32T, var_left_word32);
863 TVARIABLE(Word32T, var_right_word32);
864 TVARIABLE(BigInt, var_left_bigint);
865 Label done(this);
866 Label if_left_number(this), do_number_op(this);
867 Label if_left_bigint(this), if_left_bigint64(this);
868 Label if_left_number_right_bigint(this, Label::kDeferred);
869
870 FeedbackValues feedback_values =
871 slot ? FeedbackValues{&var_left_feedback, maybe_feedback_vector, slot,
872 update_feedback_mode}
873 : FeedbackValues();
874
876 context(), left, &if_left_number, &var_left_word32, &if_left_bigint,
877 IsBigInt64OpSupported(this, bitwise_op) ? &if_left_bigint64 : nullptr,
878 &var_left_bigint, feedback_values);
879
880 BIND(&if_left_number);
881 feedback_values.var_feedback = slot ? &var_right_feedback : nullptr;
883 context(), right, &do_number_op, &var_right_word32,
884 &if_left_number_right_bigint, nullptr, nullptr, feedback_values);
885
886 BIND(&if_left_number_right_bigint);
887 {
888 if (slot) {
889 // Ensure that the feedback is updated before we throw.
891 (*maybe_feedback_vector)(), *slot, update_feedback_mode);
892 }
893 ThrowTypeError(context(), MessageTemplate::kBigIntMixedTypes);
894 }
895
896 BIND(&do_number_op);
897 {
898 result = BitwiseOp(var_left_word32.value(), var_right_word32.value(),
899 bitwise_op);
900
901 if (slot) {
902 TNode<Smi> result_type = SelectSmiConstant(
905 TNode<Smi> input_feedback =
906 SmiOr(var_left_feedback.value(), var_right_feedback.value());
907 TNode<Smi> feedback = SmiOr(result_type, input_feedback);
908 UpdateFeedback(feedback, (*maybe_feedback_vector)(), *slot,
909 update_feedback_mode);
910 }
911 Goto(&done);
912 }
913
914 // BigInt cases.
915 {
916 TVARIABLE(BigInt, var_right_bigint);
917 Label if_both_bigint(this), if_both_bigint64(this);
918 Label if_bigint_mix(this, Label::kDeferred);
919
920 BIND(&if_left_bigint);
921 TaggedToBigInt(context(), right, &if_bigint_mix, &if_both_bigint, nullptr,
922 &var_right_bigint, slot ? &var_right_feedback : nullptr);
923
924 if (IsBigInt64OpSupported(this, bitwise_op)) {
925 BIND(&if_left_bigint64);
926 TaggedToBigInt(context(), right, &if_bigint_mix, &if_both_bigint,
927 &if_both_bigint64, &var_right_bigint,
928 slot ? &var_right_feedback : nullptr);
929
930 BIND(&if_both_bigint64);
931 if (slot) {
932 // {feedback} is Any if {left} or {right} is non-number.
933 TNode<Smi> feedback =
934 SmiOr(var_left_feedback.value(), var_right_feedback.value());
935 UpdateFeedback(feedback, (*maybe_feedback_vector)(), *slot,
936 update_feedback_mode);
937 }
938
939 TVARIABLE(UintPtrT, left_raw);
940 TVARIABLE(UintPtrT, right_raw);
941 BigIntToRawBytes(var_left_bigint.value(), &left_raw, &left_raw);
942 BigIntToRawBytes(var_right_bigint.value(), &right_raw, &right_raw);
943
944 switch (bitwise_op) {
945 case Operation::kBitwiseAnd: {
947 WordAnd(left_raw.value(), right_raw.value())));
948 Goto(&done);
949 break;
950 }
951 case Operation::kBitwiseOr: {
953 WordOr(left_raw.value(), right_raw.value())));
954 Goto(&done);
955 break;
956 }
957 case Operation::kBitwiseXor: {
959 WordXor(left_raw.value(), right_raw.value())));
960 Goto(&done);
961 break;
962 }
963 default:
964 UNREACHABLE();
965 }
966 }
967
968 BIND(&if_both_bigint);
969 {
970 if (slot) {
971 // Ensure that the feedback is updated even if the runtime call below
972 // would throw.
973 TNode<Smi> feedback =
974 SmiOr(var_left_feedback.value(), var_right_feedback.value());
975 UpdateFeedback(feedback, (*maybe_feedback_vector)(), *slot,
976 update_feedback_mode);
977 }
978
979 switch (bitwise_op) {
980 case Operation::kBitwiseAnd: {
981 result =
982 CallBuiltin(Builtin::kBigIntBitwiseAndNoThrow, context(),
983 var_left_bigint.value(), var_right_bigint.value());
984 // Check for sentinel that signals BigIntTooBig exception.
985 GotoIfNot(TaggedIsSmi(result.value()), &done);
986
987 if (slot) {
988 // Update feedback to prevent deopt loop.
990 (*maybe_feedback_vector)(), *slot,
991 update_feedback_mode);
992 }
993 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
994 break;
995 }
996 case Operation::kBitwiseOr: {
997 result =
998 CallBuiltin(Builtin::kBigIntBitwiseOrNoThrow, context(),
999 var_left_bigint.value(), var_right_bigint.value());
1000 // Check for sentinel that signals BigIntTooBig exception.
1001 GotoIfNot(TaggedIsSmi(result.value()), &done);
1002
1003 if (slot) {
1004 // Update feedback to prevent deopt loop.
1006 (*maybe_feedback_vector)(), *slot,
1007 update_feedback_mode);
1008 }
1009 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
1010 break;
1011 }
1012 case Operation::kBitwiseXor: {
1013 result =
1014 CallBuiltin(Builtin::kBigIntBitwiseXorNoThrow, context(),
1015 var_left_bigint.value(), var_right_bigint.value());
1016 // Check for sentinel that signals BigIntTooBig exception.
1017 GotoIfNot(TaggedIsSmi(result.value()), &done);
1018
1019 if (slot) {
1020 // Update feedback to prevent deopt loop.
1022 (*maybe_feedback_vector)(), *slot,
1023 update_feedback_mode);
1024 }
1025 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
1026 break;
1027 }
1028 case Operation::kShiftLeft: {
1029 result =
1030 CallBuiltin(Builtin::kBigIntShiftLeftNoThrow, context(),
1031 var_left_bigint.value(), var_right_bigint.value());
1032 // Check for sentinel that signals BigIntTooBig exception.
1033 GotoIfNot(TaggedIsSmi(result.value()), &done);
1034
1035 if (slot) {
1036 // Update feedback to prevent deopt loop.
1038 (*maybe_feedback_vector)(), *slot,
1039 update_feedback_mode);
1040 }
1041 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
1042 break;
1043 }
1044 case Operation::kShiftRight: {
1045 result =
1046 CallBuiltin(Builtin::kBigIntShiftRightNoThrow, context(),
1047 var_left_bigint.value(), var_right_bigint.value());
1048 // Check for sentinel that signals BigIntTooBig exception.
1049 GotoIfNot(TaggedIsSmi(result.value()), &done);
1050
1051 if (slot) {
1052 // Update feedback to prevent deopt loop.
1054 (*maybe_feedback_vector)(), *slot,
1055 update_feedback_mode);
1056 }
1057 ThrowRangeError(context(), MessageTemplate::kBigIntTooBig);
1058 break;
1059 }
1060 case Operation::kShiftRightLogical: {
1061 if (slot) {
1062 // Ensure that the feedback is updated before we throw.
1064 (*maybe_feedback_vector)(), *slot,
1065 update_feedback_mode);
1066 }
1067 // BigInt does not support logical right shift.
1068 ThrowTypeError(context(), MessageTemplate::kBigIntShr);
1069 break;
1070 }
1071 default:
1072 UNREACHABLE();
1073 }
1074 }
1075
1076 BIND(&if_bigint_mix);
1077 {
1078 if (slot) {
1079 // Ensure that the feedback is updated before we throw.
1081 (*maybe_feedback_vector)(), *slot, update_feedback_mode);
1082 }
1083 ThrowTypeError(context(), MessageTemplate::kBigIntMixedTypes);
1084 }
1085 }
1086
1087 BIND(&done);
1088 return result.value();
1089}
1090
1093 Operation bitwise_op, TNode<Object> left, TNode<Object> right,
1094 const LazyNode<Context>& context, TNode<UintPtrT>* slot,
1095 const LazyNode<HeapObject>* maybe_feedback_vector,
1096 UpdateFeedbackMode update_feedback_mode) {
1097 TNode<Smi> right_smi = CAST(right);
1099 TVARIABLE(Smi, var_left_feedback);
1100 TVARIABLE(Word32T, var_left_word32);
1101 TVARIABLE(BigInt, var_left_bigint);
1102 TVARIABLE(Smi, feedback);
1103 // Check if the {lhs} is a Smi or a HeapObject.
1104 Label if_lhsissmi(this), if_lhsisnotsmi(this, Label::kDeferred);
1105 Label do_number_op(this), if_bigint_mix(this), done(this);
1106
1107 Branch(TaggedIsSmi(left), &if_lhsissmi, &if_lhsisnotsmi);
1108
1109 BIND(&if_lhsissmi);
1110 {
1111 TNode<Smi> left_smi = CAST(left);
1112 result = BitwiseSmiOp(left_smi, right_smi, bitwise_op);
1113 if (slot) {
1114 if (IsBitwiseOutputKnownSmi(bitwise_op)) {
1116 } else {
1117 feedback = SelectSmiConstant(TaggedIsSmi(result.value()),
1120 }
1121 }
1122 Goto(&done);
1123 }
1124
1125 BIND(&if_lhsisnotsmi);
1126 {
1127 TNode<HeapObject> left_pointer = CAST(left);
1128 FeedbackValues feedback_values{&var_left_feedback, maybe_feedback_vector,
1129 slot, update_feedback_mode};
1131 context(), left_pointer, &do_number_op, &var_left_word32,
1132 &if_bigint_mix, nullptr, &var_left_bigint, feedback_values);
1133 BIND(&do_number_op);
1134 {
1135 result =
1136 BitwiseOp(var_left_word32.value(), SmiToInt32(right_smi), bitwise_op);
1137 if (slot) {
1138 TNode<Smi> result_type = SelectSmiConstant(
1141 feedback = SmiOr(result_type, var_left_feedback.value());
1142 }
1143 Goto(&done);
1144 }
1145
1146 BIND(&if_bigint_mix);
1147 {
1148 if (slot) {
1149 // Ensure that the feedback is updated before we throw.
1151 (*maybe_feedback_vector)(), *slot, update_feedback_mode);
1152 }
1153 ThrowTypeError(context(), MessageTemplate::kBigIntMixedTypes);
1154 }
1155 }
1156
1157 BIND(&done);
1158 if (slot) {
1159 UpdateFeedback(feedback.value(), (*maybe_feedback_vector)(), *slot,
1160 update_feedback_mode);
1161 }
1162 return result.value();
1163}
1164
1166
1167} // namespace internal
1168} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
bool IsBitwiseOutputKnownSmi(Operation bitwise_op)
std::function< TNode< Object >(TNode< Smi >, TNode< Smi >, TVariable< Smi > *)> SmiOperation
TNode< Object > Generate_BitwiseBinaryOpWithSmiOperandAndOptionalFeedback(Operation bitwise_op, TNode< Object > left, TNode< Object > right, const LazyNode< Context > &context, TNode< UintPtrT > *slot, const LazyNode< HeapObject > *maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode)
std::function< TNode< Float64T >(TNode< Float64T >, TNode< Float64T >)> FloatOperation
TNode< Object > Generate_ExponentiateWithFeedback(const LazyNode< Context > &context, TNode< Object > base, TNode< Object > exponent, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Object > Generate_BinaryOperationWithFeedback(const LazyNode< Context > &context, TNode< Object > left, TNode< Object > right, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, const SmiOperation &smiOperation, const FloatOperation &floatOperation, Operation op, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Object > Generate_DivideWithFeedback(const LazyNode< Context > &context, TNode< Object > dividend, TNode< Object > divisor, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Object > Generate_AddWithFeedback(const LazyNode< Context > &context, TNode< Object > left, TNode< Object > right, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Object > Generate_BitwiseBinaryOpWithOptionalFeedback(Operation bitwise_op, TNode< Object > left, TNode< Object > right, const LazyNode< Context > &context, TNode< UintPtrT > *slot, const LazyNode< HeapObject > *maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode)
TNode< Object > Generate_MultiplyWithFeedback(const LazyNode< Context > &context, TNode< Object > left, TNode< Object > right, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Object > Generate_SubtractWithFeedback(const LazyNode< Context > &context, TNode< Object > left, TNode< Object > right, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Object > Generate_ModulusWithFeedback(const LazyNode< Context > &context, TNode< Object > dividend, TNode< Object > divisor, TNode< UintPtrT > slot, const LazyNode< HeapObject > &maybe_feedback_vector, UpdateFeedbackMode update_feedback_mode, bool rhs_known_smi)
TNode< Number > SmiMod(TNode< Smi > a, TNode< Smi > b)
void TaggedToWord32OrBigIntWithFeedback(TNode< Context > context, TNode< Object > value, Label *if_number, TVariable< Word32T > *var_word32, Label *if_bigint, Label *if_bigint64, TVariable< BigInt > *var_maybe_bigint, const FeedbackValues &feedback)
TNode< IntPtrT > TryIntPtrDiv(TNode< IntPtrT > a, TNode< IntPtrT > b, Label *if_div_zero)
TNode< BoolT > InstanceTypeEqual(TNode< Int32T > instance_type, int type)
TNode< Smi > TrySmiSub(TNode< Smi > a, TNode< Smi > b, Label *if_overflow)
void ThrowRangeError(TNode< Context > context, MessageTemplate message, std::optional< TNode< Object > > arg0=std::nullopt, std::optional< TNode< Object > > arg1=std::nullopt, std::optional< TNode< Object > > arg2=std::nullopt)
void ThrowTypeError(TNode< Context > context, MessageTemplate message, char const *arg0=nullptr, char const *arg1=nullptr)
TNode< IntPtrT > TryIntPtrMod(TNode< IntPtrT > a, TNode< IntPtrT > b, Label *if_div_zero)
TNode< BoolT > IsAdditiveSafeIntegerFeedbackEnabled()
TNode< BoolT > TaggedEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< T > LoadObjectField(TNode< HeapObject > object, int offset)
void TaggedPointerToWord32OrBigIntWithFeedback(TNode< Context > context, TNode< HeapObject > pointer, Label *if_number, TVariable< Word32T > *var_word32, Label *if_bigint, Label *if_bigint64, TVariable< BigInt > *var_maybe_bigint, const FeedbackValues &feedback)
TNode< BoolT > TaggedIsNotSmi(TNode< MaybeObject > a)
TNode< IntPtrT > TryIntPtrSub(TNode< IntPtrT > a, TNode< IntPtrT > b, Label *if_overflow)
TNode< Number > BitwiseSmiOp(TNode< Smi > left32, TNode< Smi > right32, Operation bitwise_op)
TNode< BigInt > BigIntFromInt64(TNode< IntPtrT > value)
void UpdateFeedback(TNode< Smi > feedback, TNode< HeapObject > maybe_feedback_vector, TNode< UintPtrT > slot_id, UpdateFeedbackMode mode)
void BigIntToRawBytes(TNode< BigInt > bigint, TVariable< UintPtrT > *var_low, TVariable< UintPtrT > *var_high)
TNode< Float64T > SmiToFloat64(TNode< Smi > value)
TNode< BoolT > IsBigIntInstanceType(TNode< Int32T > instance_type)
TNode< IntPtrT > TryIntPtrMul(TNode< IntPtrT > a, TNode< IntPtrT > b, Label *if_overflow)
std::function< TNode< T >()> LazyNode
TNode< HeapNumber > AllocateHeapNumberWithValue(TNode< Float64T > value)
TNode< Word32T > IsStringWrapper(TNode< HeapObject > object)
TNode< Uint16T > LoadInstanceType(TNode< HeapObject > object)
void TerminateExecution(TNode< Context > context)
TNode< T > Select(TNode< BoolT > condition, const NodeGenerator< T > &true_body, const NodeGenerator< T > &false_body, BranchHint branch_hint=BranchHint::kNone)
TNode< BoolT > TaggedIsSmi(TNode< MaybeObject > a)
TNode< BoolT > IsAdditiveSafeInteger(TNode< Float64T > number)
TNode< Float64T > LoadHeapNumberValue(TNode< HeapObject > object)
TNode< Number > BitwiseOp(TNode< Word32T > left32, TNode< Word32T > right32, Operation bitwise_op)
TNode< Object > LoadJSPrimitiveWrapperValue(TNode< JSPrimitiveWrapper > object)
void GotoIfLargeBigInt(TNode< BigInt > bigint, Label *true_label)
TNode< Int32T > SmiToInt32(TNode< Smi > value)
TNode< IntPtrT > TryIntPtrAdd(TNode< IntPtrT > a, TNode< IntPtrT > b, Label *if_overflow)
void TaggedToBigInt(TNode< Context > context, TNode< Object > value, Label *if_not_bigint, Label *if_bigint, Label *if_bigint64, TVariable< BigInt > *var_bigint, TVariable< Smi > *var_feedback)
TNode< BoolT > IsStringInstanceType(TNode< Int32T > instance_type)
TNode< Smi > SelectSmiConstant(TNode< BoolT > condition, Tagged< Smi > true_value, Tagged< Smi > false_value)
TNode< Smi > TrySmiDiv(TNode< Smi > dividend, TNode< Smi > divisor, Label *bailout)
TNode< BoolT > IsBigInt(TNode< HeapObject > object)
TNode< Number > SmiMul(TNode< Smi > a, TNode< Smi > b)
TNode< Smi > TrySmiAdd(TNode< Smi > a, TNode< Smi > b, Label *if_overflow)
static const int kProtectorInvalid
Definition protectors.h:16
TNode< IntPtrT > WordOr(TNode< IntPtrT > left, TNode< IntPtrT > right)
void Comment(MessageWithSourceLocation message, Args &&... args)
TNode< T > UncheckedCast(Node *value)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
TNode< Smi > SmiConstant(Tagged< Smi > value)
void GotoIf(TNode< IntegralT > condition, Label *true_label, GotoHint goto_hint=GotoHint::kNone)
TNode< IntPtrT > WordAnd(TNode< IntPtrT > left, TNode< IntPtrT > right)
TNode< BoolT > BoolConstant(bool value)
TNode< T > CallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
TNode< T > CallBuiltin(Builtin id, TNode< Object > context, TArgs... args)
void Branch(TNode< IntegralT > condition, Label *true_label, Label *false_label, BranchHint branch_hint=BranchHint::kNone)
#define CAST(x)
int end
TNode< Context > context
ZoneVector< RpoNumber > & result
return value
Definition map-inl.h:893
Operation
Definition operation.h:43