v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
turbofan-graph-visualizer.cc
Go to the documentation of this file.
1// Copyright 2013 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 <memory>
8#include <optional>
9#include <regex>
10#include <sstream>
11#include <string>
12
13#include "src/base/vector.h"
22#include "src/compiler/node.h"
30#include "src/utils/ostreams.h"
31
32#if V8_ENABLE_WEBASSEMBLY
34#endif
35
36namespace v8 {
37namespace internal {
38namespace compiler {
39
41 if (!info->trace_turbo_filename()) {
42 info->set_trace_turbo_filename(GetVisualizerLogFileName(
43 info, v8_flags.trace_turbo_path, nullptr, "json"));
44 }
45 return info->trace_turbo_filename();
46}
47
49 std::ios_base::openmode mode)
50 : std::ofstream(get_cached_trace_turbo_filename(info), mode) {}
51
53
55 : std::ofstream(Isolate::GetTurboCfgFileName(isolate).c_str(),
56 std::ios_base::app) {}
57
59
60std::ostream& operator<<(std::ostream& out,
61 const SourcePositionAsJSON& asJSON) {
62 asJSON.sp.PrintJson(out);
63 return out;
64}
65
66std::ostream& operator<<(std::ostream& out, const NodeOriginAsJSON& asJSON) {
67 asJSON.no.PrintJson(out);
68 return out;
69}
70
71void JsonPrintBytecodeSource(std::ostream& os, int source_id,
72 std::unique_ptr<char[]> function_name,
73 DirectHandle<BytecodeArray> bytecode_array,
74 Tagged<FeedbackVector> feedback_vector) {
75 os << "\"" << source_id << "\" : {";
76 os << "\"sourceId\": " << source_id;
77 os << ", \"functionName\": \"" << function_name.get() << "\"";
78 os << ", \"bytecodeSource\": ";
79 bytecode_array->PrintJson(os);
80 os << ", \"feedbackVector\": \"";
81 if (!feedback_vector.is_null()) {
82 std::stringstream stream;
83 FeedbackVector::Print(feedback_vector, stream);
84 std::regex newlines_re("\n+");
85 os << std::regex_replace(stream.str(), newlines_re, "\\n");
86 }
87 os << "\"}";
88}
89
90void JsonPrintFunctionSource(std::ostream& os, int source_id,
91 std::unique_ptr<char[]> function_name,
92 DirectHandle<Script> script, Isolate* isolate,
94 bool with_key) {
95 if (with_key) os << "\"" << source_id << "\" : ";
96
97 os << "{ ";
98 os << "\"sourceId\": " << source_id;
99 os << ", \"functionName\": \"" << function_name.get() << "\" ";
100
101 int start = 0;
102 int end = 0;
103 if (!script.is_null() && !IsUndefined(*script, isolate) &&
104 !shared.is_null()) {
105 Tagged<Object> source_name = script->name();
106 os << ", \"sourceName\": \"";
107 if (IsString(source_name)) {
108 std::ostringstream escaped_name;
109 escaped_name << Cast<String>(source_name)->ToCString().get();
110 os << JSONEscaped(escaped_name);
111 }
112 os << "\"";
113 {
114 start = shared->StartPosition();
115 end = shared->EndPosition();
116 os << ", \"sourceText\": \"";
117 if (!IsUndefined(script->source())) {
119 int len = shared->EndPosition() - start;
120 SubStringRange source(Cast<String>(script->source()), no_gc, start,
121 len);
122 for (auto c : source) {
123 os << AsEscapedUC16ForJSON(c);
124 }
125#if V8_ENABLE_WEBASSEMBLY
126 } else if (shared->HasWasmExportedFunctionData()) {
128 shared->wasm_exported_function_data();
129 wasm::NativeModule* native_module =
130 function_data->instance_data()->native_module();
131 const wasm::WasmModule* module = native_module->module();
132 std::ostringstream str;
133 wasm::DisassembleFunction(module, function_data->function_index(),
134 native_module->wire_bytes(),
135 native_module->GetNamesProvider(), str);
136 os << JSONEscaped(str);
137#endif // V8_ENABLE_WEBASSEMBLY
138 }
139 os << "\"";
140 }
141 } else {
142 os << ", \"sourceName\": \"\"";
143 os << ", \"sourceText\": \"\"";
144 }
145 os << ", \"startPosition\": " << start;
146 os << ", \"endPosition\": " << end;
147 os << "}";
148}
149
151 for (unsigned i = 0; i < printed_.size(); i++) {
152 if (printed_.at(i).is_identical_to(shared)) {
153 source_ids_.push_back(i);
154 return i;
155 }
156 }
157 const int source_id = static_cast<int>(printed_.size());
158 printed_.push_back(shared);
159 source_ids_.push_back(source_id);
160 return source_id;
161}
162
163namespace {
164
165void JsonPrintInlinedFunctionInfo(
166 std::ostream& os, int source_id, int inlining_id,
168 os << "\"" << inlining_id << "\" : ";
169 os << "{ \"inliningId\" : " << inlining_id;
170 os << ", \"sourceId\" : " << source_id;
172 if (position.IsKnown()) {
173 os << ", \"inliningPosition\" : " << AsJSON(position);
174 }
175 os << "}";
176}
177
178} // namespace
179
180void JsonPrintAllBytecodeSources(std::ostream& os,
182 os << "\"bytecodeSources\" : {";
183
184 JsonPrintBytecodeSource(os, -1, info->shared_info()->DebugNameCStr(),
185 info->bytecode_array(),
186 info->closure()->feedback_vector());
187
188 const auto& inlined = info->inlined_functions();
189 SourceIdAssigner id_assigner(info->inlined_functions().size());
190
191 for (unsigned id = 0; id < inlined.size(); id++) {
192 Handle<SharedFunctionInfo> shared_info = inlined[id].shared_info;
193#if V8_ENABLE_WEBASSEMBLY
194 if (shared_info->HasWasmFunctionData()) {
195 continue;
196 }
197#endif // V8_ENABLE_WEBASSEMBLY
198 os << ", ";
199 const int source_id = id_assigner.GetIdFor(shared_info);
200 // TODO(nicohartmann): We could print some feedback for the inlined
201 // functions, too.
202 JsonPrintBytecodeSource(os, source_id, shared_info->DebugNameCStr(),
203 inlined[id].bytecode_array);
204 }
205
206 os << "}";
207}
208
211 Isolate* isolate) {
212 os << "\"sources\" : {";
213 DirectHandle<Script> script =
214 (info->shared_info().is_null() ||
215 info->shared_info()->script() == Tagged<Object>())
217 : direct_handle(Cast<Script>(info->shared_info()->script()), isolate);
219 info->shared_info().is_null()
220 ? std::unique_ptr<char[]>(new char[1]{0})
221 : info->shared_info()->DebugNameCStr(),
222 script, isolate, info->shared_info(), true);
223 const auto& inlined = info->inlined_functions();
224 SourceIdAssigner id_assigner(info->inlined_functions().size());
225 for (unsigned id = 0; id < inlined.size(); id++) {
226 os << ", ";
227 Handle<SharedFunctionInfo> shared = inlined[id].shared_info;
228 const int source_id = id_assigner.GetIdFor(shared);
230 os, source_id, shared->DebugNameCStr(),
231 direct_handle(Cast<Script>(shared->script()), isolate), isolate, shared,
232 true);
233 }
234 os << "}, ";
235 os << "\"inlinings\" : {";
236 bool need_comma = false;
237 for (unsigned id = 0; id < inlined.size(); id++) {
238 if (need_comma) os << ", ";
239 const int source_id = id_assigner.GetIdAt(id);
240 JsonPrintInlinedFunctionInfo(os, source_id, id, inlined[id]);
241 need_comma = true;
242 }
243 os << "}";
244}
245
246#if V8_ENABLE_WEBASSEMBLY
247void JsonPrintAllSourceWithPositionsWasm(
248 std::ostream& os, const wasm::WasmModule* module,
249 const wasm::WireBytesStorage* wire_bytes,
251 // Filter out duplicate sources. (A single wasm function might be inlined more
252 // than once.)
253 std::vector<int /*function id*/> sources;
254 std::unordered_map<int /*function id*/, size_t /*source index*/> source_map;
255 for (WasmInliningPosition pos : positions) {
256 auto [_, inserted] =
257 source_map.emplace(pos.inlinee_func_index, sources.size());
258 if (inserted) {
259 // The function wasn't inlined yet. Add a new entry to the sources.
260 // The hashmap stores the index to the entry in the source map.
261 sources.push_back(pos.inlinee_func_index);
262 }
263 // Don't do anything if it was already inserted.
264 }
265
266 // Print inlining sources.
267 os << "\"sources\": {";
268 for (size_t i = 0; i < sources.size(); ++i) {
269 if (i != 0) os << ", ";
270 int function_id = sources[i];
271 const wasm::WasmFunction& fct = module->functions[function_id];
272 os << '"' << i << "\": {\"sourceId\": " << i << ", \"functionName\": \""
273 << fct.func_index << "\", \"sourceName\": \"\", \"sourceText\": \"";
274 base::Vector<const uint8_t> module_bytes{nullptr, 0};
275 std::optional<wasm::ModuleWireBytes> maybe_wire_bytes =
276 wire_bytes->GetModuleBytes();
277 if (maybe_wire_bytes) module_bytes = maybe_wire_bytes->module_bytes();
278 std::ostringstream wasm_str;
279 wasm::DisassembleFunction(module, function_id,
280 wire_bytes->GetCode(fct.code), module_bytes,
281 fct.code.offset(), wasm_str);
282 os << JSONEscaped(wasm_str) << "\"}";
283 }
284 os << "},\n";
285 // Print inlining mappings.
286 // This maps the inlining position to the deduplicated source in the sources
287 // object generated above.
288 os << "\"inlinings\": {";
289 for (size_t i = 0; i < positions.size(); ++i) {
290 if (i != 0) os << ", ";
291 DCHECK(source_map.contains(positions[i].inlinee_func_index));
292 size_t source_id = source_map.find(positions[i].inlinee_func_index)->second;
293 SourcePosition inlining_pos = positions[i].caller_pos;
294 os << '"' << i << "\": {\"inliningId\": " << i
295 << ", \"sourceId\": " << source_id
296 << ", \"inliningPosition\": " << AsJSON(inlining_pos) << "}";
297 }
298}
299#endif
300
302 const char* optional_base_dir,
303 const char* phase,
304 const char* suffix) {
306 std::unique_ptr<char[]> debug_name = info->GetDebugName();
307 const char* file_prefix = v8_flags.trace_turbo_file_prefix.value();
308 int optimization_id = info->IsOptimizing() ? info->optimization_id() : 0;
309 if (strlen(debug_name.get()) > 0) {
310 if (strcmp(debug_name.get(), "WasmJSFastApiCall") == 0) {
311 // Don't clobber one wrapper's output with another's.
312 static int fast_call_wrappers_count = 0;
313 optimization_id = ++fast_call_wrappers_count;
314 }
315 SNPrintF(filename, "%s-%s-%i", file_prefix, debug_name.get(),
316 optimization_id);
317 } else if (info->has_shared_info()) {
318 SNPrintF(filename, "%s-%p-%i", file_prefix,
319 reinterpret_cast<void*>(info->shared_info()->address()),
320 optimization_id);
321 } else {
322 SNPrintF(filename, "%s-none-%i", file_prefix, optimization_id);
323 }
324 base::EmbeddedVector<char, 256> source_file(0);
325 bool source_available = false;
326 if (v8_flags.trace_file_names && info->has_shared_info() &&
327 IsScript(info->shared_info()->script())) {
328 Tagged<Object> source_name =
329 Cast<Script>(info->shared_info()->script())->name();
330 if (IsString(source_name)) {
331 Tagged<String> str = Cast<String>(source_name);
332 if (str->length() > 0) {
333 SNPrintF(source_file, "%s", str->ToCString().get());
334 std::replace(source_file.begin(),
335 source_file.begin() + source_file.length(), '/', '_');
336 source_available = true;
337 }
338 }
339 }
340 std::replace(filename.begin(), filename.begin() + filename.length(), ' ',
341 '_');
342 std::replace(filename.begin(), filename.begin() + filename.length(), ':',
343 '-');
344
346 if (optional_base_dir != nullptr) {
347 SNPrintF(base_dir, "%s%c", optional_base_dir,
349 } else {
350 base_dir[0] = '\0';
351 }
352
354 if (phase == nullptr && !source_available) {
355 SNPrintF(full_filename, "%s%s.%s", base_dir.begin(), filename.begin(),
356 suffix);
357 } else if (phase != nullptr && !source_available) {
358 SNPrintF(full_filename, "%s%s-%s.%s", base_dir.begin(), filename.begin(),
359 phase, suffix);
360 } else if (phase == nullptr && source_available) {
361 SNPrintF(full_filename, "%s%s_%s.%s", base_dir.begin(), filename.begin(),
362 source_file.begin(), suffix);
363 } else {
364 SNPrintF(full_filename, "%s%s_%s-%s.%s", base_dir.begin(), filename.begin(),
365 source_file.begin(), phase, suffix);
366 }
367
368 char* buffer = new char[full_filename.length() + 1];
369 memcpy(buffer, full_filename.begin(), full_filename.length());
370 buffer[full_filename.length()] = '\0';
371 return std::unique_ptr<char[]>(buffer);
372}
373
374static int SafeId(Node* node) { return node == nullptr ? -1 : node->id(); }
375static const char* SafeMnemonic(Node* node) {
376 return node == nullptr ? "null" : node->op()->mnemonic();
377}
378
379JSONGraphWriter::JSONGraphWriter(std::ostream& os, const TFGraph* graph,
380 const SourcePositionTable* positions,
382 : os_(os),
383 zone_(nullptr),
384 graph_(graph),
385 positions_(positions),
386 origins_(origins),
387 first_node_(true),
388 first_edge_(true) {}
389
390void JSONGraphWriter::PrintPhase(const char* phase_name) {
391 os_ << "{\"name\":\"" << phase_name << "\",\"type\":\"graph\",\"data\":";
392 Print();
393 os_ << "},\n";
394}
395
397 AccountingAllocator allocator;
398 Zone tmp_zone(&allocator, ZONE_NAME);
399 zone_ = &tmp_zone;
400
401 AllNodes all(zone_, graph_, false);
402 AllNodes live(zone_, graph_, true);
403
404 os_ << "{\n\"nodes\":[";
405 for (Node* const node : all.reachable) PrintNode(node, live.IsLive(node));
406 os_ << "\n";
407 os_ << "],\n\"edges\":[";
408 for (Node* const node : all.reachable) PrintEdges(node);
409 os_ << "\n";
410 os_ << "]}";
411 zone_ = nullptr;
412}
413
414void JSONGraphWriter::PrintNode(Node* node, bool is_live) {
415 if (first_node_) {
416 first_node_ = false;
417 } else {
418 os_ << ",\n";
419 }
420 std::ostringstream label, title, properties;
421 node->op()->PrintTo(label, Operator::PrintVerbosity::kSilent);
422 node->op()->PrintTo(title, Operator::PrintVerbosity::kVerbose);
423 node->op()->PrintPropsTo(properties);
424 os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << JSONEscaped(label)
425 << "\"" << ",\"title\":\"" << JSONEscaped(title) << "\""
426 << ",\"live\": " << (is_live ? "true" : "false") << ",\"properties\":\""
427 << JSONEscaped(properties) << "\"";
428 IrOpcode::Value opcode = node->opcode();
429 if (IrOpcode::IsPhiOpcode(opcode)) {
430 os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
431 << "]";
432 os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
433 << "]";
434 } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse ||
435 opcode == IrOpcode::kLoop) {
436 os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node)
437 << "]";
438 }
439 if (opcode == IrOpcode::kBranch) {
440 os_ << ",\"rankInputs\":[0]";
441 }
442 if (positions_ != nullptr) {
443 SourcePosition position = positions_->GetSourcePosition(node);
444 if (position.IsKnown()) {
445 os_ << ", \"sourcePosition\" : " << AsJSON(position);
446 }
447 }
448 if (origins_) {
449 NodeOrigin origin = origins_->GetNodeOrigin(node);
450 if (origin.IsKnown()) {
451 os_ << ", \"origin\" : " << AsJSON(origin);
452 }
453 }
454 os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\"";
455 os_ << ",\"control\":"
456 << (NodeProperties::IsControl(node) ? "true" : "false");
457 os_ << ",\"opinfo\":\"" << node->op()->ValueInputCount() << " v "
458 << node->op()->EffectInputCount() << " eff "
459 << node->op()->ControlInputCount() << " ctrl in, "
460 << node->op()->ValueOutputCount() << " v "
461 << node->op()->EffectOutputCount() << " eff "
462 << node->op()->ControlOutputCount() << " ctrl out\"";
463 if (auto type_opt = GetType(node)) {
464 std::ostringstream type_out;
465 type_opt->PrintTo(type_out);
466 os_ << ",\"type\":\"" << JSONEscaped(type_out) << "\"";
467 }
468 os_ << "}";
469}
470
472 for (int i = 0; i < node->InputCount(); i++) {
473 Node* input = node->InputAt(i);
474 if (input == nullptr) continue;
475 PrintEdge(node, i, input);
476 }
477}
478
479void JSONGraphWriter::PrintEdge(Node* from, int index, Node* to) {
480 if (first_edge_) {
481 first_edge_ = false;
482 } else {
483 os_ << ",\n";
484 }
485 const char* edge_type = nullptr;
486 if (index < NodeProperties::FirstValueIndex(from)) {
487 edge_type = "unknown";
488 } else if (index < NodeProperties::FirstContextIndex(from)) {
489 edge_type = "value";
490 } else if (index < NodeProperties::FirstFrameStateIndex(from)) {
491 edge_type = "context";
492 } else if (index < NodeProperties::FirstEffectIndex(from)) {
493 edge_type = "frame-state";
494 } else if (index < NodeProperties::FirstControlIndex(from)) {
495 edge_type = "effect";
496 } else {
497 edge_type = "control";
498 }
499 os_ << "{\"source\":" << SafeId(to) << ",\"target\":" << SafeId(from)
500 << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}";
501}
502
503std::optional<Type> JSONGraphWriter::GetType(Node* node) {
504 if (!NodeProperties::IsTyped(node)) return std::nullopt;
505 return NodeProperties::GetType(node);
506}
507
508std::ostream& operator<<(std::ostream& os, const GraphAsJSON& ad) {
509 JSONGraphWriter writer(os, &ad.graph, ad.positions, ad.origins);
510 writer.Print();
511 return os;
512}
513
515 public:
516 GraphC1Visualizer(std::ostream& os, Zone* zone);
519
521 void PrintSchedule(const char* phase, const Schedule* schedule,
522 const SourcePositionTable* positions,
523 const InstructionSequence* instructions);
524 void PrintLiveRanges(const char* phase, const RegisterAllocationData* data);
525 Zone* zone() const { return zone_; }
526
527 private:
528 void PrintIndent();
529 void PrintStringProperty(const char* name, const char* value);
530 void PrintLongProperty(const char* name, int64_t value);
531 void PrintIntProperty(const char* name, int value);
532 void PrintBlockProperty(const char* name, int rpo_number);
533 void PrintNodeId(Node* n);
534 void PrintNode(Node* n);
535 void PrintInputs(Node* n);
536 template <typename InputIterator>
537 void PrintInputs(InputIterator* i, int count, const char* prefix);
538 void PrintType(Node* node);
539
540 void PrintLiveRange(const LiveRange* range, const char* type, int vreg);
541 void PrintLiveRangeChain(const TopLevelLiveRange* range, const char* type);
542
543 class Tag final {
544 public:
545 Tag(GraphC1Visualizer* visualizer, const char* name) {
546 name_ = name;
547 visualizer_ = visualizer;
548 visualizer->PrintIndent();
549 visualizer_->os_ << "begin_" << name << "\n";
550 visualizer->indent_++;
551 }
552
556 visualizer_->os_ << "end_" << name_ << "\n";
558 }
559
560 private:
562 const char* name_;
563 };
564
565 std::ostream& os_;
568};
569
571 for (int i = 0; i < indent_; i++) {
572 os_ << " ";
573 }
574}
575
577 : os_(os), indent_(0), zone_(zone) {}
578
580 const char* value) {
581 PrintIndent();
582 os_ << name << " \"" << value << "\"\n";
583}
584
585void GraphC1Visualizer::PrintLongProperty(const char* name, int64_t value) {
586 PrintIndent();
587 os_ << name << " " << static_cast<int>(value / 1000) << "\n";
588}
589
590void GraphC1Visualizer::PrintBlockProperty(const char* name, int rpo_number) {
591 PrintIndent();
592 os_ << name << " \"B" << rpo_number << "\"\n";
593}
594
595void GraphC1Visualizer::PrintIntProperty(const char* name, int value) {
596 PrintIndent();
597 os_ << name << " " << value << "\n";
598}
599
601 Tag tag(this, "compilation");
602 std::unique_ptr<char[]> name = info->GetDebugName();
603 if (info->IsOptimizing()) {
604 PrintStringProperty("name", name.get());
605 PrintIndent();
606 os_ << "method \"" << name.get() << ":" << info->optimization_id()
607 << "\"\n";
608 } else {
609 PrintStringProperty("name", name.get());
610 PrintStringProperty("method", "stub");
611 }
612 PrintLongProperty("date",
613 V8::GetCurrentPlatform()->CurrentClockTimeMilliseconds());
614}
615
617
619 PrintNodeId(n);
620 os_ << " " << *n->op() << " ";
621 PrintInputs(n);
622}
623
624template <typename InputIterator>
625void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
626 const char* prefix) {
627 if (count > 0) {
628 os_ << prefix;
629 }
630 while (count > 0) {
631 os_ << " ";
632 PrintNodeId(**i);
633 ++(*i);
634 count--;
635 }
636}
637
639 auto i = node->inputs().begin();
640 PrintInputs(&i, node->op()->ValueInputCount(), " ");
642 " Ctx:");
644 " FS:");
645 PrintInputs(&i, node->op()->EffectInputCount(), " Eff:");
646 PrintInputs(&i, node->op()->ControlInputCount(), " Ctrl:");
647}
648
650 if (NodeProperties::IsTyped(node)) {
651 Type type = NodeProperties::GetType(node);
652 os_ << " type:" << type;
653 }
654}
655
656void GraphC1Visualizer::PrintSchedule(const char* phase,
657 const Schedule* schedule,
658 const SourcePositionTable* positions,
659 const InstructionSequence* instructions) {
660 Tag tag(this, "cfg");
661 PrintStringProperty("name", phase);
662 const BasicBlockVector* rpo = schedule->rpo_order();
663 for (size_t i = 0; i < rpo->size(); i++) {
664 BasicBlock* current = (*rpo)[i];
665 Tag block_tag(this, "block");
666 PrintBlockProperty("name", current->rpo_number());
667 PrintIntProperty("from_bci", -1);
668 PrintIntProperty("to_bci", -1);
669
670 PrintIndent();
671 os_ << "predecessors";
672 for (BasicBlock* predecessor : current->predecessors()) {
673 os_ << " \"B" << predecessor->rpo_number() << "\"";
674 }
675 os_ << "\n";
676
677 PrintIndent();
678 os_ << "successors";
679 for (BasicBlock* successor : current->successors()) {
680 os_ << " \"B" << successor->rpo_number() << "\"";
681 }
682 os_ << "\n";
683
684 PrintIndent();
685 os_ << "xhandlers\n";
686
687 PrintIndent();
688 os_ << "flags\n";
689
690 if (current->dominator() != nullptr) {
691 PrintBlockProperty("dominator", current->dominator()->rpo_number());
692 }
693
694 PrintIntProperty("loop_depth", current->loop_depth());
695
696 const InstructionBlock* instruction_block =
697 instructions->InstructionBlockAt(
698 RpoNumber::FromInt(current->rpo_number()));
699 if (instruction_block->code_start() >= 0) {
700 int first_index = instruction_block->first_instruction_index();
701 int last_index = instruction_block->last_instruction_index();
703 "first_lir_id",
706 "last_lir_id",
708 .value());
709 }
710
711 {
712 Tag states_tag(this, "states");
713 Tag locals_tag(this, "locals");
714 int total = 0;
715 for (BasicBlock::const_iterator it = current->begin();
716 it != current->end(); ++it) {
717 if ((*it)->opcode() == IrOpcode::kPhi) total++;
718 }
719 PrintIntProperty("size", total);
720 PrintStringProperty("method", "None");
721 int index = 0;
722 for (BasicBlock::const_iterator it = current->begin();
723 it != current->end(); ++it) {
724 if ((*it)->opcode() != IrOpcode::kPhi) continue;
725 PrintIndent();
726 os_ << index << " ";
727 PrintNodeId(*it);
728 os_ << " [";
729 PrintInputs(*it);
730 os_ << "]\n";
731 index++;
732 }
733 }
734
735 {
736 Tag HIR_tag(this, "HIR");
737 for (BasicBlock::const_iterator it = current->begin();
738 it != current->end(); ++it) {
739 Node* node = *it;
740 if (node->opcode() == IrOpcode::kPhi) continue;
741 int uses = node->UseCount();
742 PrintIndent();
743 os_ << "0 " << uses << " ";
744 PrintNode(node);
745 if (v8_flags.trace_turbo_types) {
746 os_ << " ";
747 PrintType(node);
748 }
749 if (positions != nullptr) {
750 SourcePosition position = positions->GetSourcePosition(node);
751 if (position.IsKnown()) {
752 os_ << " pos:";
753 if (position.isInlined()) {
754 os_ << "inlining(" << position.InliningId() << "),";
755 }
756 os_ << position.ScriptOffset();
757 }
758 }
759 os_ << " <|@\n";
760 }
761
762 BasicBlock::Control control = current->control();
763 if (control != BasicBlock::kNone) {
764 PrintIndent();
765 os_ << "0 0 ";
766 if (current->control_input() != nullptr) {
767 PrintNode(current->control_input());
768 } else {
769 os_ << -1 - current->rpo_number() << " Goto";
770 }
771 os_ << " ->";
772 for (BasicBlock* successor : current->successors()) {
773 os_ << " B" << successor->rpo_number();
774 }
775 if (v8_flags.trace_turbo_types && current->control_input() != nullptr) {
776 os_ << " ";
777 PrintType(current->control_input());
778 }
779 os_ << " <|@\n";
780 }
781 }
782
783 if (instructions != nullptr) {
784 Tag LIR_tag(this, "LIR");
785 for (int j = instruction_block->first_instruction_index();
786 j <= instruction_block->last_instruction_index(); j++) {
787 PrintIndent();
788 os_ << j << " " << *instructions->InstructionAt(j) << " <|@\n";
789 }
790 }
791 }
792}
793
795 const RegisterAllocationData* data) {
796 Tag tag(this, "intervals");
797 PrintStringProperty("name", phase);
798
799 for (const TopLevelLiveRange* range : data->fixed_double_live_ranges()) {
800 PrintLiveRangeChain(range, "fixed");
801 }
802
803 for (const TopLevelLiveRange* range : data->fixed_live_ranges()) {
804 PrintLiveRangeChain(range, "fixed");
805 }
806
807 for (const TopLevelLiveRange* range : data->live_ranges()) {
808 PrintLiveRangeChain(range, "object");
809 }
810}
811
813 const char* type) {
814 if (range == nullptr || range->IsEmpty()) return;
815 int vreg = range->vreg();
816 for (const LiveRange* child = range; child != nullptr;
817 child = child->next()) {
818 PrintLiveRange(child, type, vreg);
819 }
820}
821
822void GraphC1Visualizer::PrintLiveRange(const LiveRange* range, const char* type,
823 int vreg) {
824 if (range != nullptr && !range->IsEmpty()) {
825 PrintIndent();
826 os_ << vreg << ":" << range->relative_id() << " " << type;
827 if (range->HasRegisterAssigned()) {
828 AllocatedOperand op = AllocatedOperand::cast(range->GetAssignedOperand());
829 if (op.IsRegister()) {
830 os_ << " \"" << Register::from_code(op.register_code()) << "\"";
831 } else if (op.IsDoubleRegister()) {
832 os_ << " \"" << DoubleRegister::from_code(op.register_code()) << "\"";
833 } else if (op.IsFloatRegister()) {
834 os_ << " \"" << FloatRegister::from_code(op.register_code()) << "\"";
835#if defined(V8_TARGET_ARCH_X64)
836 } else if (op.IsSimd256Register()) {
837 os_ << " \"" << Simd256Register::from_code(op.register_code()) << "\"";
838#endif
839 } else {
841 os_ << " \"" << Simd128Register::from_code(op.register_code()) << "\"";
842 }
843 } else if (range->spilled()) {
844 const TopLevelLiveRange* top = range->TopLevel();
845 int index = -1;
846 if (top->HasSpillRange()) {
847 index = kMaxInt; // This hasn't been set yet.
848 } else if (top->GetSpillOperand()->IsConstant()) {
849 os_ << " \"const(nostack):"
850 << ConstantOperand::cast(top->GetSpillOperand())->virtual_register()
851 << "\"";
852 } else {
853 index = AllocatedOperand::cast(top->GetSpillOperand())->index();
854 if (IsFloatingPoint(top->representation())) {
855 os_ << " \"fp_stack:" << index << "\"";
856 } else {
857 os_ << " \"stack:" << index << "\"";
858 }
859 }
860 }
861
862 const TopLevelLiveRange* parent = range->TopLevel();
863 os_ << " " << parent->vreg() << ":" << parent->relative_id();
864
865 // TODO(herhut) Find something useful to print for the hint field
866 if (parent->get_bundle() != nullptr) {
867 os_ << " B" << parent->get_bundle()->id();
868 } else {
869 os_ << " unknown";
870 }
871
872 for (const UseInterval& interval : range->intervals()) {
873 os_ << " [" << interval.start().value() << ", " << interval.end().value()
874 << "[";
875 }
876
877 for (const UsePosition* pos : range->positions()) {
878 if (pos->RegisterIsBeneficial() || v8_flags.trace_all_uses) {
879 os_ << " " << pos->pos().value() << " M";
880 }
881 }
882
883 os_ << " \"\"\n";
884 }
885}
886
887std::ostream& operator<<(std::ostream& os, const AsC1VCompilation& ac) {
888 AccountingAllocator allocator;
889 Zone tmp_zone(&allocator, ZONE_NAME);
890 GraphC1Visualizer(os, &tmp_zone).PrintCompilation(ac.info_);
891 return os;
892}
893
894std::ostream& operator<<(std::ostream& os, const AsC1V& ac) {
895 AccountingAllocator allocator;
896 Zone tmp_zone(&allocator, ZONE_NAME);
897 GraphC1Visualizer(os, &tmp_zone)
899 return os;
900}
901
902std::ostream& operator<<(std::ostream& os,
903 const AsC1VRegisterAllocationData& ac) {
904 AccountingAllocator allocator;
905 Zone tmp_zone(&allocator, ZONE_NAME);
906 GraphC1Visualizer(os, &tmp_zone).PrintLiveRanges(ac.phase_, ac.data_);
907 return os;
908}
909
910const int kUnvisited = 0;
911const int kOnStack = 1;
912const int kVisited = 2;
913
914std::ostream& operator<<(std::ostream& os, const AsRPO& ar) {
915 AccountingAllocator allocator;
916 Zone local_zone(&allocator, ZONE_NAME);
917
918 // Do a post-order depth-first search on the RPO graph. For every node,
919 // print:
920 //
921 // - the node id
922 // - the operator mnemonic
923 // - in square brackets its parameter (if present)
924 // - in parentheses the list of argument ids and their mnemonics
925 // - the node type (if it is typed)
926
927 // Post-order guarantees that all inputs of a node will be printed before
928 // the node itself, if there are no cycles. Any cycles are broken
929 // arbitrarily.
930
931 ZoneVector<uint8_t> state(ar.graph.NodeCount(), kUnvisited, &local_zone);
932 ZoneStack<Node*> stack(&local_zone);
933
934 stack.push(ar.graph.end());
935 state[ar.graph.end()->id()] = kOnStack;
936 while (!stack.empty()) {
937 Node* n = stack.top();
938 bool pop = true;
939 for (Node* const i : n->inputs()) {
940 if (state[i->id()] == kUnvisited) {
941 state[i->id()] = kOnStack;
942 stack.push(i);
943 pop = false;
944 break;
945 }
946 }
947 if (pop) {
948 state[n->id()] = kVisited;
949 stack.pop();
950 os << "#" << n->id() << ":" << *n->op() << "(";
951 // Print the inputs.
952 int j = 0;
953 for (Node* const i : n->inputs()) {
954 if (j++ > 0) os << ", ";
955 os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
956 }
957 os << ")";
958 // Print the node type, if any.
960 os << " [Type: " << NodeProperties::GetType(n) << "]";
961 }
962 os << std::endl;
963 }
964 }
965 return os;
966}
967
968namespace {
969
970void PrintIndent(std::ostream& os, int indent) {
971 os << " ";
972 for (int i = 0; i < indent; i++) {
973 os << ". ";
974 }
975}
976
977void PrintScheduledNode(std::ostream& os, int indent, Node* n) {
978 PrintIndent(os, indent);
979 os << "#" << n->id() << ":" << *n->op() << "(";
980 // Print the inputs.
981 int j = 0;
982 for (Node* const i : n->inputs()) {
983 if (j++ > 0) os << ", ";
984 os << "#" << SafeId(i) << ":" << SafeMnemonic(i);
985 }
986 os << ")";
987 // Print the node type, if any.
989 os << " [Type: " << NodeProperties::GetType(n) << "]";
990 }
991}
992
993void PrintScheduledGraph(std::ostream& os, const Schedule* schedule) {
994 const BasicBlockVector* rpo = schedule->rpo_order();
995 for (size_t i = 0; i < rpo->size(); i++) {
996 BasicBlock* current = (*rpo)[i];
997 int indent = current->loop_depth();
998
999 os << " + Block B" << current->rpo_number() << " (pred:";
1000 for (BasicBlock* predecessor : current->predecessors()) {
1001 os << " B" << predecessor->rpo_number();
1002 }
1003 if (current->IsLoopHeader()) {
1004 os << ", loop until B" << current->loop_end()->rpo_number();
1005 } else if (current->loop_header()) {
1006 os << ", in loop B" << current->loop_header()->rpo_number();
1007 }
1008 os << ")" << std::endl;
1009
1010 for (BasicBlock::const_iterator it = current->begin(); it != current->end();
1011 ++it) {
1012 Node* node = *it;
1013 PrintScheduledNode(os, indent, node);
1014 os << std::endl;
1015 }
1016
1017 if (current->SuccessorCount() > 0) {
1018 if (current->control_input() != nullptr) {
1019 PrintScheduledNode(os, indent, current->control_input());
1020 } else {
1021 PrintIndent(os, indent);
1022 os << "Goto";
1023 }
1024 os << " ->";
1025
1026 bool isFirst = true;
1027 for (BasicBlock* successor : current->successors()) {
1028 if (isFirst) {
1029 isFirst = false;
1030 } else {
1031 os << ",";
1032 }
1033 os << " B" << successor->rpo_number();
1034 }
1035 os << std::endl;
1036 } else {
1037 DCHECK_NULL(current->control_input());
1038 }
1039 }
1040}
1041
1042} // namespace
1043
1044std::ostream& operator<<(std::ostream& os,
1045 const LiveRangeAsJSON& live_range_json) {
1046 const LiveRange& range = live_range_json.range_;
1047 os << "{\"id\":" << range.relative_id() << ",\"type\":";
1048 if (range.HasRegisterAssigned()) {
1049 const InstructionOperand op = range.GetAssignedOperand();
1050 os << "\"assigned\",\"op\":"
1051 << InstructionOperandAsJSON{&op, &(live_range_json.code_)};
1052 } else if (range.spilled() && !range.TopLevel()->HasNoSpillType()) {
1053 const TopLevelLiveRange* top = range.TopLevel();
1054 if (top->HasSpillOperand()) {
1055 os << "\"assigned\",\"op\":"
1056 << InstructionOperandAsJSON{top->GetSpillOperand(),
1057 &(live_range_json.code_)};
1058 } else {
1059 int index = top->GetSpillRange()->assigned_slot();
1060 os << "\"spilled\",\"op\":";
1061 if (IsFloatingPoint(top->representation())) {
1062 os << "\"fp_stack:" << index << "\"";
1063 } else {
1064 os << "\"stack:" << index << "\"";
1065 }
1066 }
1067 } else {
1068 os << "\"none\"";
1069 }
1070
1071 os << ",\"intervals\":[";
1072 bool first = true;
1073 for (const UseInterval& interval : range.intervals()) {
1074 if (first) {
1075 first = false;
1076 } else {
1077 os << ",";
1078 }
1079 os << "[" << interval.start().value() << "," << interval.end().value()
1080 << "]";
1081 }
1082
1083 os << "],\"uses\":[";
1084 first = true;
1085 for (const UsePosition* pos : range.positions()) {
1086 if (first) {
1087 first = false;
1088 } else {
1089 os << ",";
1090 }
1091 os << pos->pos().value();
1092 }
1093
1094 os << "]}";
1095 return os;
1096}
1097
1098std::ostream& operator<<(
1099 std::ostream& os,
1100 const TopLevelLiveRangeAsJSON& top_level_live_range_json) {
1101 int vreg = top_level_live_range_json.range_.vreg();
1102 bool first = true;
1103 int instruction_range[2] = {INT32_MAX, -1};
1104 os << "\"" << (vreg > 0 ? vreg : -vreg) << "\":{ \"child_ranges\":[";
1105 for (const LiveRange* child = &(top_level_live_range_json.range_);
1106 child != nullptr; child = child->next()) {
1107 if (!top_level_live_range_json.range_.IsEmpty()) {
1108 if (first) {
1109 first = false;
1110 } else {
1111 os << ",";
1112 }
1113 os << LiveRangeAsJSON{*child, top_level_live_range_json.code_};
1114 // Record the minimum and maximum positions observed within this
1115 // TopLevelLiveRange
1116 for (const UseInterval& interval : child->intervals()) {
1117 if (interval.start().value() < instruction_range[0])
1118 instruction_range[0] = interval.start().value();
1119 if (interval.end().value() > instruction_range[1])
1120 instruction_range[1] = interval.end().value();
1121 }
1122 }
1123 }
1124 os << "]";
1125 if (top_level_live_range_json.range_.IsFixed()) {
1126 os << ", \"is_deferred\": "
1127 << (top_level_live_range_json.range_.IsDeferredFixed() ? "true"
1128 : "false");
1129 }
1130 os << ", \"instruction_range\": [" << instruction_range[0] << ","
1131 << instruction_range[1] << "]}";
1132 return os;
1133}
1134
1135void PrintTopLevelLiveRanges(std::ostream& os,
1136 const ZoneVector<TopLevelLiveRange*> ranges,
1137 const InstructionSequence& code) {
1138 bool first = true;
1139 os << "{";
1140 for (const TopLevelLiveRange* range : ranges) {
1141 if (range != nullptr && !range->IsEmpty()) {
1142 if (first) {
1143 first = false;
1144 } else {
1145 os << ",";
1146 }
1147 os << TopLevelLiveRangeAsJSON{*range, code};
1148 }
1149 }
1150 os << "}";
1151}
1152
1153std::ostream& operator<<(std::ostream& os,
1154 const RegisterAllocationDataAsJSON& ac) {
1155 os << "\"fixed_double_live_ranges\": ";
1156 PrintTopLevelLiveRanges(os, ac.data_.fixed_double_live_ranges(), ac.code_);
1157 os << ",\"fixed_live_ranges\": ";
1158 PrintTopLevelLiveRanges(os, ac.data_.fixed_live_ranges(), ac.code_);
1159 os << ",\"live_ranges\": ";
1160 PrintTopLevelLiveRanges(os, ac.data_.live_ranges(), ac.code_);
1161 return os;
1162}
1163
1164std::ostream& operator<<(std::ostream& os, const AsScheduledGraph& scheduled) {
1165 PrintScheduledGraph(os, scheduled.schedule);
1166 return os;
1167}
1168
1169std::ostream& operator<<(std::ostream& os, const InstructionOperandAsJSON& o) {
1170 const InstructionOperand* op = o.op_;
1171 const InstructionSequence* code = o.code_;
1172 os << "{";
1173 switch (op->kind()) {
1175 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(op);
1176 os << "\"type\": \"unallocated\", ";
1177 os << "\"text\": \"v" << unalloc->virtual_register() << "\"";
1178 if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
1179 os << ",\"tooltip\": \"FIXED_SLOT: " << unalloc->fixed_slot_index()
1180 << "\"";
1181 break;
1182 }
1183 switch (unalloc->extended_policy()) {
1185 break;
1187 os << ",\"tooltip\": \"FIXED_REGISTER: "
1188 << Register::from_code(unalloc->fixed_register_index()) << "\"";
1189 break;
1190 }
1192 os << ",\"tooltip\": \"FIXED_FP_REGISTER: "
1194 << "\"";
1195 break;
1196 }
1198 os << ",\"tooltip\": \"MUST_HAVE_REGISTER\"";
1199 break;
1200 }
1202 os << ",\"tooltip\": \"MUST_HAVE_SLOT\"";
1203 break;
1204 }
1206 os << ",\"tooltip\": \"SAME_AS_INPUT: " << unalloc->input_index()
1207 << "\"";
1208 break;
1209 }
1211 os << ",\"tooltip\": \"REGISTER_OR_SLOT\"";
1212 break;
1213 }
1215 os << ",\"tooltip\": \"REGISTER_OR_SLOT_OR_CONSTANT\"";
1216 break;
1217 }
1218 }
1219 break;
1220 }
1222 int vreg = ConstantOperand::cast(op)->virtual_register();
1223 os << "\"type\": \"constant\", ";
1224 os << "\"text\": \"v" << vreg << "\",";
1225 os << "\"tooltip\": \"";
1226 std::stringstream tooltip;
1227 tooltip << code->GetConstant(vreg);
1228 for (const auto& c : tooltip.str()) {
1229 os << AsEscapedUC16ForJSON(c);
1230 }
1231 os << "\"";
1232 break;
1233 }
1235 os << "\"type\": \"immediate\", ";
1236 const ImmediateOperand* imm = ImmediateOperand::cast(op);
1237 switch (imm->type()) {
1239 os << "\"text\": \"#" << imm->inline_int32_value() << "\"";
1240 break;
1241 }
1243 os << "\"text\": \"#" << imm->inline_int64_value() << "\"";
1244 break;
1245 }
1248 int index = imm->indexed_value();
1249 os << "\"text\": \"imm:" << index << "\",";
1250 os << "\"tooltip\": \"";
1251 std::stringstream tooltip;
1252 tooltip << code->GetImmediate(imm);
1253 for (const auto& c : tooltip.str()) {
1254 os << AsEscapedUC16ForJSON(c);
1255 }
1256 os << "\"";
1257 break;
1258 }
1259 }
1260 break;
1261 }
1263 const LocationOperand* allocated = LocationOperand::cast(op);
1264 os << "\"type\": \"allocated\", ";
1265 os << "\"text\": \"";
1266 if (op->IsStackSlot()) {
1267 os << "stack:" << allocated->index();
1268 } else if (op->IsFPStackSlot()) {
1269 os << "fp_stack:" << allocated->index();
1270 } else if (op->IsRegister()) {
1271 if (allocated->register_code() < Register::kNumRegisters) {
1272 os << Register::from_code(allocated->register_code());
1273 } else {
1274 os << Register::GetSpecialRegisterName(allocated->register_code());
1275 }
1276 } else if (op->IsDoubleRegister()) {
1277 os << DoubleRegister::from_code(allocated->register_code());
1278 } else if (op->IsFloatRegister()) {
1279 os << FloatRegister::from_code(allocated->register_code());
1280#if defined(V8_TARGET_ARCH_X64)
1281 } else if (op->IsSimd256Register()) {
1282 os << Simd256Register::from_code(allocated->register_code());
1283#endif
1284 } else {
1286 os << Simd128Register::from_code(allocated->register_code());
1287 }
1288 os << "\",";
1289 os << "\"tooltip\": \""
1290 << MachineReprToString(allocated->representation()) << "\"";
1291 break;
1292 }
1295 UNREACHABLE();
1296 }
1297 os << "}";
1298 return os;
1299}
1300
1301std::ostream& operator<<(std::ostream& os, const InstructionAsJSON& i_json) {
1302 const Instruction* instr = i_json.instr_;
1303
1304 os << "{";
1305 os << "\"id\": " << i_json.index_ << ",";
1306 os << "\"opcode\": \"" << ArchOpcodeField::decode(instr->opcode()) << "\",";
1307 os << "\"flags\": \"";
1310 if (am != kMode_None) {
1311 os << " : " << AddressingModeField::decode(instr->opcode());
1312 }
1313 if (fm != kFlags_none) {
1314 os << " && " << fm << " if "
1316 }
1317 os << "\",";
1318
1319 os << "\"gaps\": [";
1322 if (i != Instruction::FIRST_GAP_POSITION) os << ",";
1323 os << "[";
1324 const ParallelMove* pm = instr->parallel_moves()[i];
1325 if (pm == nullptr) {
1326 os << "]";
1327 continue;
1328 }
1329 bool first = true;
1330 for (MoveOperands* move : *pm) {
1331 if (move->IsEliminated()) continue;
1332 if (first) {
1333 first = false;
1334 } else {
1335 os << ",";
1336 }
1337 os << "[" << InstructionOperandAsJSON{&move->destination(), i_json.code_}
1338 << "," << InstructionOperandAsJSON{&move->source(), i_json.code_}
1339 << "]";
1340 }
1341 os << "]";
1342 }
1343 os << "],";
1344
1345 os << "\"outputs\": [";
1346 bool need_comma = false;
1347 for (size_t i = 0; i < instr->OutputCount(); i++) {
1348 if (need_comma) os << ",";
1349 need_comma = true;
1351 }
1352 os << "],";
1353
1354 os << "\"inputs\": [";
1355 need_comma = false;
1356 for (size_t i = 0; i < instr->InputCount(); i++) {
1357 if (need_comma) os << ",";
1358 need_comma = true;
1359 os << InstructionOperandAsJSON{instr->InputAt(i), i_json.code_};
1360 }
1361 os << "],";
1362
1363 os << "\"temps\": [";
1364 need_comma = false;
1365 for (size_t i = 0; i < instr->TempCount(); i++) {
1366 if (need_comma) os << ",";
1367 need_comma = true;
1368 os << InstructionOperandAsJSON{instr->TempAt(i), i_json.code_};
1369 }
1370 os << "]";
1371 os << "}";
1372
1373 return os;
1374}
1375
1376std::ostream& operator<<(std::ostream& os, const InstructionBlockAsJSON& b) {
1377 const InstructionBlock* block = b.block_;
1378 const InstructionSequence* code = b.code_;
1379 os << "{";
1380 os << "\"id\": " << block->rpo_number() << ",";
1381 os << "\"deferred\": " << (block->IsDeferred() ? "true" : "false");
1382 os << ",";
1383 os << "\"loop_header\": " << block->IsLoopHeader() << ",";
1384 if (block->IsLoopHeader()) {
1385 os << "\"loop_end\": " << block->loop_end() << ",";
1386 }
1387 os << "\"predecessors\": [";
1388 bool need_comma = false;
1389 for (RpoNumber pred : block->predecessors()) {
1390 if (need_comma) os << ",";
1391 need_comma = true;
1392 os << pred.ToInt();
1393 }
1394 os << "],";
1395 os << "\"successors\": [";
1396 need_comma = false;
1397 for (RpoNumber succ : block->successors()) {
1398 if (need_comma) os << ",";
1399 need_comma = true;
1400 os << succ.ToInt();
1401 }
1402 os << "],";
1403 os << "\"phis\": [";
1404 bool needs_comma = false;
1405 InstructionOperandAsJSON json_op = {nullptr, code};
1406 for (const PhiInstruction* phi : block->phis()) {
1407 if (needs_comma) os << ",";
1408 needs_comma = true;
1409 json_op.op_ = &phi->output();
1410 os << "{\"output\" : " << json_op << ",";
1411 os << "\"operands\": [";
1412 bool op_needs_comma = false;
1413 for (int input : phi->operands()) {
1414 if (op_needs_comma) os << ",";
1415 op_needs_comma = true;
1416 os << "\"v" << input << "\"";
1417 }
1418 os << "]}";
1419 }
1420 os << "],";
1421
1422 os << "\"instructions\": [";
1423 InstructionAsJSON json_instr = {-1, nullptr, code};
1424 need_comma = false;
1425 for (int j = block->first_instruction_index();
1426 j <= block->last_instruction_index(); j++) {
1427 if (need_comma) os << ",";
1428 need_comma = true;
1429 json_instr.index_ = j;
1430 json_instr.instr_ = code->InstructionAt(j);
1431 os << json_instr;
1432 }
1433 os << "]";
1434 os << "}";
1435
1436 return os;
1437}
1438
1439std::ostream& operator<<(std::ostream& os, const InstructionSequenceAsJSON& s) {
1440 const InstructionSequence* code = s.sequence_;
1441
1442 os << "[";
1443
1444 bool need_comma = false;
1445 for (int i = 0; i < code->InstructionBlockCount(); i++) {
1446 if (need_comma) os << ",";
1447 need_comma = true;
1449 code->InstructionBlockAt(RpoNumber::FromInt(i)), code};
1450 }
1451 os << "]";
1452
1453 return os;
1454}
1455
1456} // namespace compiler
1457} // namespace internal
1458} // namespace v8
Schedule * schedule
SourcePosition pos
static constexpr T decode(U value)
Definition bit-field.h:66
static char DirectorySeparator()
int length() const
Definition vector.h:64
constexpr T * begin() const
Definition vector.h:96
static constexpr DwVfpRegister from_code(int8_t code)
static constexpr Register from_code(int code)
static const char * GetSpecialRegisterName(int code)
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
static V8_EXPORT_PRIVATE v8::Platform * GetCurrentPlatform()
Definition v8.cc:282
static constexpr YMMRegister from_code(int code)
NodeVector::const_iterator const_iterator
Definition schedule.h:105
BasicBlockVector & successors()
Definition schedule.h:82
BasicBlockVector & predecessors()
Definition schedule.h:73
Tag(GraphC1Visualizer *visualizer, const char *name)
void PrintIntProperty(const char *name, int value)
GraphC1Visualizer & operator=(const GraphC1Visualizer &)=delete
void PrintBlockProperty(const char *name, int rpo_number)
void PrintCompilation(const OptimizedCompilationInfo *info)
void PrintLiveRange(const LiveRange *range, const char *type, int vreg)
void PrintSchedule(const char *phase, const Schedule *schedule, const SourcePositionTable *positions, const InstructionSequence *instructions)
void PrintStringProperty(const char *name, const char *value)
void PrintLiveRanges(const char *phase, const RegisterAllocationData *data)
GraphC1Visualizer(const GraphC1Visualizer &)=delete
void PrintLiveRangeChain(const TopLevelLiveRange *range, const char *type)
void PrintLongProperty(const char *name, int64_t value)
const InstructionOperand * OutputAt(size_t i) const
InstructionCode opcode() const
const InstructionOperand * InputAt(size_t i) const
ParallelMove *const * parallel_moves() const
const InstructionOperand * TempAt(size_t i) const
static char const * Mnemonic(Value value)
Definition opcodes.cc:28
static bool IsPhiOpcode(Value value)
Definition opcodes.h:1400
JSONGraphWriter(std::ostream &os, const TFGraph *graph, const SourcePositionTable *positions, const NodeOriginTable *origins)
virtual std::optional< Type > GetType(Node *node)
void PrintEdge(Node *from, int index, Node *to)
static LifetimePosition InstructionFromInstructionIndex(int index)
static LifetimePosition GapFromInstructionIndex(int index)
static LocationOperand * cast(InstructionOperand *op)
static Type GetType(const Node *node)
static bool IsTyped(const Node *node)
static int FirstFrameStateIndex(Node *node)
static int FirstValueIndex(const Node *node)
Node * InputAt(int index) const
Definition node.h:70
static int GetContextInputCount(const Operator *op)
static int GetFrameStateInputCount(const Operator *op)
static RpoNumber FromInt(int index)
BasicBlockVector * rpo_order()
Definition schedule.h:280
int GetIdFor(Handle< SharedFunctionInfo > shared)
std::vector< Handle< SharedFunctionInfo > > printed_
const WasmModule * module() const
base::Vector< const uint8_t > wire_bytes() const
virtual std::optional< ModuleWireBytes > GetModuleBytes() const =0
virtual base::Vector< const uint8_t > GetCode(WireBytesRef) const =0
Zone * zone_
int start
int end
Label label
std::string filename
NodeOriginTable * origins
#define _
Instruction * instr
ZoneStack< RpoNumber > & stack
LiftoffAssembler::CacheState state
int position
Definition liveedit.cc:290
InstructionOperand source
STL namespace.
void JsonPrintBytecodeSource(std::ostream &os, int source_id, std::unique_ptr< char[]> function_name, DirectHandle< BytecodeArray > bytecode_array, Tagged< FeedbackVector > feedback_vector)
static const char * SafeMnemonic(Node *node)
void JsonPrintAllBytecodeSources(std::ostream &os, OptimizedCompilationInfo *info)
void JsonPrintAllSourceWithPositions(std::ostream &os, OptimizedCompilationInfo *info, Isolate *isolate)
void JsonPrintFunctionSource(std::ostream &os, int source_id, std::unique_ptr< char[]> function_name, DirectHandle< Script > script, Isolate *isolate, DirectHandle< SharedFunctionInfo > shared, bool with_key)
ZoneVector< BasicBlock * > BasicBlockVector
Definition schedule.h:23
std::unique_ptr< char[]> GetVisualizerLogFileName(OptimizedCompilationInfo *info, const char *optional_base_dir, const char *phase, const char *suffix)
V8_INLINE V8_EXPORT_PRIVATE SourcePositionAsJSON AsJSON(const SourcePosition &sp)
const char * get_cached_trace_turbo_filename(OptimizedCompilationInfo *info)
std::ostream & operator<<(std::ostream &os, AccessMode access_mode)
void PrintTopLevelLiveRanges(std::ostream &os, const ZoneVector< TopLevelLiveRange * > ranges, const InstructionSequence &code)
void DisassembleFunction(const WasmModule *module, int func_index, base::Vector< const uint8_t > wire_bytes, NamesProvider *names, std::ostream &os)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
constexpr bool IsFloatingPoint(MachineRepresentation rep)
const char * MachineReprToString(MachineRepresentation rep)
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
constexpr int kMaxInt
Definition globals.h:374
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NULL(val)
Definition logging.h:491
#define DCHECK(condition)
Definition logging.h:482
std::ostream * os_
const SourcePositionTable * positions_
const InstructionSequence * instructions_
TurboJsonFile(OptimizedCompilationInfo *info, std::ios_base::openmode mode)
TFGraph * graph_
wasm::ValueType type
#define ZONE_NAME
Definition zone.h:22