/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_ #define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_ #include #include #include "arch/instruction_set.h" #include "base/arena_containers.h" #include "base/value_object.h" #include "block_namer.h" namespace art { class CodeGenerator; class DexCompilationUnit; class HGraph; class HInstruction; class SlowPathCode; /** * This class outputs the HGraph in the C1visualizer format. * Note: Currently only works if the compiler is single threaded. */ struct GeneratedCodeInterval { size_t start; size_t end; }; struct SlowPathCodeInfo { const SlowPathCode* slow_path; GeneratedCodeInterval code_interval; }; // This information is filled by the code generator. It will be used by the // graph visualizer to associate disassembly of the generated code with the // instructions and slow paths. We assume that the generated code follows the // following structure: // - frame entry // - instructions // - slow paths class DisassemblyInformation { public: explicit DisassemblyInformation(ArenaAllocator* allocator) : frame_entry_interval_({0, 0}), instruction_intervals_(std::less(), allocator->Adapter()), slow_path_intervals_(allocator->Adapter()) {} void SetFrameEntryInterval(size_t start, size_t end) { frame_entry_interval_ = {start, end}; } void AddInstructionInterval(HInstruction* instr, size_t start, size_t end) { instruction_intervals_.Put(instr, {start, end}); } void AddSlowPathInterval(SlowPathCode* slow_path, size_t start, size_t end) { slow_path_intervals_.push_back({slow_path, {start, end}}); } GeneratedCodeInterval GetFrameEntryInterval() const { return frame_entry_interval_; } GeneratedCodeInterval* GetFrameEntryInterval() { return &frame_entry_interval_; } const ArenaSafeMap& GetInstructionIntervals() const { return instruction_intervals_; } ArenaSafeMap* GetInstructionIntervals() { return &instruction_intervals_; } const ArenaVector& GetSlowPathIntervals() const { return slow_path_intervals_; } ArenaVector* GetSlowPathIntervals() { return &slow_path_intervals_; } private: GeneratedCodeInterval frame_entry_interval_; ArenaSafeMap instruction_intervals_; ArenaVector slow_path_intervals_; }; class HGraphVisualizer : public ValueObject { public: HGraphVisualizer(std::ostream* output, HGraph* graph, const CodeGenerator* codegen, std::optional> namer = std::nullopt); void PrintHeader(const char* method_name) const; void DumpGraph(const char* pass_name, bool is_after_pass, bool graph_in_bad_state) const; void DumpGraphDebug() const; void DumpGraphWithDisassembly() const; // C1visualizer file format does not support inserting arbitrary metadata into a cfg // file. As a workaround a fake compilation block with the metadata in the name and the // method attributes is used. Such empty blocks don't break the c1visualizer parser. static std::string InsertMetaDataAsCompilationBlock(const std::string& meta_data); static void DumpInstruction(std::ostream* output, HGraph* graph, HInstruction* instruction); private: class OptionalDefaultNamer final : public BlockNamer { public: explicit OptionalDefaultNamer(std::optional> inner) : namer_(inner) {} std::ostream& PrintName(std::ostream& os, HBasicBlock* blk) const override; private: std::optional> namer_; }; std::ostream* const output_; HGraph* const graph_; const CodeGenerator* codegen_; OptionalDefaultNamer namer_; DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer); }; } // namespace art #endif // ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_