5#ifdef V8_ENABLE_MAGLEV_GRAPH_PRINTER
9#include <initializer_list>
34int IntWidth(
int val) {
35 if (val == -1)
return 2;
36 return std::ceil(std::log10(val + 1));
39int MaxIdWidth(MaglevGraphLabeller* graph_labeller,
NodeIdT max_node_id,
40 int padding_adjustement = 0) {
41 int max_width = IntWidth(graph_labeller->max_node_id());
43 max_width += IntWidth(max_node_id) + 1;
45 return max_width + 2 + padding_adjustement;
48void PrintPaddedId(std::ostream& os, MaglevGraphLabeller* graph_labeller,
49 NodeIdT max_node_id, NodeBase* node,
50 std::string padding =
" ",
int padding_adjustement = 0) {
51 int id = graph_labeller->NodeId(node);
52 int id_width = IntWidth(
id);
53 int other_id_width = node->has_id() ? 1 + IntWidth(node->id()) : 0;
54 int max_width = MaxIdWidth(graph_labeller, max_node_id, padding_adjustement);
55 int padding_width = std::max(0, max_width - id_width - other_id_width);
57 for (
int i = 0;
i < padding_width; ++
i) {
60 if (
v8_flags.log_colour) os <<
"\033[0m";
62 os << node->id() <<
"/";
64 os << graph_labeller->NodeId(node) <<
": ";
67void PrintPadding(std::ostream& os,
int size) {
68 os << std::setfill(
' ') << std::setw(size) <<
"";
71void PrintPadding(std::ostream& os, MaglevGraphLabeller* graph_labeller,
72 NodeIdT max_node_id,
int padding_adjustement) {
74 MaxIdWidth(graph_labeller, max_node_id, padding_adjustement));
77enum ConnectionLocation {
85 void Connect(ConnectionLocation loc) { connected |= loc; }
87 void AddHorizontal() {
113 case kBottom |
kLeft:
121 case kTop | kBottom |
kLeft:
123 case kTop | kBottom |
kRight:
135 uint8_t connected = 0;
138std::ostream&
operator<<(std::ostream& os,
const Connection& c) {
139 return os << c.ToString();
145void PrintVerticalArrows(std::ostream& os,
146 const std::vector<BasicBlock*>& targets,
147 std::set<size_t> arrows_starting_here = {},
148 std::set<BasicBlock*> targets_starting_here = {},
149 bool is_loop =
false) {
150 bool saw_start =
false;
152 int current_color = -1;
153 for (
size_t i = 0;
i < targets.
size(); ++
i) {
154 int desired_color = line_color;
159 if (arrows_starting_here.find(
i) != arrows_starting_here.end() ||
160 targets_starting_here.find(targets[
i]) != targets_starting_here.end()) {
161 desired_color = (
i % 6) + 1;
162 line_color = desired_color;
164 c.Connect(is_loop ? kTop : kBottom);
169 if (c.connected == 0 && targets[
i] !=
nullptr) {
170 desired_color = (
i % 6) + 1;
173 if (
v8_flags.log_colour && desired_color != current_color &&
174 desired_color != -1) {
175 os <<
"\033[0;3" << desired_color <<
"m";
176 current_color = desired_color;
182 if (
v8_flags.log_colour && arrows_starting_here.empty() &&
183 targets_starting_here.empty()) {
190size_t AddTarget(std::vector<BasicBlock*>& targets, BasicBlock* target) {
191 if (targets.size() == 0 || targets.back() !=
nullptr) {
192 targets.push_back(target);
193 return targets.size() - 1;
196 size_t i = targets.
size();
198 if (targets[
i - 1] !=
nullptr)
break;
209bool AddTargetIfNotNext(std::vector<BasicBlock*>& targets, BasicBlock* target,
210 BasicBlock* next_block,
211 std::set<size_t>* arrows_starting_here =
nullptr) {
212 if (next_block == target)
return false;
213 size_t index = AddTarget(targets, target);
214 if (arrows_starting_here !=
nullptr) arrows_starting_here->insert(index);
218class MaglevPrintingVisitorOstream :
public std::ostream,
219 private std::streambuf {
221 MaglevPrintingVisitorOstream(std::ostream& os,
222 std::vector<BasicBlock*>* targets)
223 :
std::ostream(this),
os_(os), targets_(targets), padding_size_(0) {}
224 ~MaglevPrintingVisitorOstream()
override =
default;
226 static MaglevPrintingVisitorOstream*
cast(
227 const std::unique_ptr<std::ostream>& os) {
228 return static_cast<MaglevPrintingVisitorOstream*
>(os.get());
231 void set_padding(
int padding_size) { padding_size_ = padding_size; }
238 std::vector<BasicBlock*>* targets_;
240 bool previous_was_new_line_ =
true;
243int MaglevPrintingVisitorOstream::overflow(
int c) {
244 if (c == EOF)
return c;
246 if (previous_was_new_line_) {
247 PrintVerticalArrows(
os_, *targets_);
248 PrintPadding(
os_, padding_size_);
250 os_.rdbuf()->sputc(c);
251 previous_was_new_line_ = (c ==
'\n');
258 MaglevGraphLabeller* graph_labeller, std::ostream& os)
259 : graph_labeller_(graph_labeller),
261 os_for_additional_info_(
262 new MaglevPrintingVisitorOstream(
os_, &targets_)) {}
264void MaglevPrintingVisitor::PreProcessGraph(Graph* graph) {
267 for (BasicBlock* block : *graph) {
268 if (block->control_node()->Is<JumpLoop>()) {
269 loop_headers_.insert(block->control_node()->Cast<JumpLoop>()->target());
271 if (max_node_id_ == kInvalidNodeId) {
272 if (block->control_node()->has_id()) {
273 max_node_id_ = block->control_node()->id();
276 max_node_id_ = std::max(max_node_id_, block->control_node()->id());
281 for (BlockConstIterator block_it = graph->begin(); block_it != graph->end();
283 BasicBlock* block = *block_it;
284 std::replace(targets_.begin(), targets_.end(), block,
285 static_cast<BasicBlock*
>(
nullptr));
287 if (loop_headers_.find(block) != loop_headers_.end()) {
288 AddTarget(targets_, block);
290 ControlNode* node = block->control_node();
291 if (node->Is<JumpLoop>()) {
292 BasicBlock* target = node->Cast<JumpLoop>()->
target();
293 std::replace(targets_.begin(), targets_.end(), target,
294 static_cast<BasicBlock*
>(
nullptr));
295 }
else if (node->Is<UnconditionalControlNode>()) {
296 AddTargetIfNotNext(targets_,
297 node->Cast<UnconditionalControlNode>()->target(),
299 }
else if (node->Is<BranchControlNode>()) {
300 AddTargetIfNotNext(targets_, node->Cast<BranchControlNode>()->if_true(),
302 AddTargetIfNotNext(targets_, node->Cast<BranchControlNode>()->if_false(),
304 }
else if (node->Is<Switch>()) {
305 for (
int i = 0;
i < node->Cast<Switch>()->
size();
i++) {
306 const BasicBlockRef& target = node->Cast<Switch>()->targets()[
i];
307 AddTargetIfNotNext(targets_, target.block_ptr(), *(block_it + 1));
309 if (node->Cast<Switch>()->has_fallthrough()) {
310 BasicBlock* fallthrough_target = node->Cast<Switch>()->fallthrough();
311 AddTargetIfNotNext(targets_, fallthrough_target, *(block_it + 1));
315 DCHECK(std::all_of(targets_.begin(), targets_.end(),
316 [](BasicBlock* block) { return block == nullptr; }));
321 size_t loop_position =
static_cast<size_t>(-1);
322 if (loop_headers_.erase(block) > 0) {
323 loop_position = AddTarget(targets_, block);
326 bool saw_start =
false;
327 int current_color = -1;
329 for (
size_t i = 0;
i < targets_.
size(); ++
i) {
330 int desired_color = line_color;
337 if (targets_[
i] == block) {
339 desired_color = (
i % 6) + 1;
340 line_color = desired_color;
344 if (
i == loop_position) {
348 targets_[
i] =
nullptr;
351 }
else if (c.connected == 0 && targets_[
i] !=
nullptr) {
355 desired_color = (
i % 6) + 1;
358 if (
v8_flags.log_colour && current_color != desired_color &&
359 desired_color != -1) {
360 os_ <<
"\033[0;3" << desired_color <<
"m";
361 current_color = desired_color;
365 os_ << (saw_start ?
"►" :
" ");
369 os_ <<
"Block b" << block->id();
370 if (block->has_state() && block->state()->is_resumable_loop()) {
371 os_ <<
" (resumable)";
373 if (block->is_exception_handler_block()) {
374 os_ <<
" (exception handler)";
376 if (block->is_loop() && block->has_state()) {
377 if (block->state()->is_loop_with_peeled_iteration()) {
380 if (
const LoopEffects* loop_effects = block->state()->loop_effects()) {
382 if (loop_effects->unstable_aspects_cleared) {
383 if (loop_effects->unstable_aspects_cleared) {
386 if (loop_effects->context_slot_written.size()) {
387 os_ <<
" c" << loop_effects->context_slot_written.size();
389 if (loop_effects->objects_written.size()) {
390 os_ <<
" o" << loop_effects->objects_written.size();
392 if (loop_effects->keys_cleared.size()) {
393 os_ <<
" k" << loop_effects->keys_cleared.size();
401 MaglevPrintingVisitorOstream::cast(os_for_additional_info_)->set_padding(1);
402 return BlockProcessResult::kContinue;
407void PrintInputLocationAndAdvance(std::ostream& os, ValueNode* node,
408 InputLocation*& input_location) {
409 if (InlinedAllocation* allocation = node->TryCast<InlinedAllocation>()) {
410 if (allocation->HasBeenAnalysed() && allocation->HasBeenElided()) {
415 if (input_location) {
416 os << input_location->operand();
421void PrintSingleDeoptFrame(
422 std::ostream& os, MaglevGraphLabeller* graph_labeller,
423 const DeoptFrame& frame, InputLocation*& current_input_location,
424 LazyDeoptInfo* lazy_deopt_info_if_top_frame =
nullptr) {
425 switch (frame.type()) {
426 case DeoptFrame::FrameType::kInterpretedFrame: {
427 os <<
"@" << frame.as_interpreted().bytecode_position();
428 if (!
v8_flags.print_maglev_deopt_verbose) {
430 frame.as_interpreted().frame_state()->ForEachValue(
431 frame.as_interpreted().unit(),
432 [&](ValueNode* node, interpreter::Register
reg) { count++; });
433 os <<
" (" << count <<
" live vars)";
438 << PrintNodeLabel(graph_labeller, frame.as_interpreted().closure())
440 PrintInputLocationAndAdvance(os, frame.as_interpreted().closure(),
441 current_input_location);
442 frame.as_interpreted().frame_state()->ForEachValue(
443 frame.as_interpreted().unit(),
444 [&](ValueNode* node, interpreter::Register
reg) {
445 os <<
", " << reg.ToString() <<
":";
446 if (lazy_deopt_info_if_top_frame &&
447 lazy_deopt_info_if_top_frame->IsResultRegister(reg)) {
450 os << PrintNodeLabel(graph_labeller, node) <<
":";
451 PrintInputLocationAndAdvance(os, node, current_input_location);
457 case DeoptFrame::FrameType::kConstructInvokeStubFrame: {
458 os <<
"@ConstructInvokeStub";
459 if (!
v8_flags.print_maglev_deopt_verbose)
return;
462 << PrintNodeLabel(graph_labeller, frame.as_construct_stub().receiver())
464 PrintInputLocationAndAdvance(os, frame.as_construct_stub().receiver(),
465 current_input_location);
467 << PrintNodeLabel(graph_labeller, frame.as_construct_stub().context())
469 PrintInputLocationAndAdvance(os, frame.as_construct_stub().context(),
470 current_input_location);
474 case DeoptFrame::FrameType::kInlinedArgumentsFrame: {
475 os <<
"@" << frame.as_inlined_arguments().bytecode_position();
476 if (!
v8_flags.print_maglev_deopt_verbose)
return;
478 auto arguments = frame.as_inlined_arguments().arguments();
480 os <<
"<this>:" << PrintNodeLabel(graph_labeller, arguments[0]) <<
":";
481 PrintInputLocationAndAdvance(os, arguments[0], current_input_location);
482 if (arguments.size() > 1) {
485 for (
size_t i = 1;
i < arguments.
size();
i++) {
486 os <<
"a" << (
i - 1) <<
":"
487 << PrintNodeLabel(graph_labeller, arguments[
i]) <<
":";
488 PrintInputLocationAndAdvance(os, arguments[
i], current_input_location);
494 case DeoptFrame::FrameType::kBuiltinContinuationFrame: {
495 os <<
"@" << Builtins::name(frame.as_builtin_continuation().builtin_id());
496 if (!
v8_flags.print_maglev_deopt_verbose)
return;
499 for (ValueNode* node : frame.as_builtin_continuation().parameters()) {
500 os <<
"a" << arg_index <<
":" << PrintNodeLabel(graph_labeller, node)
502 PrintInputLocationAndAdvance(os, node, current_input_location);
507 << PrintNodeLabel(graph_labeller,
508 frame.as_builtin_continuation().context())
510 PrintInputLocationAndAdvance(os,
511 frame.as_builtin_continuation().context(),
512 current_input_location);
519void PrintVirtualObjects(std::ostream& os, std::vector<BasicBlock*> targets,
520 const DeoptFrame& frame,
521 MaglevGraphLabeller* graph_labeller,
int max_node_id) {
522 if (!
v8_flags.trace_deopt_verbose)
return;
523 PrintVerticalArrows(os, targets);
524 PrintPadding(os, graph_labeller, max_node_id, 0);
526 const VirtualObjectList& virtual_objects = frame.GetVirtualObjects();
527 for (
auto vo : virtual_objects) {
528 os << PrintNodeLabel(graph_labeller, vo) <<
"; ";
533void PrintDeoptInfoInputLocation(std::ostream& os,
534 std::vector<BasicBlock*> targets,
535 DeoptInfo* deopt_info,
536 MaglevGraphLabeller* graph_labeller,
539 if (!
v8_flags.print_maglev_deopt_verbose)
return;
540 PrintVerticalArrows(os, targets);
541 PrintPadding(os, graph_labeller, max_node_id, 0);
542 if (deopt_info->has_input_locations()) {
543 os <<
" input locations: " << deopt_info->input_locations() <<
" ("
544 << deopt_info->input_location_count() <<
" slots)";
550void RecursivePrintEagerDeopt(std::ostream& os,
551 std::vector<BasicBlock*> targets,
552 const DeoptFrame& frame,
553 MaglevGraphLabeller* graph_labeller,
555 InputLocation*& current_input_location) {
556 if (frame.parent()) {
557 RecursivePrintEagerDeopt(os, targets, *frame.parent(), graph_labeller,
558 max_node_id, current_input_location);
561 PrintVerticalArrows(os, targets);
562 PrintPadding(os, graph_labeller, max_node_id, 0);
563 if (!frame.parent()) {
568 PrintSingleDeoptFrame(os, graph_labeller, frame, current_input_location);
570 PrintVirtualObjects(os, targets, frame, graph_labeller, max_node_id);
573void PrintEagerDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
574 NodeBase* node, MaglevGraphLabeller* graph_labeller,
576 EagerDeoptInfo* deopt_info = node->eager_deopt_info();
577 InputLocation* current_input_location =
nullptr;
578 if (deopt_info->has_input_locations()) {
579 current_input_location = deopt_info->input_locations();
581 PrintDeoptInfoInputLocation(os, targets, deopt_info, graph_labeller,
583 RecursivePrintEagerDeopt(os, targets, deopt_info->top_frame(), graph_labeller,
584 max_node_id, current_input_location);
587void MaybePrintEagerDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
588 NodeBase* node, MaglevGraphLabeller* graph_labeller,
590 if (node->properties().can_eager_deopt()) {
591 PrintEagerDeopt(os, targets, node, graph_labeller, max_node_id);
595void RecursivePrintLazyDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
596 const DeoptFrame& frame,
597 MaglevGraphLabeller* graph_labeller,
599 InputLocation*& current_input_location) {
600 if (frame.parent()) {
601 RecursivePrintLazyDeopt(os, targets, *frame.parent(), graph_labeller,
602 max_node_id, current_input_location);
605 PrintVerticalArrows(os, targets);
606 PrintPadding(os, graph_labeller, max_node_id, 0);
608 PrintSingleDeoptFrame(os, graph_labeller, frame, current_input_location);
610 PrintVirtualObjects(os, targets, frame, graph_labeller, max_node_id);
613template <
typename NodeT>
614void PrintLazyDeopt(std::ostream& os, std::vector<BasicBlock*> targets,
615 NodeT* node, MaglevGraphLabeller* graph_labeller,
617 LazyDeoptInfo* deopt_info = node->lazy_deopt_info();
618 InputLocation* current_input_location =
nullptr;
619 if (deopt_info->has_input_locations()) {
620 current_input_location = deopt_info->input_locations();
623 PrintDeoptInfoInputLocation(os, targets, deopt_info, graph_labeller,
626 const DeoptFrame& top_frame = deopt_info->top_frame();
627 if (top_frame.parent()) {
628 RecursivePrintLazyDeopt(os, targets, *top_frame.parent(), graph_labeller,
629 max_node_id, current_input_location);
632 PrintVerticalArrows(os, targets);
633 PrintPadding(os, graph_labeller, max_node_id, 0);
636 PrintSingleDeoptFrame(os, graph_labeller, top_frame, current_input_location,
639 PrintVirtualObjects(os, targets, top_frame, graph_labeller, max_node_id);
642template <
typename NodeT>
643void PrintExceptionHandlerPoint(std::ostream& os,
644 std::vector<BasicBlock*> targets, NodeT* node,
645 MaglevGraphLabeller* graph_labeller,
648 ExceptionHandlerInfo* info = node->exception_handler_info();
649 if (!info->HasExceptionHandler() || info->ShouldLazyDeopt())
return;
651 BasicBlock* block = info->catch_block();
652 DCHECK(block->is_exception_handler_block());
654 if (!block->has_phi()) {
657 Phi* first_phi = block->phis()->first();
659 int handler_offset = first_phi->merge_state()->merge_offset();
662 auto* liveness = block->state()->frame_state().liveness();
663 LazyDeoptInfo* deopt_info = node->lazy_deopt_info();
665 const InterpretedDeoptFrame* lazy_frame;
666 switch (deopt_info->top_frame().type()) {
667 case DeoptFrame::FrameType::kInterpretedFrame:
668 lazy_frame = &deopt_info->top_frame().as_interpreted();
670 case DeoptFrame::FrameType::kInlinedArgumentsFrame:
672 case DeoptFrame::FrameType::kConstructInvokeStubFrame:
673 case DeoptFrame::FrameType::kBuiltinContinuationFrame:
674 lazy_frame = &deopt_info->top_frame().parent()->as_interpreted();
678 PrintVerticalArrows(os, targets);
679 PrintPadding(os, graph_labeller, max_node_id, 0);
681 os <<
" ↳ throw @" << handler_offset <<
" : {";
683 lazy_frame->as_interpreted().frame_state()->ForEachValue(
684 lazy_frame->as_interpreted().unit(),
685 [&](ValueNode* node, interpreter::Register
reg) {
686 if (!reg.is_parameter() && !liveness->RegisterIsLive(reg.index())) {
695 os <<
reg.ToString() <<
":" << PrintNodeLabel(graph_labeller, node);
700void MaybePrintLazyDeoptOrExceptionHandler(std::ostream& os,
701 std::vector<BasicBlock*> targets,
703 MaglevGraphLabeller* graph_labeller,
705 switch (node->opcode()) {
707 case Opcode::k##Name: \
708 if constexpr (Name::kProperties.can_lazy_deopt()) { \
709 PrintLazyDeopt<Name>(os, targets, node->Cast<Name>(), graph_labeller, \
712 if constexpr (Name::kProperties.can_throw()) { \
713 PrintExceptionHandlerPoint<Name>(os, targets, node->Cast<Name>(), \
714 graph_labeller, max_node_id); \
722void MaybePrintProvenance(std::ostream& os, std::vector<BasicBlock*> targets,
723 MaglevGraphLabeller::Provenance provenance,
724 MaglevGraphLabeller::Provenance existing_provenance) {
728 bool needs_function_print = provenance.unit != existing_provenance.unit;
729 Tagged<Script> script;
730 Script::PositionInfo position_info;
731 bool has_position_info =
false;
735 if (provenance.position.IsKnown() &&
736 (provenance.position != existing_provenance.position ||
737 provenance.unit != existing_provenance.unit)) {
738 script = Cast<Script>(
739 provenance.unit->shared_function_info().object()->script());
740 has_position_info = script->GetPositionInfo(
741 provenance.position.ScriptOffset(), &position_info,
742 Script::OffsetFlag::kWithOffset);
743 needs_function_print =
true;
747 if (needs_function_print) {
748 if (script.is_null()) {
749 script = Cast<Script>(
750 provenance.unit->shared_function_info().object()->script());
752 PrintVerticalArrows(os, targets);
756 os << *provenance.unit->shared_function_info().object() <<
" ("
757 << script->GetNameOrSourceURL();
758 if (has_position_info) {
759 os <<
":" << position_info.line <<
":" << position_info.column;
760 }
else if (provenance.position.IsKnown()) {
761 os <<
"@" << provenance.position.ScriptOffset();
771 if (!provenance.bytecode_offset.IsNone() &&
772 (provenance.bytecode_offset != existing_provenance.bytecode_offset ||
773 provenance.unit != existing_provenance.unit)) {
774 PrintVerticalArrows(os, targets);
776 interpreter::BytecodeArrayIterator iterator(
777 provenance.unit->bytecode().object(),
778 provenance.bytecode_offset.ToInt(), no_gc);
782 os << std::setw(4) << iterator.current_offset() <<
" : ";
783 interpreter::BytecodeDecoder::Decode(os, iterator.current_address(),
false);
794 const ProcessingState& state) {
795 PrintVerticalArrows(
os_, targets_);
796 PrintPaddedId(
os_, graph_labeller_, max_node_id_, phi);
798 switch (phi->value_representation()) {
799 case ValueRepresentation::kTagged:
802 case ValueRepresentation::kInt32:
805 case ValueRepresentation::kUint32:
808 case ValueRepresentation::kFloat64:
811 case ValueRepresentation::kHoleyFloat64:
814 case ValueRepresentation::kIntPtr:
817 if (phi->uses_require_31_bit_value()) {
820 if (phi->input_count() == 0) {
821 os_ <<
"ₑ " << (phi->owner().is_valid() ? phi->owner().ToString() :
"VO");
823 os_ <<
" " << (phi->owner().is_valid() ? phi->owner().ToString() :
"VO")
828 for (
int i = 0;
i < phi->input_count(); ++
i) {
829 if (
i > 0)
os_ <<
", ";
830 os_ << PrintNodeLabel(graph_labeller_, phi->input(
i).node());
834 if (phi->is_tagged() && !phi->result().operand().IsUnallocated()) {
835 if (phi->decompresses_tagged_result()) {
836 os_ <<
" (decompressed)";
838 os_ <<
" (compressed)";
841 os_ <<
" → " << phi->result().operand();
842 if (phi->result().operand().IsAllocated() && phi->is_spilled() &&
843 phi->spill_slot() != phi->result().operand()) {
844 os_ <<
" (spilled: " << phi->spill_slot() <<
")";
846 if (phi->has_valid_live_range()) {
847 os_ <<
", live range: [" << phi->live_range().start <<
"-"
848 << phi->live_range().end <<
"]";
850 if (!phi->has_id()) {
851 os_ <<
", " << phi->use_count() <<
" uses";
855 MaglevPrintingVisitorOstream::cast(os_for_additional_info_)
856 ->set_padding(MaxIdWidth(graph_labeller_, max_node_id_, 2));
857 return ProcessResult::kContinue;
861 const ProcessingState& state) {
862 MaglevGraphLabeller::Provenance provenance =
863 graph_labeller_->GetNodeProvenance(node);
864 if (provenance.unit !=
nullptr) {
865 MaybePrintProvenance(
os_, targets_, provenance, existing_provenance_);
866 existing_provenance_ = provenance;
869 MaybePrintEagerDeopt(
os_, targets_, node, graph_labeller_, max_node_id_);
871 PrintVerticalArrows(
os_, targets_);
872 PrintPaddedId(
os_, graph_labeller_, max_node_id_, node);
873 if (node->properties().is_call()) {
876 os_ << PrintNode(graph_labeller_, node) <<
"\n";
878 MaglevPrintingVisitorOstream::cast(os_for_additional_info_)
879 ->set_padding(MaxIdWidth(graph_labeller_, max_node_id_, 2));
881 MaybePrintLazyDeoptOrExceptionHandler(
os_, targets_, node, graph_labeller_,
883 return ProcessResult::kContinue;
886ProcessResult MaglevPrintingVisitor::Process(ControlNode* control_node,
887 const ProcessingState& state) {
888 MaglevGraphLabeller::Provenance provenance =
889 graph_labeller_->GetNodeProvenance(control_node);
890 if (provenance.unit !=
nullptr) {
891 MaybePrintProvenance(
os_, targets_, provenance, existing_provenance_);
892 existing_provenance_ = provenance;
895 MaybePrintEagerDeopt(
os_, targets_, control_node, graph_labeller_,
898 bool has_fallthrough =
false;
900 if (control_node->Is<JumpLoop>()) {
901 BasicBlock* target = control_node->Cast<JumpLoop>()->
target();
903 PrintVerticalArrows(
os_, targets_, {}, {target},
true);
905 PrintPaddedId(
os_, graph_labeller_, max_node_id_, control_node,
"─", -2);
906 std::replace(targets_.begin(), targets_.end(), target,
907 static_cast<BasicBlock*
>(
nullptr));
909 }
else if (control_node->Is<UnconditionalControlNode>()) {
911 control_node->Cast<UnconditionalControlNode>()->
target();
913 std::set<size_t> arrows_starting_here;
914 has_fallthrough |= !AddTargetIfNotNext(targets_, target, state.next_block(),
915 &arrows_starting_here);
916 PrintVerticalArrows(
os_, targets_, arrows_starting_here);
917 PrintPaddedId(
os_, graph_labeller_, max_node_id_, control_node,
918 has_fallthrough ?
" " :
"─");
920 }
else if (control_node->Is<BranchControlNode>()) {
921 BasicBlock* true_target =
922 control_node->Cast<BranchControlNode>()->if_true();
923 BasicBlock* false_target =
924 control_node->Cast<BranchControlNode>()->if_false();
926 std::set<size_t> arrows_starting_here;
927 has_fallthrough |= !AddTargetIfNotNext(
928 targets_, false_target, state.next_block(), &arrows_starting_here);
929 has_fallthrough |= !AddTargetIfNotNext(
930 targets_, true_target, state.next_block(), &arrows_starting_here);
931 PrintVerticalArrows(
os_, targets_, arrows_starting_here);
932 PrintPaddedId(
os_, graph_labeller_, max_node_id_, control_node,
"─");
933 }
else if (control_node->Is<Switch>()) {
934 std::set<size_t> arrows_starting_here;
935 for (
int i = 0;
i < control_node->Cast<Switch>()->
size();
i++) {
936 const BasicBlockRef& target = control_node->Cast<Switch>()->targets()[
i];
938 !AddTargetIfNotNext(targets_, target.block_ptr(), state.next_block(),
939 &arrows_starting_here);
942 if (control_node->Cast<Switch>()->has_fallthrough()) {
943 BasicBlock* fallthrough_target =
944 control_node->Cast<Switch>()->fallthrough();
946 !AddTargetIfNotNext(targets_, fallthrough_target, state.next_block(),
947 &arrows_starting_here);
950 PrintVerticalArrows(
os_, targets_, arrows_starting_here);
951 PrintPaddedId(
os_, graph_labeller_, max_node_id_, control_node,
"─");
954 PrintVerticalArrows(
os_, targets_);
955 PrintPaddedId(
os_, graph_labeller_, max_node_id_, control_node);
958 os_ << PrintNode(graph_labeller_, control_node) <<
"\n";
960 bool printed_phis =
false;
961 if (control_node->Is<UnconditionalControlNode>()) {
963 control_node->Cast<UnconditionalControlNode>()->
target();
964 if (target->has_phi()) {
966 PrintVerticalArrows(
os_, targets_);
967 PrintPadding(
os_, graph_labeller_, max_node_id_, -1);
968 os_ << (has_fallthrough ?
"│" :
" ");
969 os_ <<
" with gap moves:\n";
970 int pid = state.block()->predecessor_id();
971 for (Phi* phi : *target->phis()) {
972 PrintVerticalArrows(
os_, targets_);
973 PrintPadding(
os_, graph_labeller_, max_node_id_, -1);
974 os_ << (has_fallthrough ?
"│" :
" ");
976 graph_labeller_->PrintInput(
os_, phi->input(pid));
977 os_ <<
" → " << graph_labeller_->NodeId(phi) <<
": φ";
978 switch (phi->value_representation()) {
979 case ValueRepresentation::kTagged:
982 case ValueRepresentation::kInt32:
985 case ValueRepresentation::kUint32:
988 case ValueRepresentation::kFloat64:
991 case ValueRepresentation::kHoleyFloat64:
994 case ValueRepresentation::kIntPtr:
997 if (phi->uses_require_31_bit_value()) {
1000 os_ <<
" " << (phi->owner().is_valid() ? phi->owner().ToString() :
"VO")
1001 <<
" " << phi->result().operand() <<
"\n";
1003#ifdef V8_ENABLE_MAGLEV
1004 if (target->state()->register_state().is_initialized()) {
1005 PrintVerticalArrows(
os_, targets_);
1006 PrintPadding(
os_, graph_labeller_, max_node_id_, -1);
1007 os_ << (has_fallthrough ?
"│" :
" ");
1008 os_ <<
" with register merges:\n";
1011 RegisterMerge* merge;
1013 compiler::InstructionOperand source = merge->operand(pid);
1014 PrintVerticalArrows(
os_, targets_);
1015 PrintPadding(
os_, graph_labeller_, max_node_id_, -1);
1016 os_ << (has_fallthrough ?
"│" :
" ");
1017 os_ <<
" - " << source <<
" → " <<
reg <<
"\n";
1020 target->state()->register_state().ForEachGeneralRegister(
1021 print_register_merges);
1022 target->state()->register_state().ForEachDoubleRegister(
1023 print_register_merges);
1029 PrintVerticalArrows(
os_, targets_);
1030 if (has_fallthrough) {
1031 PrintPadding(
os_, graph_labeller_, max_node_id_, -1);
1042 MaglevPrintingVisitorOstream::cast(os_for_additional_info_)
1043 ->set_padding(MaxIdWidth(graph_labeller_, max_node_id_, 2));
1045 return ProcessResult::kContinue;
1048void PrintGraph(std::ostream& os, MaglevCompilationInfo* compilation_info,
1049 Graph*
const graph) {
1050 GraphProcessor<MaglevPrintingVisitor,
true> printer(
1051 compilation_info->graph_labeller(), os);
1052 printer.ProcessGraph(graph);
1055void PrintNode::Print(std::ostream& os)
const {
1056 node_->Print(os, graph_labeller_, skip_targets_);
1059void PrintNodeLabel::Print(std::ostream& os)
const {
1060 graph_labeller_->PrintNodeLabel(os,
node_);
1064void BasicBlock::Print()
const {
1065 std::cout <<
"Block";
1067 if (
state()->is_loop_with_peeled_iteration()) {
1068 std::cout <<
" (peeled loop)";
1069 }
else if (has_state() &&
state()->is_resumable_loop()) {
1070 std::cout <<
" (resumable loop)";
1072 std::cout <<
" (loop header)";
1074 }
else if (is_exception_handler_block()) {
1075 std::cout <<
" (exception handler)";
1078 for (
auto node :
nodes_) {
1081 if (control_node_) {
1082 control_node_->Print();
1084 std::cout <<
" (missing control node)\n";
MaglevPrintingVisitor(MaglevGraphLabeller *graph_labeller, std::ostream &os)
constexpr const char * ToString(DataViewOp op)
ZoneLinkedList< BFEntry > nodes_
LiftoffAssembler::CacheState state
#define NODE_BASE_LIST(V)
static constexpr NodeIdT kInvalidNodeId
void PrintGraph(std::ostream &os, MaglevCompilationInfo *compilation_info, Graph *const graph)
std::ostream & operator<<(std::ostream &os, const PrintNode &printer)
base::PointerWithPayload< void, RegisterStateFlags, 2 > RegisterState
bool LoadMergeState(RegisterState state, RegisterMerge **merge)
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
V8_EXPORT_PRIVATE FlagValues v8_flags
#define CHECK_NOT_NULL(val)
#define DCHECK(condition)
#define DCHECK_GT(v1, v2)