v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-typed-lowering.cc
Go to the documentation of this file.
1// Copyright 2014 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
7#include <optional>
8
9#include "src/ast/modules.h"
14#include "src/common/globals.h"
26#include "src/compiler/node.h"
34#include "src/flags/flags.h"
35#include "src/objects/casting.h"
40#include "src/objects/objects.h"
42
43namespace v8 {
44namespace internal {
45namespace compiler {
46
47// A helper class to simplify the process of reducing a single binop node with a
48// JSOperator. This class manages the rewriting of context, control, and effect
49// dependencies during lowering of a binop and contains numerous helper
50// functions for matching the types of inputs to an operation.
51class JSBinopReduction final {
52 public:
54 : lowering_(lowering), node_(node) {}
55
84
109
111 DCHECK_EQ(1, node_->op()->EffectOutputCount());
114 BothInputsMaybe(Type::InternalizedString());
115 }
116
118 DCHECK_EQ(1, node_->op()->EffectOutputCount());
121 BothInputsMaybe(Type::Receiver());
122 }
123
125 DCHECK_EQ(1, node_->op()->EffectOutputCount());
128 BothInputsMaybe(Type::ReceiverOrNullOrUndefined());
129 }
130
132 DCHECK_EQ(1, node_->op()->EffectOutputCount());
134 BothInputsMaybe(Type::String());
135 }
136
138 DCHECK_EQ(1, node_->op()->EffectOutputCount());
140 BothInputsMaybe(Type::Symbol());
141 }
142
143 // Check if a string addition will definitely result in creating a ConsString,
144 // i.e. if the combined length of the resulting string exceeds the ConsString
145 // minimum length.
147 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
148 DCHECK(OneInputIs(Type::String()));
149 if (node_->InputAt(1)->opcode() == IrOpcode::kNewConsString) {
150 // If the right hand side is a ConsString, then we can create a
151 // ConsString. This doesn't work with the left hand side, since the right
152 // hand side of a ConsString cannot be the empty string except when the
153 // left hand side is a SeqString or External string, but we don't know
154 // that here.
155 return true;
156 }
157 if (BothInputsAre(Type::String()) ||
161 if (m.right().HasResolvedValue() && m.right().Ref(broker).IsString()) {
162 StringRef right_string = m.right().Ref(broker).AsString();
163 if (right_string.length() >= ConsString::kMinLength) return true;
164 }
165 if (m.left().HasResolvedValue() && m.left().Ref(broker).IsString()) {
166 StringRef left_string = m.left().Ref(broker).AsString();
167 if (left_string.length() >= ConsString::kMinLength) {
168 // The invariant for ConsString requires the left hand side to be
169 // a sequential or external string if the right hand side is the
170 // empty string. Since we don't know anything about the right hand
171 // side here, we must ensure that the left hand side satisfy the
172 // constraints independent of the right hand side.
173 return left_string.IsSeqString() || left_string.IsExternalString();
174 }
175 }
176 }
177 return false;
178 }
179
180 // Inserts a CheckReceiver for the left input.
182 Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
183 effect(), control());
184 node_->ReplaceInput(0, left_input);
185 update_effect(left_input);
186 }
187
188 // Inserts a CheckReceiverOrNullOrUndefined for the left input.
190 Node* left_input =
191 graph()->NewNode(simplified()->CheckReceiverOrNullOrUndefined(), left(),
192 effect(), control());
193 node_->ReplaceInput(0, left_input);
194 update_effect(left_input);
195 }
196
197 // Checks that both inputs are Receiver, and if we don't know
198 // statically that one side is already a Receiver, insert a
199 // CheckReceiver node.
201 if (!left_type().Is(Type::Receiver())) {
203 }
204 if (!right_type().Is(Type::Receiver())) {
205 Node* right_input = graph()->NewNode(simplified()->CheckReceiver(),
206 right(), effect(), control());
207 node_->ReplaceInput(1, right_input);
208 update_effect(right_input);
209 }
210 }
211
212 // Checks that both inputs are Receiver, Null or Undefined and if
213 // we don't know statically that one side is already a Receiver,
214 // Null or Undefined, insert CheckReceiverOrNullOrUndefined nodes.
216 if (!left_type().Is(Type::ReceiverOrNullOrUndefined())) {
218 }
219 if (!right_type().Is(Type::ReceiverOrNullOrUndefined())) {
220 Node* right_input =
221 graph()->NewNode(simplified()->CheckReceiverOrNullOrUndefined(),
222 right(), effect(), control());
223 node_->ReplaceInput(1, right_input);
224 update_effect(right_input);
225 }
226 }
227
228 // Inserts a CheckSymbol for the left input.
230 Node* left_input = graph()->NewNode(simplified()->CheckSymbol(), left(),
231 effect(), control());
232 node_->ReplaceInput(0, left_input);
233 update_effect(left_input);
234 }
235
236 // Checks that both inputs are Symbol, and if we don't know
237 // statically that one side is already a Symbol, insert a
238 // CheckSymbol node.
240 if (!left_type().Is(Type::Symbol())) {
242 }
243 if (!right_type().Is(Type::Symbol())) {
244 Node* right_input = graph()->NewNode(simplified()->CheckSymbol(), right(),
245 effect(), control());
246 node_->ReplaceInput(1, right_input);
247 update_effect(right_input);
248 }
249 }
250
251 // Checks that both inputs are String, and if we don't know
252 // statically that one side is already a String, insert a
253 // CheckString node.
255 if (!left_type().Is(Type::String())) {
256 Node* left_input =
257 graph()->NewNode(simplified()->CheckString(FeedbackSource()), left(),
258 effect(), control());
259 node_->ReplaceInput(0, left_input);
260 update_effect(left_input);
261 }
262 if (!right_type().Is(Type::String())) {
263 Node* right_input =
264 graph()->NewNode(simplified()->CheckString(FeedbackSource()), right(),
265 effect(), control());
266 node_->ReplaceInput(1, right_input);
267 update_effect(right_input);
268 }
269 }
270
271 // Checks that both inputs are String or string wrapper, and if we don't know
272 // statically that one side is already a String or a string wrapper, insert a
273 // CheckStringOrStringWrapper node.
275 if (!left_type().Is(Type::StringOrStringWrapper())) {
276 Node* left_input = graph()->NewNode(
277 simplified()->CheckStringOrStringWrapper(FeedbackSource()), left(),
278 effect(), control());
279 node_->ReplaceInput(0, left_input);
280 update_effect(left_input);
281 }
282 if (!right_type().Is(Type::StringOrStringWrapper())) {
283 Node* right_input = graph()->NewNode(
284 simplified()->CheckStringOrStringWrapper(FeedbackSource()), right(),
285 effect(), control());
286 node_->ReplaceInput(1, right_input);
287 update_effect(right_input);
288 }
289 }
290
291 // Checks that both inputs are InternalizedString, and if we don't know
292 // statically that one side is already an InternalizedString, insert a
293 // CheckInternalizedString node.
295 if (!left_type().Is(Type::UniqueName())) {
296 Node* left_input = graph()->NewNode(
297 simplified()->CheckInternalizedString(), left(), effect(), control());
298 node_->ReplaceInput(0, left_input);
299 update_effect(left_input);
300 }
301 if (!right_type().Is(Type::UniqueName())) {
302 Node* right_input =
303 graph()->NewNode(simplified()->CheckInternalizedString(), right(),
304 effect(), control());
305 node_->ReplaceInput(1, right_input);
306 update_effect(right_input);
307 }
308 }
309
311 DCHECK(left_type().Is(Type::PlainPrimitive()));
312 DCHECK(right_type().Is(Type::PlainPrimitive()));
315 }
316
317 void ConvertInputsToUI32(Signedness left_signedness,
318 Signedness right_signedness) {
319 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
320 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
321 }
322
323 void SwapInputs() {
324 Node* l = left();
325 Node* r = right();
326 node_->ReplaceInput(0, r);
327 node_->ReplaceInput(1, l);
328 }
329
330 // Remove all effect and control inputs and outputs to this node and change
331 // to the pure operator {op}.
333 DCHECK_EQ(0, op->EffectInputCount());
336 DCHECK_EQ(2, op->ValueInputCount());
337
338 // Remove the effects from the node, and update its effect/control usages.
339 if (node_->op()->EffectInputCount() > 0) {
340 lowering_->RelaxEffectsAndControls(node_);
341 }
342 // Remove the inputs corresponding to context, effect, and control.
344 // Remove the feedback vector input, if applicable.
346 node_->RemoveInput(JSBinaryOpNode::FeedbackVectorIndex());
347 }
348 // Finally, update the operator to the new one.
350
351 // TODO(jarin): Replace the explicit typing hack with a call to some method
352 // that encapsulates changing the operator and re-typing.
355
356 return lowering_->Changed(node_);
357 }
358
360 DCHECK_EQ(1, op->EffectInputCount());
366 DCHECK_EQ(2, op->ValueInputCount());
367
368 DCHECK_EQ(1, node_->op()->EffectInputCount());
369 DCHECK_EQ(1, node_->op()->EffectOutputCount());
370 DCHECK_EQ(1, node_->op()->ControlInputCount());
371
372 // Reconnect the control output to bypass the IfSuccess node and
373 // possibly disconnect from the IfException node.
374 lowering_->RelaxControls(node_);
375
376 // Remove the frame state and the context.
379 }
381
382 // Remove the feedback vector input, if applicable.
384 node_->RemoveInput(JSBinaryOpNode::FeedbackVectorIndex());
385 }
386 // Finally, update the operator to the new one.
388
389 // Update the type to number.
392 Type::Intersect(node_type, upper_bound, zone()));
393
394 return lowering_->Changed(node_);
395 }
396
398 switch (node_->opcode()) {
399 case IrOpcode::kJSAdd:
400 return simplified()->NumberAdd();
401 case IrOpcode::kJSSubtract:
402 return simplified()->NumberSubtract();
403 case IrOpcode::kJSMultiply:
404 return simplified()->NumberMultiply();
405 case IrOpcode::kJSDivide:
406 return simplified()->NumberDivide();
407 case IrOpcode::kJSModulus:
408 return simplified()->NumberModulus();
409 case IrOpcode::kJSExponentiate:
410 return simplified()->NumberPow();
411 case IrOpcode::kJSBitwiseAnd:
412 return simplified()->NumberBitwiseAnd();
413 case IrOpcode::kJSBitwiseOr:
414 return simplified()->NumberBitwiseOr();
415 case IrOpcode::kJSBitwiseXor:
416 return simplified()->NumberBitwiseXor();
417 case IrOpcode::kJSShiftLeft:
418 return simplified()->NumberShiftLeft();
419 case IrOpcode::kJSShiftRight:
420 return simplified()->NumberShiftRight();
421 case IrOpcode::kJSShiftRightLogical:
423 default:
424 break;
425 }
426 UNREACHABLE();
427 }
428
429 bool LeftInputIs(Type t) { return left_type().Is(t); }
430
431 bool RightInputIs(Type t) { return right_type().Is(t); }
432
433 bool OneInputIs(Type t) { return LeftInputIs(t) || RightInputIs(t); }
434
435 bool BothInputsAre(Type t) { return LeftInputIs(t) && RightInputIs(t); }
436
438 return left_type().Maybe(t) && right_type().Maybe(t);
439 }
440
442 return !left_type().Maybe(t) || !right_type().Maybe(t);
443 }
444
446 return !left_type().Maybe(t) && !right_type().Maybe(t);
447 }
448
453
462
464 TFGraph* graph() const { return lowering_->graph(); }
466 Isolate* isolate() { return jsgraph()->isolate(); }
469 Zone* zone() const { return graph()->zone(); }
470
471 private:
472 JSTypedLowering* lowering_; // The containing lowering instance.
473 Node* node_; // The original node.
474
476 DCHECK(NodeProperties::GetType(node).Is(Type::PlainPrimitive()));
477 // Avoid inserting too many eager ToNumber() operations.
478 Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
479 if (reduction.Changed()) return reduction.replacement();
480 if (NodeProperties::GetType(node).Is(Type::Number())) {
481 return node;
482 }
483 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
484 }
485
486 Node* ConvertToUI32(Node* node, Signedness signedness) {
487 // Avoid introducing too many eager NumberToXXnt32() operations.
488 Type type = NodeProperties::GetType(node);
489 if (signedness == kSigned) {
490 if (!type.Is(Type::Signed32())) {
491 node = graph()->NewNode(simplified()->NumberToInt32(), node);
492 }
493 } else {
494 DCHECK_EQ(kUnsigned, signedness);
495 if (!type.Is(Type::Unsigned32())) {
496 node = graph()->NewNode(simplified()->NumberToUint32(), node);
497 }
498 }
499 return node;
500 }
501
506
507 void update_effect(Node* effect) {
509 }
510};
511
512
513// TODO(turbofan): js-typed-lowering improvements possible
514// - immediately put in type bounds for all new nodes
515// - relax effects from generic but not-side-effecting operations
516
518 JSHeapBroker* broker, Zone* zone)
519 : AdvancedReducer(editor),
520 jsgraph_(jsgraph),
522 empty_string_type_(
523 Type::Constant(broker, broker->empty_string(), graph()->zone())),
524 pointer_comparable_type_(
526 Type::Hole(), graph()->zone()),
527 Type::Union(Type::SymbolOrReceiver(), empty_string_type_,
528 graph()->zone()),
529 graph()->zone())),
530 type_cache_(TypeCache::Get()) {}
531
533 Node* input = NodeProperties::GetValueInput(node, 0);
534 Type input_type = NodeProperties::GetType(input);
535 if (input_type.Is(Type::PlainPrimitive())) {
536 // JSBitwiseNot(x) => NumberBitwiseXor(ToInt32(x), -1)
537 const FeedbackParameter& p = FeedbackParameterOf(node->op());
538 node->InsertInput(graph()->zone(), 1, jsgraph()->SmiConstant(-1));
539 NodeProperties::ChangeOp(node, javascript()->BitwiseXor(p.feedback()));
540 JSBinopReduction r(this, node);
541 r.ConvertInputsToNumber();
542 r.ConvertInputsToUI32(kSigned, kSigned);
543 return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
544 }
545 return NoChange();
546}
547
549 Node* input = NodeProperties::GetValueInput(node, 0);
550 Type input_type = NodeProperties::GetType(input);
551 if (input_type.Is(Type::PlainPrimitive())) {
552 // JSDecrement(x) => NumberSubtract(ToNumber(x), 1)
553 const FeedbackParameter& p = FeedbackParameterOf(node->op());
554 node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
555 NodeProperties::ChangeOp(node, javascript()->Subtract(p.feedback()));
556 JSBinopReduction r(this, node);
557 r.ConvertInputsToNumber();
558 DCHECK_EQ(simplified()->NumberSubtract(), r.NumberOp());
559 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
560 }
561 return NoChange();
562}
563
565 Node* input = NodeProperties::GetValueInput(node, 0);
566 Type input_type = NodeProperties::GetType(input);
567 if (input_type.Is(Type::PlainPrimitive())) {
568 // JSIncrement(x) => NumberAdd(ToNumber(x), 1)
569 const FeedbackParameter& p = FeedbackParameterOf(node->op());
570 node->InsertInput(graph()->zone(), 1, jsgraph()->OneConstant());
572 JSBinopReduction r(this, node);
573 r.ConvertInputsToNumber();
574 DCHECK_EQ(simplified()->NumberAdd(), r.NumberOp());
575 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
576 }
577 return NoChange();
578}
579
581 Node* input = NodeProperties::GetValueInput(node, 0);
582 Type input_type = NodeProperties::GetType(input);
583 if (input_type.Is(Type::PlainPrimitive())) {
584 // JSNegate(x) => NumberMultiply(ToNumber(x), -1)
585 const FeedbackParameter& p = FeedbackParameterOf(node->op());
586 node->InsertInput(graph()->zone(), 1, jsgraph()->SmiConstant(-1));
587 NodeProperties::ChangeOp(node, javascript()->Multiply(p.feedback()));
588 JSBinopReduction r(this, node);
589 r.ConvertInputsToNumber();
590 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
591 }
592 return NoChange();
593}
594
596 Node* node, Node* left, Node* right, Node* context, Node* frame_state,
597 Node** effect, Node** control, bool should_create_cons_string) {
598 // Compute the resulting length.
599 Node* left_length = graph()->NewNode(simplified()->StringLength(), left);
600 Node* right_length = graph()->NewNode(simplified()->StringLength(), right);
601 Node* length =
602 graph()->NewNode(simplified()->NumberAdd(), left_length, right_length);
603
604 PropertyCellRef string_length_protector =
605 MakeRef(broker(), factory()->string_length_protector());
606 string_length_protector.CacheAsProtector(broker());
607
608 if (string_length_protector.value(broker()).AsSmi() ==
610 // We can just deoptimize if the {length} is out-of-bounds. Besides
611 // generating a shorter code sequence than the version below, this
612 // has the additional benefit of not holding on to the lazy {frame_state}
613 // and thus potentially reduces the number of live ranges and allows for
614 // more truncations.
615 length = *effect = graph()->NewNode(
617 jsgraph()->ConstantNoHole(String::kMaxLength + 1), *effect, *control);
618 } else {
619 // Check if we would overflow the allowed maximum string length.
620 Node* check =
621 graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
622 jsgraph()->ConstantNoHole(String::kMaxLength));
623 Node* branch =
624 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, *control);
625 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
626 Node* efalse = *effect;
627 {
628 // Throw a RangeError in case of overflow.
629 Node* vfalse = efalse = if_false = graph()->NewNode(
630 javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
631 context, frame_state, efalse, if_false);
632
633 // Update potential {IfException} uses of {node} to point to the
634 // %ThrowInvalidStringLength runtime call node instead.
635 Node* on_exception = nullptr;
636 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
637 NodeProperties::ReplaceControlInput(on_exception, vfalse);
638 NodeProperties::ReplaceEffectInput(on_exception, efalse);
639 if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
640 Revisit(on_exception);
641 }
642
643 // The above %ThrowInvalidStringLength runtime call is an unconditional
644 // throw, making it impossible to return a successful completion in this
645 // case. We simply connect the successful completion to the graph end.
646 if_false = graph()->NewNode(common()->Throw(), efalse, if_false);
647 MergeControlToEnd(graph(), common(), if_false);
648 }
649 *control = graph()->NewNode(common()->IfTrue(), branch);
650 length = *effect =
652 length, *effect, *control);
653 }
654 // TODO(bmeurer): Ideally this should always use StringConcat and decide to
655 // optimize to NewConsString later during SimplifiedLowering, but for that
656 // to work we need to know that it's safe to create a ConsString.
657 Operator const* const op = should_create_cons_string
660 Node* value = graph()->NewNode(op, length, left, right);
661 ReplaceWithValue(node, value, *effect, *control);
662 return Replace(value);
663}
664
666 Node** effect, Node** control) {
667 Node* check =
668 graph()->NewNode(simplified()->ObjectIsString(), string_or_wrapper);
669 Node* branch = graph()->NewNode(common()->Branch(), check, *control);
670
671 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
672 Node* etrue = *effect;
673 Node* vtrue = string_or_wrapper;
674
675 // We just checked that the value is a string.
676 vtrue = etrue = graph()->NewNode(common()->TypeGuard(Type::String()), vtrue,
677 etrue, if_true);
678
679 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
680 Node* efalse = *effect;
681
682 Node* vfalse = efalse = graph()->NewNode(
684 string_or_wrapper, *effect, *control);
685
686 // The value read from a string wrapper is a string.
687 vfalse = efalse = graph()->NewNode(common()->TypeGuard(Type::String()),
688 vfalse, efalse, if_false);
689
690 *control = graph()->NewNode(common()->Merge(2), if_true, if_false);
691 *effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, *control);
692
694 vtrue, vfalse, *control);
695}
696
698 JSBinopReduction r(this, node);
699 if (r.BothInputsAre(Type::Number())) {
700 // JSAdd(x:number, y:number) => NumberAdd(x, y)
701 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
702 }
703 if (r.BothInputsAre(Type::PlainPrimitive()) &&
704 r.NeitherInputCanBe(Type::StringOrReceiver())) {
705 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
706 r.ConvertInputsToNumber();
707 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
708 }
709
710 // Strength-reduce if one input is already known to be a string.
711 if (r.LeftInputIs(Type::String())) {
712 // JSAdd(x:string, y) => JSAdd(x, JSToString(y))
713 Reduction const reduction = ReduceJSToStringInput(r.right());
714 if (reduction.Changed()) {
715 NodeProperties::ReplaceValueInput(node, reduction.replacement(), 1);
716 }
717 } else if (r.RightInputIs(Type::String())) {
718 // JSAdd(x, y:string) => JSAdd(JSToString(x), y)
719 Reduction const reduction = ReduceJSToStringInput(r.left());
720 if (reduction.Changed()) {
721 NodeProperties::ReplaceValueInput(node, reduction.replacement(), 0);
722 }
723 }
724
725 PropertyCellRef to_primitive_protector =
726 MakeRef(broker(), factory()->string_wrapper_to_primitive_protector());
727 to_primitive_protector.CacheAsProtector(broker());
728 bool can_inline_string_wrapper_add = false;
729
730 // Always bake in String feedback into the graph.
731 if (r.GetBinaryOperationHint(node) == BinaryOperationHint::kString) {
732 r.CheckInputsToString();
733 } else if (r.GetBinaryOperationHint(node) ==
735 can_inline_string_wrapper_add =
736 dependencies()->DependOnProtector(to_primitive_protector);
737 if (can_inline_string_wrapper_add) {
738 r.CheckInputsToStringOrStringWrapper();
739 }
740 }
741
742 // Strength-reduce concatenation of empty strings if both sides are
743 // primitives, as in that case the ToPrimitive on the other side is
744 // definitely going to be a no-op.
745 if (r.BothInputsAre(Type::Primitive())) {
746 if (r.LeftInputIs(empty_string_type_)) {
747 // JSAdd("", x:primitive) => JSToString(x)
751 node, Type::Intersect(r.type(), Type::String(), graph()->zone()));
752 return Changed(node).FollowedBy(ReduceJSToString(node));
753 } else if (r.RightInputIs(empty_string_type_)) {
754 // JSAdd(x:primitive, "") => JSToString(x)
758 node, Type::Intersect(r.type(), Type::String(), graph()->zone()));
759 return Changed(node).FollowedBy(ReduceJSToString(node));
760 }
761 }
762
763 Node* context = NodeProperties::GetContextInput(node);
764 Node* frame_state = NodeProperties::GetFrameStateInput(node);
765 Node* effect = NodeProperties::GetEffectInput(node);
766 Node* control = NodeProperties::GetControlInput(node);
767
768 // Lower to string addition if both inputs are known to be strings.
769 if (r.BothInputsAre(Type::String())) {
770 return GenerateStringAddition(node, r.left(), r.right(), context,
771 frame_state, &effect, &control,
772 r.ShouldCreateConsString());
773 } else if (r.BothInputsAre(Type::StringOrStringWrapper()) &&
774 can_inline_string_wrapper_add) {
775 // If the left hand side is a string wrapper, unwrap it.
776 Node* left_string = UnwrapStringWrapper(r.left(), &effect, &control);
777
778 // If the right hand side is a string wrapper, unwrap it.
779 Node* right_string = UnwrapStringWrapper(r.right(), &effect, &control);
780
781 // Generate the string addition.
782 return GenerateStringAddition(node, left_string, right_string, context,
783 frame_state, &effect, &control, false);
784 }
785
786 // We never get here when we had String feedback.
787 DCHECK_NE(BinaryOperationHint::kString, r.GetBinaryOperationHint(node));
788 if (r.OneInputIs(Type::String())) {
790 if (!r.LeftInputIs(Type::String())) {
792 } else if (!r.RightInputIs(Type::String())) {
794 }
795 Operator::Properties properties = node->op()->properties();
796 if (r.NeitherInputCanBe(Type::Receiver())) {
797 // Both sides are already strings, so we know that the
798 // string addition will not cause any observable side
799 // effects; it can still throw obviously.
801 }
802
803 // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
804 // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
805 Callable const callable = CodeFactory::StringAdd(isolate(), flags);
806 auto call_descriptor = Linkage::GetStubCallDescriptor(
807 graph()->zone(), callable.descriptor(),
811 node->RemoveInput(JSAddNode::FeedbackVectorIndex());
812 node->InsertInput(graph()->zone(), 0,
813 jsgraph()->HeapConstantNoHole(callable.code()));
814 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
815 return Changed(node);
816 }
817 return NoChange();
818}
819
821 JSBinopReduction r(this, node);
822 if (r.BothInputsAre(Type::PlainPrimitive())) {
823 r.ConvertInputsToNumber();
824 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
825 }
826 return NoChange();
827}
828
830 JSBinopReduction r(this, node);
831 if (r.BothInputsAre(Type::PlainPrimitive())) {
832 r.ConvertInputsToNumber();
833 r.ConvertInputsToUI32(kSigned, kSigned);
834 return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
835 }
836 return NoChange();
837}
838
840 JSBinopReduction r(this, node);
841 if (r.BothInputsAre(Type::PlainPrimitive())) {
842 r.ConvertInputsToNumber();
843 r.ConvertInputsToUI32(signedness, kUnsigned);
844 return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
845 ? Type::Unsigned32()
846 : Type::Signed32());
847 }
848 return NoChange();
849}
850
852 JSBinopReduction r(this, node);
853 if (r.BothInputsAre(Type::String())) {
854 // If both inputs are definitely strings, perform a string comparison.
855 const Operator* stringOp;
856 switch (node->opcode()) {
857 case IrOpcode::kJSLessThan:
858 stringOp = simplified()->StringLessThan();
859 break;
860 case IrOpcode::kJSGreaterThan:
861 stringOp = simplified()->StringLessThan();
862 r.SwapInputs(); // a > b => b < a
863 break;
864 case IrOpcode::kJSLessThanOrEqual:
865 stringOp = simplified()->StringLessThanOrEqual();
866 break;
867 case IrOpcode::kJSGreaterThanOrEqual:
868 stringOp = simplified()->StringLessThanOrEqual();
869 r.SwapInputs(); // a >= b => b <= a
870 break;
871 default:
872 return NoChange();
873 }
874 r.ChangeToPureOperator(stringOp);
875 return Changed(node);
876 }
877
878 const Operator* less_than;
879 const Operator* less_than_or_equal;
880 if (r.BothInputsAre(Type::Signed32()) ||
881 r.BothInputsAre(Type::Unsigned32())) {
882 less_than = simplified()->NumberLessThan();
883 less_than_or_equal = simplified()->NumberLessThanOrEqual();
884 } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
885 r.BothInputsAre(Type::PlainPrimitive())) {
886 r.ConvertInputsToNumber();
887 less_than = simplified()->NumberLessThan();
888 less_than_or_equal = simplified()->NumberLessThanOrEqual();
889 } else if (r.IsStringCompareOperation()) {
890 r.CheckInputsToString();
891 less_than = simplified()->StringLessThan();
892 less_than_or_equal = simplified()->StringLessThanOrEqual();
893 } else {
894 return NoChange();
895 }
896 const Operator* comparison;
897 switch (node->opcode()) {
898 case IrOpcode::kJSLessThan:
899 comparison = less_than;
900 break;
901 case IrOpcode::kJSGreaterThan:
902 comparison = less_than;
903 r.SwapInputs(); // a > b => b < a
904 break;
905 case IrOpcode::kJSLessThanOrEqual:
906 comparison = less_than_or_equal;
907 break;
908 case IrOpcode::kJSGreaterThanOrEqual:
909 comparison = less_than_or_equal;
910 r.SwapInputs(); // a >= b => b <= a
911 break;
912 default:
913 return NoChange();
914 }
915 return r.ChangeToPureOperator(comparison);
916}
917
919 JSBinopReduction r(this, node);
920
921 if (r.BothInputsAre(Type::UniqueName())) {
922 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
923 }
924 if (r.IsInternalizedStringCompareOperation()) {
925 r.CheckInputsToInternalizedString();
926 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
927 }
928 if (r.BothInputsAre(Type::String())) {
929 return r.ChangeToPureOperator(simplified()->StringEqual());
930 }
931 if (r.BothInputsAre(Type::Boolean())) {
932 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
933 }
934 if (r.BothInputsAre(Type::Receiver())) {
935 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
936 }
937 if (r.OneInputIs(Type::NullOrUndefined())) {
938 RelaxEffectsAndControls(node);
939 node->RemoveInput(r.LeftInputIs(Type::NullOrUndefined()) ? 0 : 1);
940 node->TrimInputCount(1);
941 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
942 return Changed(node);
943 }
944
945 if (r.BothInputsAre(Type::Signed32()) ||
946 r.BothInputsAre(Type::Unsigned32())) {
947 return r.ChangeToPureOperator(simplified()->NumberEqual());
948 } else if (r.BothInputsAre(Type::Number())) {
949 return r.ChangeToPureOperator(simplified()->NumberEqual());
950 } else if (r.IsReceiverCompareOperation()) {
951 r.CheckInputsToReceiver();
952 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
953 } else if (r.IsReceiverOrNullOrUndefinedCompareOperation()) {
954 // Check that both inputs are Receiver, Null or Undefined.
955 r.CheckInputsToReceiverOrNullOrUndefined();
956
957 // If one side is known to be a detectable receiver now, we
958 // can simply perform reference equality here, since this
959 // known detectable receiver is going to only match itself.
960 if (r.OneInputIs(Type::DetectableReceiver())) {
961 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
962 }
963
964 // Known that both sides are Receiver, Null or Undefined, the
965 // abstract equality operation can be performed like this:
966 //
967 // if left == undefined || left == null
968 // then ObjectIsUndetectable(right)
969 // else if right == undefined || right == null
970 // then ObjectIsUndetectable(left)
971 // else ReferenceEqual(left, right)
972#define __ gasm.
973 JSGraphAssembler gasm(broker(), jsgraph(), jsgraph()->zone(),
975 gasm.InitializeEffectControl(r.effect(), r.control());
976
977 auto lhs = TNode<Object>::UncheckedCast(r.left());
978 auto rhs = TNode<Object>::UncheckedCast(r.right());
979
980 auto done = __ MakeLabel(MachineRepresentation::kTagged);
981 auto check_undetectable = __ MakeLabel(MachineRepresentation::kTagged);
982
983 __ GotoIf(__ ReferenceEqual(lhs, __ UndefinedConstant()),
984 &check_undetectable, rhs);
985 __ GotoIf(__ ReferenceEqual(lhs, __ NullConstant()), &check_undetectable,
986 rhs);
987 __ GotoIf(__ ReferenceEqual(rhs, __ UndefinedConstant()),
988 &check_undetectable, lhs);
989 __ GotoIf(__ ReferenceEqual(rhs, __ NullConstant()), &check_undetectable,
990 lhs);
991 __ Goto(&done, __ ReferenceEqual(lhs, rhs));
992
993 __ Bind(&check_undetectable);
994 __ Goto(&done,
995 __ ObjectIsUndetectable(check_undetectable.PhiAt<Object>(0)));
996
997 __ Bind(&done);
998 Node* value = done.PhiAt(0);
999 ReplaceWithValue(node, value, gasm.effect(), gasm.control());
1000 return Replace(value);
1001#undef __
1002 } else if (r.IsStringCompareOperation()) {
1003 r.CheckInputsToString();
1004 return r.ChangeToPureOperator(simplified()->StringEqual());
1005 } else if (r.IsSymbolCompareOperation()) {
1006 r.CheckInputsToSymbol();
1007 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1008 }
1009 return NoChange();
1010}
1011
1013 JSBinopReduction r(this, node);
1014 if (r.type().IsSingleton()) {
1015 // Let ConstantFoldingReducer handle this.
1016 return NoChange();
1017 }
1018 if (r.left() == r.right()) {
1019 // x === x is always true if x != NaN
1020 Node* replacement = graph()->NewNode(
1021 simplified()->BooleanNot(),
1022 graph()->NewNode(simplified()->ObjectIsNaN(), r.left()));
1023 DCHECK(NodeProperties::GetType(replacement).Is(r.type()));
1024 ReplaceWithValue(node, replacement);
1025 return Replace(replacement);
1026 }
1027
1028 if (r.BothInputsAre(Type::Unique())) {
1029 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1030 }
1031 if (r.OneInputIs(pointer_comparable_type_)) {
1032 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1033 }
1034 if (r.IsInternalizedStringCompareOperation()) {
1035 r.CheckInputsToInternalizedString();
1036 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1037 }
1038 if (r.BothInputsAre(Type::String())) {
1039 return r.ChangeToPureOperator(simplified()->StringEqual());
1040 }
1041
1043 BigIntOperationHint hint_bigint;
1044 if (r.BothInputsAre(Type::Signed32()) ||
1045 r.BothInputsAre(Type::Unsigned32())) {
1046 return r.ChangeToPureOperator(simplified()->NumberEqual());
1047 } else if (r.GetCompareNumberOperationHint(&hint) &&
1050 // SpeculativeNumberEqual performs implicit conversion of oddballs to
1051 // numbers, so me must not generate it for strict equality with respective
1052 // hint.
1055 return r.ChangeToSpeculativeOperator(
1056 simplified()->SpeculativeNumberEqual(hint), Type::Boolean());
1057 } else if (r.BothInputsAre(Type::Number())) {
1058 return r.ChangeToPureOperator(simplified()->NumberEqual());
1059 } else if (r.GetCompareBigIntOperationHint(&hint_bigint)) {
1060 DCHECK(hint_bigint == BigIntOperationHint::kBigInt ||
1061 hint_bigint == BigIntOperationHint::kBigInt64);
1062 return r.ChangeToSpeculativeOperator(
1063 simplified()->SpeculativeBigIntEqual(hint_bigint), Type::Boolean());
1064 } else if (r.IsReceiverCompareOperation()) {
1065 // For strict equality, it's enough to know that one input is a Receiver,
1066 // as a strict equality comparison with a Receiver can only yield true if
1067 // both sides refer to the same Receiver.
1068 r.CheckLeftInputToReceiver();
1069 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1070 } else if (r.IsReceiverOrNullOrUndefinedCompareOperation()) {
1071 // For strict equality, it's enough to know that one input is a Receiver,
1072 // Null or Undefined, as a strict equality comparison with a Receiver,
1073 // Null or Undefined can only yield true if both sides refer to the same
1074 // instance.
1075 r.CheckLeftInputToReceiverOrNullOrUndefined();
1076 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1077 } else if (r.IsStringCompareOperation()) {
1078 r.CheckInputsToString();
1079 return r.ChangeToPureOperator(simplified()->StringEqual());
1080 } else if (r.IsSymbolCompareOperation()) {
1081 // For strict equality, it's enough to know that one input is a Symbol,
1082 // as a strict equality comparison with a Symbol can only yield true if
1083 // both sides refer to the same Symbol.
1084 r.CheckLeftInputToSymbol();
1085 return r.ChangeToPureOperator(simplified()->ReferenceEqual());
1086 }
1087 return NoChange();
1088}
1089
1091 Node* const input = NodeProperties::GetValueInput(node, 0);
1092 Type const input_type = NodeProperties::GetType(input);
1093 if (input_type.Is(Type::Name())) {
1094 // JSToName(x:name) => x
1095 ReplaceWithValue(node, input);
1096 return Replace(input);
1097 }
1098 return NoChange();
1099}
1100
1102 Node* input = NodeProperties::GetValueInput(node, 0);
1103 Type input_type = NodeProperties::GetType(input);
1104 if (input_type.Is(type_cache_->kIntegerOrMinusZero)) {
1105 if (input_type.IsNone() || input_type.Max() <= 0.0) {
1106 input = jsgraph()->ZeroConstant();
1107 } else if (input_type.Min() >= kMaxSafeInteger) {
1109 } else {
1110 if (input_type.Min() <= 0.0) {
1111 input = graph()->NewNode(simplified()->NumberMax(),
1112 jsgraph()->ZeroConstant(), input);
1113 }
1114 if (input_type.Max() > kMaxSafeInteger) {
1115 input =
1116 graph()->NewNode(simplified()->NumberMin(),
1117 jsgraph()->ConstantNoHole(kMaxSafeInteger), input);
1118 }
1119 }
1120 ReplaceWithValue(node, input);
1121 return Replace(input);
1122 }
1123 return NoChange();
1124}
1125
1127 // Try constant-folding of JSToNumber with constant inputs.
1128 Type input_type = NodeProperties::GetType(input);
1129
1130 if (input_type.Is(Type::String())) {
1131 HeapObjectMatcher m(input);
1132 if (m.HasResolvedValue() && m.Ref(broker()).IsString()) {
1133 StringRef input_value = m.Ref(broker()).AsString();
1134 std::optional<double> number = input_value.ToNumber(broker());
1135 if (!number.has_value()) return NoChange();
1136 return Replace(jsgraph()->ConstantNoHole(number.value()));
1137 }
1138 }
1139 if (input_type.IsHeapConstant()) {
1140 HeapObjectRef input_value = input_type.AsHeapConstant()->Ref();
1141 double value;
1142 if (input_value.OddballToNumber(broker()).To(&value)) {
1143 return Replace(jsgraph()->ConstantNoHole(value));
1144 }
1145 }
1146 if (input_type.Is(Type::Number())) {
1147 // JSToNumber(x:number) => x
1148 return Changed(input);
1149 }
1150 if (input_type.Is(Type::Undefined())) {
1151 // JSToNumber(undefined) => #NaN
1152 return Replace(jsgraph()->NaNConstant());
1153 }
1154 if (input_type.Is(Type::Null())) {
1155 // JSToNumber(null) => #0
1156 return Replace(jsgraph()->ZeroConstant());
1157 }
1158 return NoChange();
1159}
1160
1162 // Try to reduce the input first.
1163 Node* const input = node->InputAt(0);
1164 Reduction reduction = ReduceJSToNumberInput(input);
1165 if (reduction.Changed()) {
1166 ReplaceWithValue(node, reduction.replacement());
1167 return reduction;
1168 }
1169 Type const input_type = NodeProperties::GetType(input);
1170 if (input_type.Is(Type::PlainPrimitive())) {
1171 RelaxEffectsAndControls(node);
1172 node->TrimInputCount(1);
1173 // For a PlainPrimitive, ToNumeric is the same as ToNumber.
1174 Type node_type = NodeProperties::GetType(node);
1176 node, Type::Intersect(node_type, Type::Number(), graph()->zone()));
1177 NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1178 return Changed(node);
1179 }
1180 return NoChange();
1181}
1182
1184 // TODO(panq): Reduce constant inputs.
1185 Node* const input = node->InputAt(0);
1186 Type const input_type = NodeProperties::GetType(input);
1187 if (input_type.Is(Type::BigInt())) {
1188 ReplaceWithValue(node, input);
1189 return Changed(input);
1190 }
1191 return NoChange();
1192}
1193
1195 // TODO(panq): Reduce constant inputs.
1196 Node* const input = node->InputAt(0);
1197 Type const input_type = NodeProperties::GetType(input);
1198 if (input_type.Is(Type::BigInt())) {
1199 ReplaceWithValue(node, input);
1200 return Changed(input);
1201 } else if (input_type.Is(Type::Signed32OrMinusZero()) ||
1202 input_type.Is(Type::Unsigned32OrMinusZero())) {
1203 RelaxEffectsAndControls(node);
1204 node->TrimInputCount(1);
1205 Type node_type = NodeProperties::GetType(node);
1207 node,
1208 Type::Intersect(node_type, Type::SignedBigInt64(), graph()->zone()));
1210 simplified()->Integral32OrMinusZeroToBigInt());
1211 return Changed(node);
1212 }
1213 return NoChange();
1214}
1215
1217 Node* const input = NodeProperties::GetValueInput(node, 0);
1218 Type const input_type = NodeProperties::GetType(input);
1219 if (input_type.Is(Type::NonBigIntPrimitive())) {
1220 // ToNumeric(x:primitive\bigint) => ToNumber(x)
1222 Type node_type = NodeProperties::GetType(node);
1224 node, Type::Intersect(node_type, Type::Number(), graph()->zone()));
1225 return Changed(node).FollowedBy(ReduceJSToNumber(node));
1226 }
1227 return NoChange();
1228}
1229
1231 if (input->opcode() == IrOpcode::kJSToString) {
1232 // Recursively try to reduce the input first.
1234 if (result.Changed()) return result;
1235 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
1236 }
1237 Type input_type = NodeProperties::GetType(input);
1238 if (input_type.Is(Type::String())) {
1239 return Changed(input); // JSToString(x:string) => x
1240 }
1241 if (input_type.Is(Type::Boolean())) {
1242 return Replace(graph()->NewNode(
1243 common()->Select(MachineRepresentation::kTagged), input,
1244 jsgraph()->HeapConstantNoHole(factory()->true_string()),
1245 jsgraph()->HeapConstantNoHole(factory()->false_string())));
1246 }
1247 if (input_type.Is(Type::Undefined())) {
1248 return Replace(
1249 jsgraph()->HeapConstantNoHole(factory()->undefined_string()));
1250 }
1251 if (input_type.Is(Type::Null())) {
1252 return Replace(jsgraph()->HeapConstantNoHole(factory()->null_string()));
1253 }
1254 if (input_type.Is(Type::NaN())) {
1255 return Replace(jsgraph()->HeapConstantNoHole(factory()->NaN_string()));
1256 }
1257 if (input_type.Is(Type::Number())) {
1258 return Replace(graph()->NewNode(simplified()->NumberToString(), input));
1259 }
1260 return NoChange();
1261}
1262
1264 DCHECK_EQ(IrOpcode::kJSToString, node->opcode());
1265 // Try to reduce the input first.
1266 Node* const input = node->InputAt(0);
1267 Reduction reduction = ReduceJSToStringInput(input);
1268 if (reduction.Changed()) {
1269 ReplaceWithValue(node, reduction.replacement());
1270 return reduction;
1271 }
1272 return NoChange();
1273}
1274
1276 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1278 Type receiver_type = NodeProperties::GetType(receiver);
1279 Node* context = NodeProperties::GetContextInput(node);
1280 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1281 Node* effect = NodeProperties::GetEffectInput(node);
1282 Node* control = NodeProperties::GetControlInput(node);
1283 if (receiver_type.Is(Type::Receiver())) {
1284 ReplaceWithValue(node, receiver, effect, control);
1285 return Replace(receiver);
1286 }
1287
1288 // Check whether {receiver} is a spec object.
1289 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1290 Node* branch =
1291 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1292
1293 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1294 Node* etrue = effect;
1295 Node* rtrue = receiver;
1296
1297 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1298 Node* efalse = effect;
1299 Node* rfalse;
1300 {
1301 // Convert {receiver} using the ToObjectStub.
1302 Callable callable = Builtins::CallableFor(isolate(), Builtin::kToObject);
1303 auto call_descriptor = Linkage::GetStubCallDescriptor(
1304 graph()->zone(), callable.descriptor(),
1306 CallDescriptor::kNeedsFrameState, node->op()->properties());
1307 Node* call = rfalse = efalse = if_false =
1308 graph()->NewNode(common()->Call(call_descriptor),
1309 jsgraph()->HeapConstantNoHole(callable.code()),
1310 receiver, context, frame_state, efalse, if_false);
1311
1312 // We preserve the type of {node}. This is generally useful (to enable
1313 // type-based optimizations), and is also required in order to help
1314 // verification of TypeGuards.
1316 }
1317
1318 // Update potential {IfException} uses of {node} to point to the above
1319 // ToObject stub call node instead. Note that the stub can only throw on
1320 // receivers that can be null or undefined.
1321 Node* on_exception = nullptr;
1322 if (receiver_type.Maybe(Type::NullOrUndefined()) &&
1323 NodeProperties::IsExceptionalCall(node, &on_exception)) {
1324 NodeProperties::ReplaceControlInput(on_exception, if_false);
1325 NodeProperties::ReplaceEffectInput(on_exception, efalse);
1326 if_false = graph()->NewNode(common()->IfSuccess(), if_false);
1327 Revisit(on_exception);
1328 }
1329
1330 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1331 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1332
1333 // Morph the {node} into an appropriate Phi.
1334 ReplaceWithValue(node, node, effect, control);
1335 node->ReplaceInput(0, rtrue);
1336 node->ReplaceInput(1, rfalse);
1337 node->ReplaceInput(2, control);
1338 node->TrimInputCount(3);
1341 return Changed(node);
1342}
1343
1345 JSLoadNamedNode n(node);
1346 Node* receiver = n.object();
1347 Type receiver_type = NodeProperties::GetType(receiver);
1348 NameRef name = NamedAccessOf(node->op()).name();
1349 NameRef length_str = broker()->length_string();
1350 // Optimize "length" property of strings.
1351 if (name.equals(length_str) && receiver_type.Is(Type::String())) {
1352 Node* value = graph()->NewNode(simplified()->StringLength(), receiver);
1353 ReplaceWithValue(node, value);
1354 return Replace(value);
1355 }
1356 return NoChange();
1357}
1358
1360 DCHECK_EQ(IrOpcode::kJSHasInPrototypeChain, node->opcode());
1361 Node* value = NodeProperties::GetValueInput(node, 0);
1362 Type value_type = NodeProperties::GetType(value);
1363 Node* prototype = NodeProperties::GetValueInput(node, 1);
1364 Node* context = NodeProperties::GetContextInput(node);
1365 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1366 Node* effect = NodeProperties::GetEffectInput(node);
1367 Node* control = NodeProperties::GetControlInput(node);
1368
1369 // If {value} cannot be a receiver, then it cannot have {prototype} in
1370 // it's prototype chain (all Primitive values have a null prototype).
1371 if (value_type.Is(Type::Primitive())) {
1372 value = jsgraph()->FalseConstant();
1373 ReplaceWithValue(node, value, effect, control);
1374 return Replace(value);
1375 }
1376
1377 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
1378 Node* branch0 =
1379 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1380
1381 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1382 Node* etrue0 = effect;
1383 Node* vtrue0 = jsgraph()->FalseConstant();
1384
1385 control = graph()->NewNode(common()->IfFalse(), branch0);
1386
1387 // Loop through the {value}s prototype chain looking for the {prototype}.
1388 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1389 Node* eloop = effect =
1390 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1391 Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop);
1392 MergeControlToEnd(graph(), common(), terminate);
1393 Node* vloop = value = graph()->NewNode(
1394 common()->Phi(MachineRepresentation::kTagged, 2), value, value, loop);
1395 NodeProperties::SetType(vloop, Type::NonInternal());
1396
1397 // Load the {value} map and instance type.
1398 Node* value_map = effect = graph()->NewNode(
1399 simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
1400 Node* value_instance_type = effect = graph()->NewNode(
1401 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
1402 effect, control);
1403
1404 // Check if the {value} is a special receiver, because for special
1405 // receivers, i.e. proxies or API values that need access checks,
1406 // we have to use the %HasInPrototypeChain runtime function instead.
1407 Node* check1 = graph()->NewNode(
1408 simplified()->NumberLessThanOrEqual(), value_instance_type,
1409 jsgraph()->ConstantNoHole(LAST_SPECIAL_RECEIVER_TYPE));
1410 Node* branch1 =
1411 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1412
1413 control = graph()->NewNode(common()->IfFalse(), branch1);
1414
1415 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1416 Node* etrue1 = effect;
1417 Node* vtrue1;
1418
1419 // Check if the {value} is not a receiver at all.
1420 Node* check10 =
1421 graph()->NewNode(simplified()->NumberLessThan(), value_instance_type,
1422 jsgraph()->ConstantNoHole(FIRST_JS_RECEIVER_TYPE));
1423 Node* branch10 =
1424 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1425
1426 // A primitive value cannot match the {prototype} we're looking for.
1427 if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1428 vtrue1 = jsgraph()->FalseConstant();
1429
1430 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
1431 Node* efalse1 = etrue1;
1432 Node* vfalse1;
1433 {
1434 // Slow path, need to call the %HasInPrototypeChain runtime function.
1435 vfalse1 = efalse1 = if_false1 = graph()->NewNode(
1436 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), value,
1437 prototype, context, frame_state, efalse1, if_false1);
1438
1439 // Replace any potential {IfException} uses of {node} to catch
1440 // exceptions from this %HasInPrototypeChain runtime call instead.
1441 Node* on_exception = nullptr;
1442 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
1443 NodeProperties::ReplaceControlInput(on_exception, vfalse1);
1444 NodeProperties::ReplaceEffectInput(on_exception, efalse1);
1445 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1446 Revisit(on_exception);
1447 }
1448 }
1449
1450 // Load the {value} prototype.
1451 Node* value_prototype = effect = graph()->NewNode(
1452 simplified()->LoadField(AccessBuilder::ForMapPrototype()), value_map,
1453 effect, control);
1454
1455 // Check if we reached the end of {value}s prototype chain.
1456 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1457 value_prototype, jsgraph()->NullConstant());
1458 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1459
1460 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1461 Node* etrue2 = effect;
1462 Node* vtrue2 = jsgraph()->FalseConstant();
1463
1464 control = graph()->NewNode(common()->IfFalse(), branch2);
1465
1466 // Check if we reached the {prototype}.
1467 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1468 value_prototype, prototype);
1469 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1470
1471 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1472 Node* etrue3 = effect;
1473 Node* vtrue3 = jsgraph()->TrueConstant();
1474
1475 control = graph()->NewNode(common()->IfFalse(), branch3);
1476
1477 // Close the loop.
1478 vloop->ReplaceInput(1, value_prototype);
1479 eloop->ReplaceInput(1, effect);
1480 loop->ReplaceInput(1, control);
1481
1482 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1483 if_true3, if_false1);
1484 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
1485 etrue3, efalse1, control);
1486
1487 // Morph the {node} into an appropriate Phi.
1488 ReplaceWithValue(node, node, effect, control);
1489 node->ReplaceInput(0, vtrue0);
1490 node->ReplaceInput(1, vtrue1);
1491 node->ReplaceInput(2, vtrue2);
1492 node->ReplaceInput(3, vtrue3);
1493 node->ReplaceInput(4, vfalse1);
1494 node->ReplaceInput(5, control);
1495 node->TrimInputCount(6);
1498 return Changed(node);
1499}
1500
1502 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1503 Node* constructor = NodeProperties::GetValueInput(node, 0);
1504 Type constructor_type = NodeProperties::GetType(constructor);
1505 Node* object = NodeProperties::GetValueInput(node, 1);
1506 Type object_type = NodeProperties::GetType(object);
1507
1508 // Check if the {constructor} cannot be callable.
1509 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1.
1510 if (!constructor_type.Maybe(Type::Callable())) {
1511 Node* value = jsgraph()->FalseConstant();
1512 ReplaceWithValue(node, value);
1513 return Replace(value);
1514 }
1515
1516 // If the {constructor} cannot be a JSBoundFunction and then {object}
1517 // cannot be a JSReceiver, then this can be constant-folded to false.
1518 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3.
1519 if (!object_type.Maybe(Type::Receiver()) &&
1520 !constructor_type.Maybe(Type::BoundFunction())) {
1521 Node* value = jsgraph()->FalseConstant();
1522 ReplaceWithValue(node, value);
1523 return Replace(value);
1524 }
1525
1526 return NoChange();
1527}
1528
1530 DCHECK_EQ(IrOpcode::kJSHasContextExtension, node->opcode());
1531 size_t depth = OpParameter<size_t>(node->op());
1532 Node* effect = NodeProperties::GetEffectInput(node);
1533 TNode<Context> context =
1535 Node* control = graph()->start();
1536
1539 gasm.InitializeEffectControl(effect, control);
1540
1541 for (size_t i = 0; i < depth; ++i) {
1542#if DEBUG
1543 // Const tracking let data is stored in the extension slot of a
1544 // ScriptContext - however, it's unrelated to the sloppy eval variable
1545 // extension. We should never iterate through a ScriptContext here.
1546
1547 TNode<ScopeInfo> scope_info = gasm.LoadField<ScopeInfo>(
1549 TNode<Word32T> scope_info_flags = gasm.EnterMachineGraph<Word32T>(
1552 TNode<Word32T> scope_type = gasm.Word32And(
1553 scope_info_flags, gasm.Uint32Constant(ScopeInfo::ScopeTypeBits::kMask));
1554 TNode<Word32T> is_script_scope = gasm.Word32Equal(
1555 scope_type, gasm.Uint32Constant(ScopeType::SCRIPT_SCOPE));
1556 TNode<Word32T> is_not_script_scope =
1557 gasm.Word32Equal(is_script_scope, gasm.Uint32Constant(0));
1558 gasm.Assert(is_not_script_scope, "we should no see a ScriptContext here",
1559 __FILE__, __LINE__);
1560#endif
1561
1562 context = gasm.LoadField<Context>(
1564 context);
1565 }
1566 TNode<ScopeInfo> scope_info = gasm.LoadField<ScopeInfo>(
1568 TNode<Word32T> scope_info_flags = gasm.EnterMachineGraph<Word32T>(
1571 TNode<Word32T> flags_masked = gasm.Word32And(
1572 scope_info_flags,
1573 gasm.Uint32Constant(ScopeInfo::HasContextExtensionSlotBit::kMask));
1574 TNode<Word32T> no_extension =
1575 gasm.Word32Equal(flags_masked, gasm.Uint32Constant(0));
1576 TNode<Word32T> has_extension =
1577 gasm.Word32Equal(no_extension, gasm.Uint32Constant(0));
1578 TNode<Boolean> has_extension_boolean = gasm.ExitMachineGraph<Boolean>(
1579 has_extension, MachineRepresentation::kBit, Type::Boolean());
1580
1581 ReplaceWithValue(node, has_extension_boolean, gasm.effect(), gasm.control());
1582 return Changed(node);
1583}
1584
1586 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1587 ContextAccess const& access = ContextAccessOf(node->op());
1588 Node* effect = NodeProperties::GetEffectInput(node);
1589 Node* context = NodeProperties::GetContextInput(node);
1590 Node* control = graph()->start();
1591 for (size_t i = 0; i < access.depth(); ++i) {
1592 context = effect = graph()->NewNode(
1593 simplified()->LoadField(
1595 context, effect, control);
1596 }
1597 node->ReplaceInput(0, context);
1598 node->ReplaceInput(1, effect);
1599 node->AppendInput(jsgraph()->zone(), control);
1601 node,
1602 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1603 return Changed(node);
1604}
1605
1607 DCHECK_EQ(IrOpcode::kJSLoadScriptContext, node->opcode());
1608 ContextAccess const& access = ContextAccessOf(node->op());
1609 Node* effect = NodeProperties::GetEffectInput(node);
1610 Node* control = NodeProperties::GetControlInput(node);
1611 JSGraphAssembler gasm(broker(), jsgraph(), jsgraph()->zone(),
1613 gasm.InitializeEffectControl(effect, control);
1614
1615 TNode<Context> context =
1617 for (size_t i = 0; i < access.depth(); ++i) {
1618 context = gasm.LoadField<Context>(
1620 context);
1621 }
1622
1623 TNode<Object> value = gasm.LoadField<Object>(
1624 AccessBuilder::ForContextSlot(access.index()), context);
1626 gasm.SelectIf<Object>(gasm.ObjectIsSmi(value))
1627 .Then([&] { return value; })
1628 .Else([&] {
1629 TNode<Map> value_map =
1631 return gasm.SelectIf<Object>(gasm.IsHeapNumberMap(value_map))
1632 .Then([&] {
1633 size_t side_data_index =
1634 access.index() - Context::MIN_CONTEXT_EXTENDED_SLOTS;
1635 TNode<FixedArray> side_data = gasm.LoadField<FixedArray>(
1638 context);
1639 TNode<Object> data = gasm.LoadField<Object>(
1640 AccessBuilder::ForFixedArraySlot(side_data_index),
1641 side_data);
1642 TNode<Object> property =
1643 gasm.SelectIf<Object>(gasm.ObjectIsSmi(data))
1644 .Then([&] { return data; })
1645 .Else([&] {
1646 return gasm.LoadField<Object>(
1649 })
1650 .Value();
1651 if (v8_flags.script_context_mutable_heap_int32) {
1652 return gasm
1654 property,
1657 .Then([&] {
1658 Node* number = gasm.LoadField(
1660 // Allocate a new HeapNumber.
1662 gasm.effect(), gasm.control());
1663 a.Allocate(sizeof(HeapNumber), AllocationType::kYoung,
1664 Type::OtherInternal());
1665 a.Store(AccessBuilder::ForMap(),
1666 broker()->heap_number_map());
1667 a.Store(AccessBuilder::ForHeapNumberValue(), number);
1668 Node* new_heap_number = a.Finish();
1669 gasm.UpdateEffectControlWith(new_heap_number);
1670 return TNode<Object>::UncheckedCast(new_heap_number);
1671 })
1672 .Else([&] {
1673 return gasm
1675 property,
1678 kMutableHeapNumber))))
1679 .Then([&] {
1680 Node* number = gasm.LoadHeapNumberValue(value);
1681 // Allocate a new HeapNumber.
1683 gasm.effect(),
1684 gasm.control());
1685 a.Allocate(sizeof(HeapNumber),
1687 Type::OtherInternal());
1688 a.Store(AccessBuilder::ForMap(),
1689 broker()->heap_number_map());
1691 number);
1692 Node* new_heap_number = a.Finish();
1693 gasm.UpdateEffectControlWith(new_heap_number);
1695 new_heap_number);
1696 })
1697 .Else([&] { return value; })
1698 .Value();
1699 })
1700 .Value();
1701 } else {
1702 return gasm
1704 property,
1707 .Then([&] {
1708 Node* number = gasm.LoadHeapNumberValue(value);
1709 // Allocate a new HeapNumber.
1711 gasm.effect(), gasm.control());
1712 a.Allocate(sizeof(HeapNumber), AllocationType::kYoung,
1713 Type::OtherInternal());
1714 a.Store(AccessBuilder::ForMap(),
1715 broker()->heap_number_map());
1716 a.Store(AccessBuilder::ForHeapNumberValue(), number);
1717 Node* new_heap_number = a.Finish();
1718 gasm.UpdateEffectControlWith(new_heap_number);
1719 return TNode<Object>::UncheckedCast(new_heap_number);
1720 })
1721 .Else([&] { return value; })
1722 .Value();
1723 }
1724 })
1725 .Else([&] { return value; })
1726 .ExpectFalse()
1727 .Value();
1728 })
1729 .Value();
1730
1731 ReplaceWithValue(node, result, gasm.effect(), gasm.control());
1732 return Changed(node);
1733}
1734
1736 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1737 ContextAccess const& access = ContextAccessOf(node->op());
1738 Node* effect = NodeProperties::GetEffectInput(node);
1739 Node* context = NodeProperties::GetContextInput(node);
1740 Node* control = graph()->start();
1741 Node* value = NodeProperties::GetValueInput(node, 0);
1742 for (size_t i = 0; i < access.depth(); ++i) {
1743 context = effect = graph()->NewNode(
1744 simplified()->LoadField(
1746 context, effect, control);
1747 }
1748 node->ReplaceInput(0, context);
1749 node->ReplaceInput(1, value);
1750 node->ReplaceInput(2, effect);
1752 node,
1753 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1754 return Changed(node);
1755}
1756
1758 DCHECK_EQ(IrOpcode::kJSStoreScriptContext, node->opcode());
1759 ContextAccess const& access = ContextAccessOf(node->op());
1760 Node* effect = NodeProperties::GetEffectInput(node);
1761 Node* control = NodeProperties::GetControlInput(node);
1762 JSGraphAssembler gasm(broker(), jsgraph(), jsgraph()->zone(),
1764 gasm.InitializeEffectControl(effect, control);
1765
1766 TNode<Context> context =
1768 for (size_t i = 0; i < access.depth(); ++i) {
1769 context = gasm.LoadField<Context>(
1771 context);
1772 }
1773
1774 TNode<Object> old_value = gasm.LoadField<Object>(
1775 AccessBuilder::ForContextSlot(access.index()), context);
1776 TNode<Object> new_value =
1778
1779 gasm.IfNot(gasm.ReferenceEqual(old_value, new_value)).Then([&] {
1780 size_t side_data_index =
1781 access.index() - Context::MIN_CONTEXT_EXTENDED_SLOTS;
1782 TNode<FixedArray> side_data = gasm.LoadField<FixedArray>(
1785 context);
1786 TNode<Object> data = gasm.LoadField<Object>(
1787 AccessBuilder::ForFixedArraySlot(side_data_index), side_data);
1788
1789 TNode<Boolean> is_other = gasm.ReferenceEqual(
1792 gasm.If(is_other)
1793 .Then([&] {
1794 gasm.StoreField(AccessBuilder::ForContextSlot(access.index()),
1795 context, new_value);
1796 })
1797 .Else([&] {
1798 gasm.CheckIf(gasm.BooleanNot(gasm.IsUndefined(data)),
1799 DeoptimizeReason::kWrongValue);
1800 TNode<Object> property =
1801 gasm.SelectIf<Object>(gasm.ObjectIsSmi(data))
1802 .Then([&] { return data; })
1803 .Else([&] {
1804 return gasm.LoadField<Object>(
1807 })
1808 .Value();
1809 TNode<Boolean> is_const = gasm.ReferenceEqual(
1812 gasm.CheckIf(gasm.BooleanNot(is_const),
1813 DeoptimizeReason::kWrongValue);
1814 if (v8_flags.script_context_mutable_heap_number) {
1815 TNode<Boolean> is_smi_marker = gasm.ReferenceEqual(
1818 gasm.If(is_smi_marker)
1819 .Then([&] {
1820 Node* smi_value = gasm.CheckSmi(new_value);
1821 gasm.StoreField(
1822 AccessBuilder::ForContextSlotSmi(access.index()), context,
1823 smi_value);
1824 })
1825 .Else([&] {
1826 if (v8_flags.script_context_mutable_heap_int32) {
1827 TNode<Boolean> is_mutable_int32 = gasm.ReferenceEqual(
1830 gasm.If(is_mutable_int32)
1831 .Then([&] {
1832 // It is a mutable int32 number.
1833 Node* number_value =
1834 gasm.CheckNumberFitsInt32(new_value);
1836 old_value, number_value);
1837 })
1838 .Else([&] {
1839 // It must be a mutable heap number in this case.
1840 Node* number_value = gasm.CheckNumber(new_value);
1842 old_value, number_value);
1843 });
1844
1845 } else {
1846 // It must be a mutable heap number in this case.
1847 Node* number_value = gasm.CheckNumber(new_value);
1849 old_value, number_value);
1850 }
1851 });
1852
1853 } else {
1854 gasm.StoreField(AccessBuilder::ForContextSlot(access.index()),
1855 context, new_value);
1856 }
1857 })
1858 .ExpectTrue();
1859 });
1860 ReplaceWithValue(node, gasm.effect(), gasm.effect(), gasm.control());
1861 return Changed(node);
1862}
1863
1865 DCHECK(node->opcode() == IrOpcode::kJSLoadModule ||
1866 node->opcode() == IrOpcode::kJSStoreModule);
1867 Node* effect = NodeProperties::GetEffectInput(node);
1868 Node* control = NodeProperties::GetControlInput(node);
1869
1870 int32_t cell_index = OpParameter<int32_t>(node->op());
1871 Node* module = NodeProperties::GetValueInput(node, 0);
1872 Type module_type = NodeProperties::GetType(module);
1873
1874 if (module_type.IsHeapConstant()) {
1875 SourceTextModuleRef module_constant =
1876 module_type.AsHeapConstant()->Ref().AsSourceTextModule();
1877 OptionalCellRef cell_constant =
1878 module_constant.GetCell(broker(), cell_index);
1879 if (cell_constant.has_value())
1880 return jsgraph()->ConstantNoHole(*cell_constant, broker());
1881 }
1882
1883 FieldAccess field_access;
1884 int index;
1888 index = cell_index - 1;
1889 } else {
1893 index = -cell_index - 1;
1894 }
1895 Node* array = effect = graph()->NewNode(simplified()->LoadField(field_access),
1896 module, effect, control);
1897 return graph()->NewNode(
1898 simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1899 effect, control);
1900}
1901
1903 DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1904 Node* effect = NodeProperties::GetEffectInput(node);
1905 Node* control = NodeProperties::GetControlInput(node);
1906
1907 Node* cell = BuildGetModuleCell(node);
1908 if (cell->op()->EffectOutputCount() > 0) effect = cell;
1909 Node* value = effect =
1911 cell, effect, control);
1912
1913 ReplaceWithValue(node, value, effect, control);
1914 return Changed(value);
1915}
1916
1918 DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1919 Node* effect = NodeProperties::GetEffectInput(node);
1920 Node* control = NodeProperties::GetControlInput(node);
1921 Node* value = NodeProperties::GetValueInput(node, 1);
1923 OpParameter<int32_t>(node->op())),
1925
1926 Node* cell = BuildGetModuleCell(node);
1927 if (cell->op()->EffectOutputCount() > 0) effect = cell;
1928 effect =
1930 cell, value, effect, control);
1931
1932 ReplaceWithValue(node, effect, effect, control);
1933 return Changed(value);
1934}
1935
1936namespace {
1937
1938void ReduceBuiltin(JSGraph* jsgraph, Node* node, Builtin builtin, int arity,
1939 CallDescriptor::Flags flags) {
1940 // Patch {node} to a direct CEntry call.
1941 // ----------- A r g u m e n t s -----------
1942 // -- 0: CEntry
1943 // --- Stack args ---
1944 // -- 1: new_target
1945 // -- 2: target
1946 // -- 3: argc, including the receiver and implicit args (Smi)
1947 // -- 4: padding
1948 // -- 5: receiver
1949 // -- [6, 6 + n[: the n actual arguments passed to the builtin
1950 // --- Register args ---
1951 // -- 6 + n: the C entry point
1952 // -- 6 + n + 1: argc (Int32)
1953 // -----------------------------------
1954
1955 // These SBXCHECKs are a defense-in-depth measure to ensure that we always
1956 // generate valid calls here (with matching signatures).
1957 SBXCHECK(Builtins::IsCpp(builtin));
1960
1961 // The logic contained here is mirrored in Builtins::Generate_Adaptor.
1962 // Keep these in sync.
1963
1964 Node* target = node->InputAt(JSCallOrConstructNode::TargetIndex());
1965
1966 // Unify representations between construct and call nodes. For construct
1967 // nodes, the receiver is undefined. For call nodes, the new_target is
1968 // undefined.
1970 Zone* zone = jsgraph->zone();
1971 if (node->opcode() == IrOpcode::kJSConstruct) {
1972 static_assert(JSCallNode::ReceiverIndex() ==
1973 JSConstructNode::NewTargetIndex());
1974 new_target = JSConstructNode{node}.new_target();
1975 node->ReplaceInput(JSConstructNode::NewTargetIndex(),
1976 jsgraph->UndefinedConstant());
1977 node->RemoveInput(JSConstructNode{node}.FeedbackVectorIndex());
1978 } else {
1979 new_target = jsgraph->UndefinedConstant();
1980 node->RemoveInput(JSCallNode{node}.FeedbackVectorIndex());
1981 }
1982
1983 // CPP builtins are implemented in C++, and we can inline it.
1984 // CPP builtins create a builtin exit frame.
1985 const bool has_builtin_exit_frame = true;
1986
1987 Node* stub =
1988 jsgraph->CEntryStubConstant(1, ArgvMode::kStack, has_builtin_exit_frame);
1989 node->ReplaceInput(0, stub);
1990
1991 const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1992 Node* argc_node = jsgraph->ConstantNoHole(argc);
1993
1994 static const int kStub = 1;
1995 static_assert(BuiltinArguments::kNewTargetIndex == 0);
1996 static_assert(BuiltinArguments::kTargetIndex == 1);
1997 static_assert(BuiltinArguments::kArgcIndex == 2);
1998 static_assert(BuiltinArguments::kPaddingIndex == 3);
1999 node->InsertInput(zone, 1, new_target);
2000 node->InsertInput(zone, 2, target);
2001 node->InsertInput(zone, 3, argc_node);
2002 node->InsertInput(zone, 4, jsgraph->PaddingConstant());
2003 int cursor = arity + kStub + BuiltinArguments::kNumExtraArgsWithReceiver;
2004
2005 Address entry = Builtins::CppEntryOf(builtin);
2006 ExternalReference entry_ref = ExternalReference::Create(entry);
2007 Node* entry_node = jsgraph->ExternalConstant(entry_ref);
2008
2009 node->InsertInput(zone, cursor++, entry_node);
2010 node->InsertInput(zone, cursor++, argc_node);
2011
2012 static const int kReturnCount = 1;
2013 const char* debug_name = Builtins::name(builtin);
2014 Operator::Properties properties = node->op()->properties();
2015 auto call_descriptor = Linkage::GetCEntryStubCallDescriptor(
2016 zone, kReturnCount, argc, debug_name, properties, flags,
2018
2019 NodeProperties::ChangeOp(node, jsgraph->common()->Call(call_descriptor));
2020}
2021} // namespace
2022
2024 DCHECK_EQ(IrOpcode::kJSConstructForwardVarargs, node->opcode());
2027 DCHECK_LE(2u, p.arity());
2028 int const arity = static_cast<int>(p.arity() - 2);
2029 int const start_index = static_cast<int>(p.start_index());
2030 Node* target = NodeProperties::GetValueInput(node, 0);
2031 Type target_type = NodeProperties::GetType(target);
2032
2033 // Check if {target} is a JSFunction.
2034 if (target_type.IsHeapConstant() &&
2035 target_type.AsHeapConstant()->Ref().IsJSFunction()) {
2036 // Only optimize [[Construct]] here if {function} is a Constructor.
2037 JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
2038 if (!function.map(broker()).is_constructor()) return NoChange();
2039 // Patch {node} to an indirect call via ConstructFunctionForwardVarargs.
2041 node->InsertInput(graph()->zone(), 0,
2042 jsgraph()->HeapConstantNoHole(callable.code()));
2043 node->InsertInput(graph()->zone(), 3,
2044 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2045 node->InsertInput(graph()->zone(), 4,
2046 jsgraph()->ConstantNoHole(start_index));
2047 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
2050 graph()->zone(), callable.descriptor(), arity + 1,
2052 return Changed(node);
2053 }
2054
2055 return NoChange();
2056}
2057
2059 JSConstructNode n(node);
2060 ConstructParameters const& p = n.Parameters();
2061 int const arity = p.arity_without_implicit_args();
2062 Node* target = n.target();
2063 Type target_type = NodeProperties::GetType(target);
2064
2065 // Check if {target} is a known JSFunction.
2066 if (target_type.IsHeapConstant() &&
2067 target_type.AsHeapConstant()->Ref().IsJSFunction()) {
2068 JSFunctionRef function = target_type.AsHeapConstant()->Ref().AsJSFunction();
2069
2070 // Only optimize [[Construct]] here if {function} is a Constructor.
2071 if (!function.map(broker()).is_constructor()) return NoChange();
2072
2073 // Patch {node} to an indirect call via the {function}s construct stub.
2075 isolate(), function.shared(broker()).construct_as_builtin()
2076 ? Builtin::kJSBuiltinsConstructStub
2077 : Builtin::kJSConstructStubGeneric);
2078 static_assert(JSConstructNode::TargetIndex() == 0);
2079 static_assert(JSConstructNode::NewTargetIndex() == 1);
2080 node->RemoveInput(n.FeedbackVectorIndex());
2081 node->InsertInput(graph()->zone(), 0,
2082 jsgraph()->HeapConstantNoHole(callable.code()));
2083 node->InsertInput(graph()->zone(), 3,
2084 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2085 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2088 graph()->zone(), callable.descriptor(), 1 + arity,
2090 return Changed(node);
2091 }
2092
2093 return NoChange();
2094}
2095
2097 DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
2099 DCHECK_LE(2u, p.arity());
2100 int const arity = static_cast<int>(p.arity() - 2);
2101 int const start_index = static_cast<int>(p.start_index());
2102 Node* target = NodeProperties::GetValueInput(node, 0);
2103 Type target_type = NodeProperties::GetType(target);
2104
2105 // Check if {target} is a directly callable JSFunction.
2106 if (target_type.Is(Type::CallableFunction())) {
2107 // Compute flags for the call.
2109 // Patch {node} to an indirect call via CallFunctionForwardVarargs.
2111 node->InsertInput(graph()->zone(), 0,
2112 jsgraph()->HeapConstantNoHole(callable.code()));
2113 node->InsertInput(graph()->zone(), 2,
2114 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2115 node->InsertInput(graph()->zone(), 3,
2116 jsgraph()->ConstantNoHole(start_index));
2119 graph()->zone(), callable.descriptor(), arity + 1, flags)));
2120 return Changed(node);
2121 }
2122
2123 return NoChange();
2124}
2125
2127 JSCallNode n(node);
2128 CallParameters const& p = n.Parameters();
2129 int arity = p.arity_without_implicit_args();
2130 ConvertReceiverMode convert_mode = p.convert_mode();
2131 Node* target = n.target();
2132 Type target_type = NodeProperties::GetType(target);
2133 Node* receiver = n.receiver();
2134 Type receiver_type = NodeProperties::GetType(receiver);
2135 Effect effect = n.effect();
2136 Control control = n.control();
2137
2138 // Try to infer receiver {convert_mode} from {receiver} type.
2139 if (receiver_type.Is(Type::NullOrUndefined())) {
2141 } else if (!receiver_type.Maybe(Type::NullOrUndefined())) {
2143 }
2144
2145 // Check if we know the SharedFunctionInfo of {target}.
2146 OptionalJSFunctionRef function;
2147 OptionalSharedFunctionInfoRef shared;
2148
2149 if (target_type.IsHeapConstant() &&
2150 target_type.AsHeapConstant()->Ref().IsJSFunction()) {
2151 function = target_type.AsHeapConstant()->Ref().AsJSFunction();
2152 shared = function->shared(broker());
2153 } else if (target->opcode() == IrOpcode::kJSCreateClosure) {
2154 CreateClosureParameters const& ccp =
2156 shared = ccp.shared_info();
2157 } else if (target->opcode() == IrOpcode::kCheckClosure) {
2158 FeedbackCellRef cell = MakeRef(broker(), FeedbackCellOf(target->op()));
2159 shared = cell.shared_function_info(broker());
2160 }
2161
2162 if (shared.has_value()) {
2163 // Do not inline the call if we need to check whether to break at entry.
2164 // If this state changes during background compilation, the compilation
2165 // job will be aborted from the main thread (see
2166 // Debug::PrepareFunctionForDebugExecution()).
2167 if (shared->HasBreakInfo(broker())) return NoChange();
2168
2169 // Class constructors are callable, but [[Call]] will raise an exception.
2170 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
2171 // We need to check here in addition to JSCallReducer for Realms.
2172 // TODO(pthier): Consolidate all the class constructor checks.
2173 if (IsClassConstructor(shared->kind())) return NoChange();
2174
2175 // Check if we need to convert the {receiver}, but bailout if it would
2176 // require data from a foreign native context.
2177 if (is_sloppy(shared->language_mode()) && !shared->native() &&
2178 !receiver_type.Is(Type::Receiver())) {
2179 if (!function.has_value() || !function->native_context(broker()).equals(
2180 broker()->target_native_context())) {
2181 return NoChange();
2182 }
2183 NativeContextRef native_context = function->native_context(broker());
2184 Node* global_proxy = jsgraph()->ConstantNoHole(
2185 native_context.global_proxy_object(broker()), broker());
2186 receiver = effect = graph()->NewNode(
2187 simplified()->ConvertReceiver(convert_mode), receiver,
2188 jsgraph()->ConstantNoHole(native_context, broker()), global_proxy,
2189 effect, control);
2191 }
2192
2193 // Load the context from the {target}.
2194 Node* context = effect = graph()->NewNode(
2195 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
2196 effect, control);
2198
2199 // Update the effect dependency for the {node}.
2201
2202 // Compute flags for the call.
2204 Node* new_target = jsgraph()->UndefinedConstant();
2205
2206 int formal_count =
2207 shared->internal_formal_parameter_count_without_receiver();
2208 if (formal_count > arity) {
2209 node->RemoveInput(n.FeedbackVectorIndex());
2210 // Underapplication. Massage the arguments to match the expected number of
2211 // arguments.
2212 for (int i = arity; i < formal_count; i++) {
2213 node->InsertInput(graph()->zone(), arity + 2,
2214 jsgraph()->UndefinedConstant());
2215 }
2216
2217 // Patch {node} to a direct call.
2218 node->InsertInput(graph()->zone(), formal_count + 2, new_target);
2219 node->InsertInput(graph()->zone(), formal_count + 3,
2220 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2221#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
2222 node->InsertInput(
2223 graph()->zone(), formal_count + 4,
2224 jsgraph()->ConstantNoHole(kPlaceholderDispatchHandle.value()));
2225#endif
2228 graph()->zone(), false, 1 + formal_count,
2230 } else if (shared->HasBuiltinId() &&
2231 Builtins::IsCpp(shared->builtin_id())) {
2232 // Patch {node} to a direct CEntry call.
2233 ReduceBuiltin(jsgraph(), node, shared->builtin_id(), arity, flags);
2234 } else if (shared->HasBuiltinId()) {
2235 Builtin builtin = shared->builtin_id();
2237
2238 // This SBXCHECK is a defense-in-depth measure to ensure that we always
2239 // generate valid calls here (with matching signatures).
2242
2243 // Patch {node} to a direct code object call.
2244 Callable callable = Builtins::CallableFor(isolate(), builtin);
2245
2246 const CallInterfaceDescriptor& descriptor = callable.descriptor();
2247 auto call_descriptor = Linkage::GetStubCallDescriptor(
2248 graph()->zone(), descriptor, 1 + arity, flags);
2249 Node* stub_code = jsgraph()->HeapConstantNoHole(callable.code());
2250 node->RemoveInput(n.FeedbackVectorIndex());
2251 node->InsertInput(graph()->zone(), 0, stub_code); // Code object.
2252 node->InsertInput(graph()->zone(), 2, new_target);
2253 node->InsertInput(graph()->zone(), 3,
2254 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2255#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
2256 node->InsertInput(
2257 graph()->zone(), 4,
2258 jsgraph()->ConstantNoHole(kPlaceholderDispatchHandle.value()));
2259#endif
2260 NodeProperties::ChangeOp(node, common()->Call(call_descriptor));
2261 } else {
2262 // Patch {node} to a direct call.
2263 node->RemoveInput(n.FeedbackVectorIndex());
2264 node->InsertInput(graph()->zone(), arity + 2, new_target);
2265 node->InsertInput(graph()->zone(), arity + 3,
2266 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2267#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
2268 node->InsertInput(
2269 graph()->zone(), arity + 4,
2270 jsgraph()->ConstantNoHole(kPlaceholderDispatchHandle.value()));
2271#endif
2274 graph()->zone(), false, 1 + arity,
2276 }
2277 return Changed(node);
2278 }
2279
2280 // Check if {target} is a directly callable JSFunction.
2281 if (target_type.Is(Type::CallableFunction())) {
2282 // The node will change operators, remove the feedback vector.
2283 node->RemoveInput(n.FeedbackVectorIndex());
2284 // Compute flags for the call.
2286 // Patch {node} to an indirect call via the CallFunction builtin.
2287 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
2288 node->InsertInput(graph()->zone(), 0,
2289 jsgraph()->HeapConstantNoHole(callable.code()));
2290 node->InsertInput(graph()->zone(), 2,
2291 jsgraph()->ConstantNoHole(JSParameterCount(arity)));
2294 graph()->zone(), callable.descriptor(), 1 + arity, flags)));
2295 return Changed(node);
2296 }
2297
2298 // Maybe we did at least learn something about the {receiver}.
2299 if (p.convert_mode() != convert_mode) {
2301 node,
2302 javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
2304 return Changed(node);
2305 }
2306
2307 return NoChange();
2308}
2309
2311 JSForInNextNode n(node);
2312 Node* receiver = n.receiver();
2313 Node* cache_array = n.cache_array();
2314 Node* cache_type = n.cache_type();
2315 Node* index = n.index();
2316 Node* context = n.context();
2317 FrameState frame_state = n.frame_state();
2318 Effect effect = n.effect();
2319 Control control = n.control();
2320
2321 // Load the map of the {receiver}.
2322 Node* receiver_map = effect =
2323 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
2324 receiver, effect, control);
2325
2326 switch (n.Parameters().mode()) {
2329 // Ensure that the expected map still matches that of the {receiver}.
2330 Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
2331 receiver_map, cache_type);
2332 effect =
2333 graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
2334 check, effect, control);
2335
2336 // Since the change to LoadElement() below is effectful, we connect
2337 // node to all effect uses.
2338 ReplaceWithValue(node, node, node, control);
2339
2340 // Morph the {node} into a LoadElement.
2341 node->ReplaceInput(0, cache_array);
2342 node->ReplaceInput(1, index);
2343 node->ReplaceInput(2, effect);
2344 node->ReplaceInput(3, control);
2345 node->TrimInputCount(4);
2346 ElementAccess access =
2347 AccessBuilder::ForJSForInCacheArrayElement(n.Parameters().mode());
2348 NodeProperties::ChangeOp(node, simplified()->LoadElement(access));
2349 NodeProperties::SetType(node, access.type);
2350 break;
2351 }
2352 case ForInMode::kGeneric: {
2353 // Load the next {key} from the {cache_array}.
2354 Node* key = effect = graph()->NewNode(
2356 n.Parameters().mode())),
2357 cache_array, index, effect, control);
2358
2359 // Check if the expected map still matches that of the {receiver}.
2360 Node* check = graph()->NewNode(simplified()->ReferenceEqual(),
2361 receiver_map, cache_type);
2362 Node* branch =
2363 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
2364
2365 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
2366 Node* etrue;
2367 Node* vtrue;
2368 {
2369 // Don't need filtering since expected map still matches that of the
2370 // {receiver}.
2371 etrue = effect;
2372 vtrue = key;
2373 }
2374
2375 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
2376 Node* efalse;
2377 Node* vfalse;
2378 {
2379 // Filter the {key} to check if it's still a valid property of the
2380 // {receiver} (does the ToName conversion implicitly).
2381 Callable const callable =
2382 Builtins::CallableFor(isolate(), Builtin::kForInFilter);
2383 auto call_descriptor = Linkage::GetStubCallDescriptor(
2384 graph()->zone(), callable.descriptor(),
2387 vfalse = efalse = if_false = graph()->NewNode(
2388 common()->Call(call_descriptor),
2389 jsgraph()->HeapConstantNoHole(callable.code()), key, receiver,
2390 context, frame_state, effect, if_false);
2392 vfalse,
2393 Type::Union(Type::String(), Type::Undefined(), graph()->zone()));
2394
2395 // Update potential {IfException} uses of {node} to point to the above
2396 // ForInFilter stub call node instead.
2397 Node* if_exception = nullptr;
2398 if (NodeProperties::IsExceptionalCall(node, &if_exception)) {
2399 if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
2400 NodeProperties::ReplaceControlInput(if_exception, vfalse);
2401 NodeProperties::ReplaceEffectInput(if_exception, efalse);
2402 Revisit(if_exception);
2403 }
2404 }
2405
2406 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
2407 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2408 ReplaceWithValue(node, node, effect, control);
2409
2410 // Morph the {node} into a Phi.
2411 node->ReplaceInput(0, vtrue);
2412 node->ReplaceInput(1, vfalse);
2413 node->ReplaceInput(2, control);
2414 node->TrimInputCount(3);
2416 node, common()->Phi(MachineRepresentation::kTagged, 2));
2417 }
2418 }
2419
2420 return Changed(node);
2421}
2422
2424 JSForInPrepareNode n(node);
2425 Node* enumerator = n.enumerator();
2426 Effect effect = n.effect();
2427 Control control = n.control();
2428 Node* cache_type = enumerator;
2429 Node* cache_array = nullptr;
2430 Node* cache_length = nullptr;
2431
2432 switch (n.Parameters().mode()) {
2435 // Check that the {enumerator} is a Map.
2436 // The direct IsMap check requires reading of an instance type, so we
2437 // compare its map against fixed_array_map instead (by definition,
2438 // the {enumerator} is either the receiver's Map or a FixedArray).
2439 Node* check_for_fixed_array = effect =
2440 graph()->NewNode(simplified()->CompareMaps(
2441 ZoneRefSet<Map>(broker()->fixed_array_map())),
2442 enumerator, effect, control);
2443 Node* check_for_not_fixed_array =
2444 graph()->NewNode(simplified()->BooleanNot(), check_for_fixed_array);
2445 effect =
2446 graph()->NewNode(simplified()->CheckIf(DeoptimizeReason::kWrongMap),
2447 check_for_not_fixed_array, effect, control);
2448
2449 // Load the enum cache from the {enumerator} map.
2450 Node* descriptor_array = effect = graph()->NewNode(
2452 enumerator, effect, control);
2453 Node* enum_cache = effect = graph()->NewNode(
2455 descriptor_array, effect, control);
2456 cache_array = effect = graph()->NewNode(
2458 enum_cache, effect, control);
2459
2460 // Load the enum length of the {enumerator} map.
2461 Node* bit_field3 = effect = graph()->NewNode(
2462 simplified()->LoadField(AccessBuilder::ForMapBitField3()), enumerator,
2463 effect, control);
2464 static_assert(Map::Bits3::EnumLengthBits::kShift == 0);
2465 cache_length = graph()->NewNode(
2466 simplified()->NumberBitwiseAnd(), bit_field3,
2467 jsgraph()->ConstantNoHole(Map::Bits3::EnumLengthBits::kMask));
2468 break;
2469 }
2470 case ForInMode::kGeneric: {
2471 // Check if the {enumerator} is a Map or a FixedArray.
2472 // The direct IsMap check requires reading of an instance type, so we
2473 // compare against fixed array map instead (by definition,
2474 // the {enumerator} is either the receiver's Map or a FixedArray).
2475 Node* check = effect =
2476 graph()->NewNode(simplified()->CompareMaps(
2477 ZoneRefSet<Map>(broker()->fixed_array_map())),
2478 enumerator, effect, control);
2479 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kFalse),
2480 check, control);
2481
2482 Node* if_map = graph()->NewNode(common()->IfFalse(), branch);
2483 Node* etrue = effect;
2484 Node* cache_array_true;
2485 Node* cache_length_true;
2486 {
2487 // Load the enum cache from the {enumerator} map.
2488 Node* descriptor_array = etrue = graph()->NewNode(
2490 enumerator, etrue, if_map);
2491 Node* enum_cache = etrue =
2492 graph()->NewNode(simplified()->LoadField(
2494 descriptor_array, etrue, if_map);
2495 cache_array_true = etrue = graph()->NewNode(
2497 enum_cache, etrue, if_map);
2498
2499 // Load the enum length of the {enumerator} map.
2500 Node* bit_field3 = etrue = graph()->NewNode(
2502 enumerator, etrue, if_map);
2503 static_assert(Map::Bits3::EnumLengthBits::kShift == 0);
2504 cache_length_true = graph()->NewNode(
2505 simplified()->NumberBitwiseAnd(), bit_field3,
2506 jsgraph()->ConstantNoHole(Map::Bits3::EnumLengthBits::kMask));
2507 }
2508
2509 Node* if_fixed_array = graph()->NewNode(common()->IfTrue(), branch);
2510 Node* efalse = effect;
2511 Node* cache_array_false;
2512 Node* cache_length_false;
2513 {
2514 // The {enumerator} is the FixedArray with the keys to iterate.
2515 cache_array_false = enumerator;
2516 cache_length_false = efalse = graph()->NewNode(
2518 cache_array_false, efalse, if_fixed_array);
2519 }
2520
2521 // Rewrite the uses of the {node}.
2522 control = graph()->NewNode(common()->Merge(2), if_map, if_fixed_array);
2523 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
2524 cache_array =
2526 cache_array_true, cache_array_false, control);
2527 cache_length =
2529 cache_length_true, cache_length_false, control);
2530 break;
2531 }
2532 }
2533
2534 // Update the uses of {node}.
2535 for (Edge edge : node->use_edges()) {
2536 Node* const user = edge.from();
2537 if (NodeProperties::IsEffectEdge(edge)) {
2538 edge.UpdateTo(effect);
2539 Revisit(user);
2540 } else if (NodeProperties::IsControlEdge(edge)) {
2541 edge.UpdateTo(control);
2542 Revisit(user);
2543 } else {
2545 switch (ProjectionIndexOf(user->op())) {
2546 case 0:
2547 Replace(user, cache_type);
2548 break;
2549 case 1:
2550 Replace(user, cache_array);
2551 break;
2552 case 2:
2553 Replace(user, cache_length);
2554 break;
2555 default:
2556 UNREACHABLE();
2557 }
2558 }
2559 }
2560 node->Kill();
2561 return Replace(effect);
2562}
2563
2565 DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2566 ExternalReference const ref =
2568 node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2569 NodeProperties::ChangeOp(node, simplified()->LoadMessage());
2570 return Changed(node);
2571}
2572
2574 DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2575 ExternalReference const ref =
2577 Node* value = NodeProperties::GetValueInput(node, 0);
2578 node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2579 node->ReplaceInput(1, value);
2580 NodeProperties::ChangeOp(node, simplified()->StoreMessage());
2581 return Changed(node);
2582}
2583
2585 DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2586 Node* generator = NodeProperties::GetValueInput(node, 0);
2589 Node* context = NodeProperties::GetContextInput(node);
2590 Node* effect = NodeProperties::GetEffectInput(node);
2591 Node* control = NodeProperties::GetControlInput(node);
2592 int value_count = GeneratorStoreValueCountOf(node->op());
2593
2594 FieldAccess array_field =
2597 FieldAccess continuation_field =
2599 FieldAccess input_or_debug_pos_field =
2601
2602 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2603 generator, effect, control);
2604
2605 for (int i = 0; i < value_count; ++i) {
2606 Node* value = NodeProperties::GetValueInput(node, 3 + i);
2607 if (value != jsgraph()->OptimizedOutConstant()) {
2608 effect = graph()->NewNode(
2609 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2610 value, effect, control);
2611 }
2612 }
2613
2614 effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2615 context, effect, control);
2616 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2617 generator, continuation, effect, control);
2618 effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2619 generator, offset, effect, control);
2620
2621 ReplaceWithValue(node, effect, effect, control);
2622 return Changed(effect);
2623}
2624
2626 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2627 Node* generator = NodeProperties::GetValueInput(node, 0);
2628 Node* effect = NodeProperties::GetEffectInput(node);
2629 Node* control = NodeProperties::GetControlInput(node);
2630
2631 FieldAccess continuation_field =
2633
2634 Node* continuation = effect = graph()->NewNode(
2635 simplified()->LoadField(continuation_field), generator, effect, control);
2636 Node* executing =
2638 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2639 generator, executing, effect, control);
2640
2641 ReplaceWithValue(node, continuation, effect, control);
2642 return Changed(continuation);
2643}
2644
2646 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContext, node->opcode());
2647
2648 const Operator* new_op =
2650
2651 // Mutate the node in-place.
2654 node->RemoveInput(NodeProperties::FirstContextIndex(node));
2655
2656 NodeProperties::ChangeOp(node, new_op);
2657 return Changed(node);
2658}
2659
2661 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2662 Node* generator = NodeProperties::GetValueInput(node, 0);
2663 Node* effect = NodeProperties::GetEffectInput(node);
2664 Node* control = NodeProperties::GetControlInput(node);
2665 int index = RestoreRegisterIndexOf(node->op());
2666
2667 FieldAccess array_field =
2669 FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2670
2671 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2672 generator, effect, control);
2673 Node* element = effect = graph()->NewNode(
2674 simplified()->LoadField(element_field), array, effect, control);
2675 Node* stale = jsgraph()->StaleRegisterConstant();
2676 effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2677 stale, effect, control);
2678
2679 ReplaceWithValue(node, element, effect, control);
2680 return Changed(element);
2681}
2682
2684 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreInputOrDebugPos, node->opcode());
2685
2686 FieldAccess input_or_debug_pos_field =
2688 const Operator* new_op = simplified()->LoadField(input_or_debug_pos_field);
2689
2690 // Mutate the node in-place.
2693 node->RemoveInput(NodeProperties::FirstContextIndex(node));
2694
2695 NodeProperties::ChangeOp(node, new_op);
2696 return Changed(node);
2697}
2698
2700 Node* value = NodeProperties::GetValueInput(node, 0);
2701 Type value_type = NodeProperties::GetType(value);
2702 Node* context = NodeProperties::GetContextInput(node);
2703 Node* frame_state = NodeProperties::GetFrameStateInput(node);
2704 Node* effect = NodeProperties::GetEffectInput(node);
2705 Node* control = NodeProperties::GetControlInput(node);
2706
2707 // Constant-fold based on {value} type.
2708 if (value_type.Is(Type::Array())) {
2709 value = jsgraph()->TrueConstant();
2710 ReplaceWithValue(node, value);
2711 return Replace(value);
2712 } else if (!value_type.Maybe(Type::ArrayOrProxy())) {
2713 value = jsgraph()->FalseConstant();
2714 ReplaceWithValue(node, value);
2715 return Replace(value);
2716 }
2717
2718 int count = 0;
2719 Node* values[5];
2720 Node* effects[5];
2721 Node* controls[4];
2722
2723 // Check if the {value} is a Smi.
2724 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), value);
2725 control =
2726 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2727
2728 // The {value} is a Smi.
2729 controls[count] = graph()->NewNode(common()->IfTrue(), control);
2730 effects[count] = effect;
2731 values[count] = jsgraph()->FalseConstant();
2732 count++;
2733
2734 control = graph()->NewNode(common()->IfFalse(), control);
2735
2736 // Load the {value}s instance type.
2737 Node* value_map = effect = graph()->NewNode(
2738 simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
2739 Node* value_instance_type = effect = graph()->NewNode(
2740 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
2741 effect, control);
2742
2743 // Check if the {value} is a JSArray.
2744 check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2745 jsgraph()->ConstantNoHole(JS_ARRAY_TYPE));
2746 control = graph()->NewNode(common()->Branch(), check, control);
2747
2748 // The {value} is a JSArray.
2749 controls[count] = graph()->NewNode(common()->IfTrue(), control);
2750 effects[count] = effect;
2751 values[count] = jsgraph()->TrueConstant();
2752 count++;
2753
2754 control = graph()->NewNode(common()->IfFalse(), control);
2755
2756 // Check if the {value} is a JSProxy.
2757 check = graph()->NewNode(simplified()->NumberEqual(), value_instance_type,
2758 jsgraph()->ConstantNoHole(JS_PROXY_TYPE));
2759 control =
2760 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
2761
2762 // The {value} is neither a JSArray nor a JSProxy.
2763 controls[count] = graph()->NewNode(common()->IfFalse(), control);
2764 effects[count] = effect;
2765 values[count] = jsgraph()->FalseConstant();
2766 count++;
2767
2768 control = graph()->NewNode(common()->IfTrue(), control);
2769
2770 // Let the %ArrayIsArray runtime function deal with the JSProxy {value}.
2771 value = effect = control =
2772 graph()->NewNode(javascript()->CallRuntime(Runtime::kArrayIsArray), value,
2773 context, frame_state, effect, control);
2774 NodeProperties::SetType(value, Type::Boolean());
2775
2776 // Update potential {IfException} uses of {node} to point to the above
2777 // %ArrayIsArray runtime call node instead.
2778 Node* on_exception = nullptr;
2779 if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
2780 NodeProperties::ReplaceControlInput(on_exception, control);
2781 NodeProperties::ReplaceEffectInput(on_exception, effect);
2782 control = graph()->NewNode(common()->IfSuccess(), control);
2783 Revisit(on_exception);
2784 }
2785
2786 // The {value} is neither a JSArray nor a JSProxy.
2787 controls[count] = control;
2788 effects[count] = effect;
2789 values[count] = value;
2790 count++;
2791
2792 control = graph()->NewNode(common()->Merge(count), count, controls);
2793 effects[count] = control;
2794 values[count] = control;
2795 effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects);
2797 count + 1, values);
2798 ReplaceWithValue(node, value, effect, control);
2799 return Replace(value);
2800}
2801
2803 Node* value = NodeProperties::GetValueInput(node, 0);
2804 Type value_type = NodeProperties::GetType(value);
2805 Node* radix = NodeProperties::GetValueInput(node, 1);
2806 Type radix_type = NodeProperties::GetType(radix);
2807 // We need kTenOrUndefined and kZeroOrUndefined because
2808 // the type representing {0,10} would become the range 1-10.
2809 if (value_type.Is(type_cache_->kSafeInteger) &&
2810 (radix_type.Is(type_cache_->kTenOrUndefined) ||
2811 radix_type.Is(type_cache_->kZeroOrUndefined))) {
2812 // Number.parseInt(a:safe-integer) -> a
2813 // Number.parseInt(a:safe-integer,b:#0\/undefined) -> a
2814 // Number.parseInt(a:safe-integer,b:#10\/undefined) -> a
2815 ReplaceWithValue(node, value);
2816 return Replace(value);
2817 }
2818 return NoChange();
2819}
2820
2822 DCHECK_EQ(IrOpcode::kJSResolvePromise, node->opcode());
2823 Node* resolution = NodeProperties::GetValueInput(node, 1);
2824 Type resolution_type = NodeProperties::GetType(resolution);
2825 // We can strength-reduce JSResolvePromise to JSFulfillPromise
2826 // if the {resolution} is known to be a primitive, as in that
2827 // case we don't perform the implicit chaining (via "then").
2828 if (resolution_type.Is(Type::Primitive())) {
2829 // JSResolvePromise(p,v:primitive) -> JSFulfillPromise(p,v)
2830 node->RemoveInput(3); // frame state
2831 NodeProperties::ChangeOp(node, javascript()->FulfillPromise());
2832 return Changed(node);
2833 }
2834 return NoChange();
2835}
2836
2838 switch (node->opcode()) {
2839 case IrOpcode::kJSEqual:
2840 return ReduceJSEqual(node);
2841 case IrOpcode::kJSStrictEqual:
2842 return ReduceJSStrictEqual(node);
2843 case IrOpcode::kJSLessThan: // fall through
2844 case IrOpcode::kJSGreaterThan: // fall through
2845 case IrOpcode::kJSLessThanOrEqual: // fall through
2846 case IrOpcode::kJSGreaterThanOrEqual:
2847 return ReduceJSComparison(node);
2848 case IrOpcode::kJSBitwiseOr:
2849 case IrOpcode::kJSBitwiseXor:
2850 case IrOpcode::kJSBitwiseAnd:
2851 return ReduceInt32Binop(node);
2852 case IrOpcode::kJSShiftLeft:
2853 case IrOpcode::kJSShiftRight:
2854 return ReduceUI32Shift(node, kSigned);
2855 case IrOpcode::kJSShiftRightLogical:
2856 return ReduceUI32Shift(node, kUnsigned);
2857 case IrOpcode::kJSAdd:
2858 return ReduceJSAdd(node);
2859 case IrOpcode::kJSSubtract:
2860 case IrOpcode::kJSMultiply:
2861 case IrOpcode::kJSDivide:
2862 case IrOpcode::kJSModulus:
2863 case IrOpcode::kJSExponentiate:
2864 return ReduceNumberBinop(node);
2865 case IrOpcode::kJSBitwiseNot:
2866 return ReduceJSBitwiseNot(node);
2867 case IrOpcode::kJSDecrement:
2868 return ReduceJSDecrement(node);
2869 case IrOpcode::kJSIncrement:
2870 return ReduceJSIncrement(node);
2871 case IrOpcode::kJSNegate:
2872 return ReduceJSNegate(node);
2873 case IrOpcode::kJSHasInPrototypeChain:
2874 return ReduceJSHasInPrototypeChain(node);
2875 case IrOpcode::kJSOrdinaryHasInstance:
2876 return ReduceJSOrdinaryHasInstance(node);
2877 case IrOpcode::kJSToLength:
2878 return ReduceJSToLength(node);
2879 case IrOpcode::kJSToName:
2880 return ReduceJSToName(node);
2881 case IrOpcode::kJSToNumber:
2882 case IrOpcode::kJSToNumberConvertBigInt:
2883 return ReduceJSToNumber(node);
2884 case IrOpcode::kJSToBigInt:
2885 return ReduceJSToBigInt(node);
2886 case IrOpcode::kJSToBigIntConvertNumber:
2887 return ReduceJSToBigIntConvertNumber(node);
2888 case IrOpcode::kJSToNumeric:
2889 return ReduceJSToNumeric(node);
2890 case IrOpcode::kJSToString:
2891 return ReduceJSToString(node);
2892 case IrOpcode::kJSToObject:
2893 return ReduceJSToObject(node);
2894 case IrOpcode::kJSLoadNamed:
2895 return ReduceJSLoadNamed(node);
2896 case IrOpcode::kJSLoadContext:
2897 return ReduceJSLoadContext(node);
2898 case IrOpcode::kJSLoadScriptContext:
2899 return ReduceJSLoadScriptContext(node);
2900 case IrOpcode::kJSStoreContext:
2901 return ReduceJSStoreContext(node);
2902 case IrOpcode::kJSStoreScriptContext:
2903 return ReduceJSStoreScriptContext(node);
2904 case IrOpcode::kJSLoadModule:
2905 return ReduceJSLoadModule(node);
2906 case IrOpcode::kJSStoreModule:
2907 return ReduceJSStoreModule(node);
2908 case IrOpcode::kJSConstructForwardVarargs:
2910 case IrOpcode::kJSConstruct:
2911 return ReduceJSConstruct(node);
2912 case IrOpcode::kJSCallForwardVarargs:
2913 return ReduceJSCallForwardVarargs(node);
2914 case IrOpcode::kJSCall:
2915 return ReduceJSCall(node);
2916 case IrOpcode::kJSForInPrepare:
2917 return ReduceJSForInPrepare(node);
2918 case IrOpcode::kJSForInNext:
2919 return ReduceJSForInNext(node);
2920 case IrOpcode::kJSHasContextExtension:
2921 return ReduceJSHasContextExtension(node);
2922 case IrOpcode::kJSLoadMessage:
2923 return ReduceJSLoadMessage(node);
2924 case IrOpcode::kJSStoreMessage:
2925 return ReduceJSStoreMessage(node);
2926 case IrOpcode::kJSGeneratorStore:
2927 return ReduceJSGeneratorStore(node);
2928 case IrOpcode::kJSGeneratorRestoreContinuation:
2930 case IrOpcode::kJSGeneratorRestoreContext:
2932 case IrOpcode::kJSGeneratorRestoreRegister:
2934 case IrOpcode::kJSGeneratorRestoreInputOrDebugPos:
2936 case IrOpcode::kJSObjectIsArray:
2937 return ReduceObjectIsArray(node);
2938 case IrOpcode::kJSParseInt:
2939 return ReduceJSParseInt(node);
2940 case IrOpcode::kJSResolvePromise:
2941 return ReduceJSResolvePromise(node);
2942 default:
2943 break;
2944 }
2945 return NoChange();
2946}
2947
2949
2951
2955
2957
2961
2965
2969
2970} // namespace compiler
2971} // namespace internal
2972} // namespace v8
JSGraph * jsgraph
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
#define SBXCHECK_GE(lhs, rhs)
Definition check.h:65
#define SBXCHECK(condition)
Definition check.h:61
constexpr UnderlyingType & value() &
static constexpr int kNumExtraArgsWithReceiver
static constexpr int kNewTargetIndex
static constexpr int kPaddingIndex
static constexpr int kArgcIndex
static constexpr int kTargetIndex
static V8_EXPORT_PRIVATE bool IsCpp(Builtin builtin)
Definition builtins.cc:496
static Address CppEntryOf(Builtin builtin)
Definition builtins.cc:350
static int GetFormalParameterCount(Builtin builtin)
static V8_EXPORT_PRIVATE bool HasJSLinkage(Builtin builtin)
Definition builtins.cc:220
static V8_EXPORT_PRIVATE const char * name(Builtin builtin)
Definition builtins.cc:226
static V8_EXPORT_PRIVATE Callable CallableFor(Isolate *isolate, Builtin builtin)
Definition builtins.cc:214
Handle< Code > code() const
Definition callable.h:22
CallInterfaceDescriptor descriptor() const
Definition callable.h:23
static Callable ConstructFunctionForwardVarargs(Isolate *isolate)
static Callable StringAdd(Isolate *isolate, StringAddFlags flags=STRING_ADD_CHECK_NONE)
static Callable CallFunctionForwardVarargs(Isolate *isolate)
static Callable CallFunction(Isolate *isolate, ConvertReceiverMode mode=ConvertReceiverMode::kAny)
static const uint32_t kMinLength
Definition string.h:1029
static V8_EXPORT_PRIVATE ExternalReference address_of_pending_message(LocalIsolate *local_isolate)
static ExternalReference Create(const SCTableReference &table_ref)
static const int kGeneratorExecuting
static const int kProtectorValid
Definition protectors.h:15
static CellIndexKind GetCellIndexKind(int cell_index)
Definition modules.cc:279
static const uint32_t kMaxLength
Definition string.h:511
static TNode UncheckedCast(compiler::Node *node)
Definition tnode.h:413
static FieldAccess ForMap(WriteBarrierKind write_barrier=kMapWriteBarrier)
static FieldAccess ForContextSlotSmi(size_t index)
static FieldAccess ForFixedArraySlot(size_t index, WriteBarrierKind write_barrier_kind=kFullWriteBarrier)
static FieldAccess ForContextSlotKnownPointer(size_t index)
static FieldAccess ForJSGeneratorObjectContext()
static FieldAccess ForJSGeneratorObjectInputOrDebugPos()
static ElementAccess ForJSForInCacheArrayElement(ForInMode mode)
static FieldAccess ForJSPrimitiveWrapperValue()
static FieldAccess ForContextSlot(size_t index)
static FieldAccess ForJSGeneratorObjectContinuation()
static FieldAccess ForDescriptorArrayEnumCache()
static FieldAccess ForJSGeneratorObjectParametersAndRegisters()
ConvertReceiverMode convert_mode() const
CallFeedbackRelation feedback_relation() const
CallFrequency const & frequency() const
FeedbackSource const & feedback() const
SpeculationMode speculation_mode() const
const Operator * Call(const CallDescriptor *call_descriptor)
SharedFunctionInfoRef shared_info() const
FeedbackSource const & feedback() const
V8_INLINE void UpdateEffectControlWith(Node *node)
TNode< Uint32T > Uint32Constant(uint32_t value)
Node * LoadHeapNumberValue(Node *heap_number)
void InitializeEffectControl(Node *effect, Node *control)
BinaryOperationHint GetBinaryOperationHint(Node *node) const
Node * ConvertToUI32(Node *node, Signedness signedness)
void ConvertInputsToUI32(Signedness left_signedness, Signedness right_signedness)
bool GetCompareNumberOperationHint(NumberOperationHint *hint)
SimplifiedOperatorBuilder * simplified()
Reduction ChangeToPureOperator(const Operator *op, Type type=Type::Any())
Reduction ChangeToSpeculativeOperator(const Operator *op, Type upper_bound)
bool GetCompareBigIntOperationHint(BigIntOperationHint *hint)
JSBinopReduction(JSTypedLowering *lowering, Node *node)
CompareOperationHint GetCompareOperationHint(Node *node) const
const CreateClosureParameters & Parameters() const
IfBuilder0 & Then(const VoidGenerator0 &body)
TNode< Map > LoadMap(TNode< HeapObject > object)
Node * StoreField(FieldAccess const &, Node *object, Node *value)
Node * CheckSmi(Node *value, const FeedbackSource &feedback={})
TNode< T > ExitMachineGraph(TNode< U > input, MachineRepresentation output_representation, Type output_type)
Node * CheckNumberFitsInt32(Node *value, const FeedbackSource &feedback={})
IfBuilder1< T, Boolean > SelectIf(TNode< Boolean > cond)
Node * CheckIf(Node *cond, DeoptimizeReason reason, const FeedbackSource &feedback={})
Node * CheckNumber(Node *value, const FeedbackSource &feedback={})
Node * Assert(Node *cond, const char *condition_string="", const char *file="", int line=-1)
TNode< Boolean > ReferenceEqual(TNode< Object > lhs, TNode< Object > rhs)
TNode< T > EnterMachineGraph(TNode< U > input, UseInfo use_info)
IfBuilder0 IfNot(TNode< Boolean > cond)
TNode< Boolean > ObjectIsSmi(TNode< Object > value)
IfBuilder0 If(TNode< Boolean > cond)
Node * LoadField(FieldAccess const &, Node *object)
TNode< Smi > SmiConstant(int32_t value)
JSOperatorBuilder * javascript() const
Definition js-graph.h:104
SimplifiedOperatorBuilder * simplified() const
Definition js-graph.h:105
Node * HeapConstantNoHole(Handle< HeapObject > value)
Definition js-graph.cc:146
Node * CEntryStubConstant(int result_size, ArgvMode argv_mode=ArgvMode::kStack, bool builtin_exit_frame=false)
Definition js-graph.cc:23
Isolate * isolate() const
Definition js-graph.h:106
Factory * factory() const
Definition js-graph.h:107
Node * ConstantNoHole(ObjectRef ref, JSHeapBroker *broker)
Definition js-graph.cc:51
TNode< Hole > PaddingConstant()
Definition js-graph.h:46
BinaryOperationHint GetFeedbackForBinaryOperation(FeedbackSource const &source)
CompilationDependencies * dependencies() const
CompareOperationHint GetFeedbackForCompareOperation(FeedbackSource const &source)
static constexpr bool IsBinaryWithFeedback(Operator::Opcode opcode)
Definition js-operator.h:71
SimplifiedOperatorBuilder * simplified() const
Reduction ReduceJSGeneratorRestoreContinuation(Node *node)
JSTypedLowering(Editor *editor, JSGraph *jsgraph, JSHeapBroker *broker, Zone *zone)
Reduction ReduceJSGeneratorRestoreInputOrDebugPos(Node *node)
CompilationDependencies * dependencies() const
Reduction ReduceUI32Shift(Node *node, Signedness signedness)
CommonOperatorBuilder * common() const
Node * UnwrapStringWrapper(Node *string_or_wrapper, Node **effect, Node **control)
Reduction GenerateStringAddition(Node *node, Node *left, Node *right, Node *context, Node *frame_state, Node **effect, Node **control, bool should_create_cons_string)
static CallDescriptor * GetStubCallDescriptor(Zone *zone, const CallInterfaceDescriptor &descriptor, int stack_parameter_count, CallDescriptor::Flags flags, Operator::Properties properties=Operator::kNoProperties, StubCallMode stub_mode=StubCallMode::kCallCodeObject)
Definition linkage.cc:587
static CallDescriptor * GetJSCallDescriptor(Zone *zone, bool is_osr, int parameter_count, CallDescriptor::Flags flags, Operator::Properties properties=Operator::kNoProperties)
Definition linkage.cc:507
static CallDescriptor * GetCEntryStubCallDescriptor(Zone *zone, int return_count, int js_parameter_count, const char *debug_name, Operator::Properties properties, CallDescriptor::Flags flags, StackArgumentOrder stack_order=StackArgumentOrder::kDefault)
Definition linkage.cc:447
Node * ExternalConstant(ExternalReference ref)
CommonOperatorBuilder * common() const
static void ChangeOp(Node *node, const Operator *new_op)
static void ReplaceEffectInput(Node *node, Node *effect, int index=0)
static Type GetType(const Node *node)
static void RemoveNonValueInputs(Node *node)
static void ReplaceControlInput(Node *node, Node *control, int index=0)
static Node * GetEffectInput(Node *node, int index=0)
static int FirstFrameStateIndex(Node *node)
static Node * GetContextInput(Node *node)
static void ReplaceContextInput(Node *node, Node *context)
static Node * GetFrameStateInput(Node *node)
static Node * GetValueInput(Node *node, int index)
static void SetType(Node *node, Type type)
static void ReplaceValueInput(Node *node, Node *value, int index)
static void ReplaceValueInputs(Node *node, Node *value)
static bool IsExceptionalCall(Node *node, Node **out_exception=nullptr)
static Node * GetControlInput(Node *node, int index=0)
constexpr IrOpcode::Value opcode() const
Definition node.h:52
const Operator * op() const
Definition node.h:50
void ReplaceInput(int index, Node *new_to)
Definition node.h:76
Node * InputAt(int index) const
Definition node.h:70
Node * RemoveInput(int index)
Definition node.cc:232
void InsertInput(Zone *zone, int index, Node *new_to)
Definition node.cc:203
static bool HasContextInput(const Operator *op)
static bool HasFrameStateInput(const Operator *op)
static int GetFrameStateInputCount(const Operator *op)
base::Flags< Property, uint8_t > Properties
Definition operator.h:60
void CacheAsProtector(JSHeapBroker *broker) const
Definition heap-refs.h:545
ObjectRef value(JSHeapBroker *broker) const
const Operator * LoadField(FieldAccess const &)
OptionalCellRef GetCell(JSHeapBroker *broker, int cell_index) const
std::optional< double > ToNumber(JSHeapBroker *broker)
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
static Type Union(Type type1, Type type2, Zone *zone)
bool Maybe(Type that) const
const HeapConstantType * AsHeapConstant() const
static Type Intersect(Type type1, Type type2, Zone *zone)
bool Is(Type that) const
static UseInfo TruncatingWord32()
Definition use-info.h:200
JSHeapBroker *const broker_
uint32_t count
DirectHandle< Object > new_target
Definition execution.cc:75
JSHeapBroker * broker
int32_t offset
TNode< Context > context
std::optional< TNode< JSArray > > a
TNode< Object > receiver
SharedFunctionInfoRef shared
Node * node
ZoneVector< RpoNumber > & result
MovableLabel continuation
int m
Definition mul-fft.cc:294
int n
Definition mul-fft.cc:296
int r
Definition mul-fft.cc:298
UnionOf< Boolean, Null, Undefined > BooleanOrNullOrUndefined
Definition index.h:539
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
size_t ProjectionIndexOf(const Operator *const op)
JSCallNodeBase< IrOpcode::kJSCall > JSCallNode
NamedAccess const & NamedAccessOf(const Operator *op)
CallForwardVarargsParameters const & CallForwardVarargsParametersOf(Operator const *op)
int RestoreRegisterIndexOf(const Operator *op)
Handle< FeedbackCell > FeedbackCellOf(const Operator *op)
ConstructForwardVarargsParameters const & ConstructForwardVarargsParametersOf(Operator const *op)
HeapConstantNoHole(BUILTIN_CODE(isolate(), AllocateInOldGeneration))) DEFINE_GETTER(ArrayConstructorStubConstant
T const & OpParameter(const Operator *op)
Definition operator.h:214
JSConstructNodeBase< IrOpcode::kJSConstruct > JSConstructNode
FeedbackParameter const & FeedbackParameterOf(const Operator *op)
std::string ToString(const BytecodeLivenessState &liveness)
ContextAccess const & ContextAccessOf(Operator const *op)
int GeneratorStoreValueCountOf(const Operator *op)
ref_traits< T >::ref_type MakeRef(JSHeapBroker *broker, Tagged< T > object)
constexpr double kMaxSafeInteger
Definition globals.h:1985
@ STRING_ADD_CONVERT_RIGHT
Definition type-hints.h:77
@ STRING_ADD_CHECK_NONE
Definition type-hints.h:74
@ STRING_ADD_CONVERT_LEFT
Definition type-hints.h:76
bool is_sloppy(LanguageMode language_mode)
Definition globals.h:773
bool IsClassConstructor(FunctionKind kind)
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
int ToNumber(Register reg)
constexpr int kJSArgcReceiverSlots
Definition globals.h:2778
void Terminate(Isolate *isolate)
Definition bigint.cc:1187
uint32_t NumberToUint32(Tagged< Object > number)
constexpr JSDispatchHandle kPlaceholderDispatchHandle(0x0)
int32_t NumberToInt32(Tagged< Object > number)
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr int JSParameterCount(int param_count_without_receiver)
Definition globals.h:2782
return value
Definition map-inl.h:893
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
uint32_t equals
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485