1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
18 #define ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
19 
20 #include <functional>
21 #include <ostream>
22 
23 #include "arch/instruction_set.h"
24 #include "base/arena_containers.h"
25 #include "base/value_object.h"
26 #include "block_namer.h"
27 
28 namespace art {
29 
30 class CodeGenerator;
31 class DexCompilationUnit;
32 class HGraph;
33 class HInstruction;
34 class SlowPathCode;
35 
36 /**
37  * This class outputs the HGraph in the C1visualizer format.
38  * Note: Currently only works if the compiler is single threaded.
39  */
40 struct GeneratedCodeInterval {
41   size_t start;
42   size_t end;
43 };
44 
45 struct SlowPathCodeInfo {
46   const SlowPathCode* slow_path;
47   GeneratedCodeInterval code_interval;
48 };
49 
50 // This information is filled by the code generator. It will be used by the
51 // graph visualizer to associate disassembly of the generated code with the
52 // instructions and slow paths. We assume that the generated code follows the
53 // following structure:
54 //   - frame entry
55 //   - instructions
56 //   - slow paths
57 class DisassemblyInformation {
58  public:
DisassemblyInformation(ArenaAllocator * allocator)59   explicit DisassemblyInformation(ArenaAllocator* allocator)
60       : frame_entry_interval_({0, 0}),
61         instruction_intervals_(std::less<const HInstruction*>(), allocator->Adapter()),
62         slow_path_intervals_(allocator->Adapter()) {}
63 
SetFrameEntryInterval(size_t start,size_t end)64   void SetFrameEntryInterval(size_t start, size_t end) {
65     frame_entry_interval_ = {start, end};
66   }
67 
AddInstructionInterval(HInstruction * instr,size_t start,size_t end)68   void AddInstructionInterval(HInstruction* instr, size_t start, size_t end) {
69     instruction_intervals_.Put(instr, {start, end});
70   }
71 
AddSlowPathInterval(SlowPathCode * slow_path,size_t start,size_t end)72   void AddSlowPathInterval(SlowPathCode* slow_path, size_t start, size_t end) {
73     slow_path_intervals_.push_back({slow_path, {start, end}});
74   }
75 
GetFrameEntryInterval()76   GeneratedCodeInterval GetFrameEntryInterval() const {
77     return frame_entry_interval_;
78   }
79 
GetFrameEntryInterval()80   GeneratedCodeInterval* GetFrameEntryInterval() {
81     return &frame_entry_interval_;
82   }
83 
GetInstructionIntervals()84   const ArenaSafeMap<const HInstruction*, GeneratedCodeInterval>& GetInstructionIntervals() const {
85     return instruction_intervals_;
86   }
87 
GetInstructionIntervals()88   ArenaSafeMap<const HInstruction*, GeneratedCodeInterval>* GetInstructionIntervals() {
89     return &instruction_intervals_;
90   }
91 
GetSlowPathIntervals()92   const ArenaVector<SlowPathCodeInfo>& GetSlowPathIntervals() const { return slow_path_intervals_; }
93 
GetSlowPathIntervals()94   ArenaVector<SlowPathCodeInfo>* GetSlowPathIntervals() { return &slow_path_intervals_; }
95 
96  private:
97   GeneratedCodeInterval frame_entry_interval_;
98   ArenaSafeMap<const HInstruction*, GeneratedCodeInterval> instruction_intervals_;
99   ArenaVector<SlowPathCodeInfo> slow_path_intervals_;
100 };
101 
102 class HGraphVisualizer : public ValueObject {
103  public:
104   HGraphVisualizer(std::ostream* output,
105                    HGraph* graph,
106                    const CodeGenerator* codegen,
107                    std::optional<std::reference_wrapper<const BlockNamer>> namer = std::nullopt);
108 
109   void PrintHeader(const char* method_name) const;
110   void DumpGraph(const char* pass_name, bool is_after_pass, bool graph_in_bad_state) const;
111   void DumpGraphDebug() const;
112   void DumpGraphWithDisassembly() const;
113 
114   // C1visualizer file format does not support inserting arbitrary metadata into a cfg
115   // file. As a workaround a fake compilation block with the metadata in the name and the
116   // method attributes is used. Such empty blocks don't break the c1visualizer parser.
117   static std::string InsertMetaDataAsCompilationBlock(const std::string& meta_data);
118 
119   static void DumpInstruction(std::ostream* output, HGraph* graph, HInstruction* instruction);
120 
121  private:
122   class OptionalDefaultNamer final : public BlockNamer {
123    public:
OptionalDefaultNamer(std::optional<std::reference_wrapper<const BlockNamer>> inner)124     explicit OptionalDefaultNamer(std::optional<std::reference_wrapper<const BlockNamer>> inner)
125         : namer_(inner) {}
126 
127     std::ostream& PrintName(std::ostream& os, HBasicBlock* blk) const override;
128 
129    private:
130     std::optional<std::reference_wrapper<const BlockNamer>> namer_;
131   };
132 
133   std::ostream* const output_;
134   HGraph* const graph_;
135   const CodeGenerator* codegen_;
136   OptionalDefaultNamer namer_;
137 
138   DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer);
139 };
140 
141 }  // namespace art
142 
143 #endif  // ART_COMPILER_OPTIMIZING_GRAPH_VISUALIZER_H_
144