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 #include <fstream>
18 #include <stdint.h>
19 
20 #include "builder.h"
21 #include "code_generator.h"
22 #include "compilers.h"
23 #include "driver/compiler_driver.h"
24 #include "driver/dex_compilation_unit.h"
25 #include "graph_visualizer.h"
26 #include "nodes.h"
27 #include "register_allocator.h"
28 #include "ssa_phi_elimination.h"
29 #include "ssa_liveness_analysis.h"
30 #include "utils/arena_allocator.h"
31 
32 namespace art {
33 
34 /**
35  * Used by the code generator, to allocate the code in a vector.
36  */
37 class CodeVectorAllocator FINAL : public CodeAllocator {
38  public:
CodeVectorAllocator()39   CodeVectorAllocator() { }
40 
Allocate(size_t size)41   virtual uint8_t* Allocate(size_t size) {
42     size_ = size;
43     memory_.resize(size);
44     return &memory_[0];
45   }
46 
GetSize() const47   size_t GetSize() const { return size_; }
GetMemory() const48   const std::vector<uint8_t>& GetMemory() const { return memory_; }
49 
50  private:
51   std::vector<uint8_t> memory_;
52   size_t size_;
53 
54   DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
55 };
56 
57 /**
58  * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
59  */
60 static bool kIsVisualizerEnabled = false;
61 
62 /**
63  * Filter to apply to the visualizer. Methods whose name contain that filter will
64  * be in the file.
65  */
66 static const char* kStringFilter = "";
67 
OptimizingCompiler(CompilerDriver * driver)68 OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) {
69   if (kIsVisualizerEnabled) {
70     visualizer_output_.reset(new std::ofstream("art.cfg"));
71   }
72 }
73 
TryCompile(const DexFile::CodeItem * code_item,uint32_t access_flags,InvokeType invoke_type,uint16_t class_def_idx,uint32_t method_idx,jobject class_loader,const DexFile & dex_file) const74 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
75                                                uint32_t access_flags,
76                                                InvokeType invoke_type,
77                                                uint16_t class_def_idx,
78                                                uint32_t method_idx,
79                                                jobject class_loader,
80                                                const DexFile& dex_file) const {
81   InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
82   // Always use the thumb2 assembler: some runtime functionality (like implicit stack
83   // overflow checks) assume thumb2.
84   if (instruction_set == kArm) {
85     instruction_set = kThumb2;
86   }
87 
88   // Do not attempt to compile on architectures we do not support.
89   if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) {
90     return nullptr;
91   }
92 
93   DexCompilationUnit dex_compilation_unit(
94     nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item,
95     class_def_idx, method_idx, access_flags,
96     GetCompilerDriver()->GetVerifiedMethod(&dex_file, method_idx));
97 
98   // For testing purposes, we put a special marker on method names that should be compiled
99   // with this compiler. This makes sure we're not regressing.
100   bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos;
101   bool shouldOptimize =
102       dex_compilation_unit.GetSymbol().find("00024reg_00024") != std::string::npos;
103 
104   ArenaPool pool;
105   ArenaAllocator arena(&pool);
106   HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file, GetCompilerDriver());
107 
108   HGraph* graph = builder.BuildGraph(*code_item);
109   if (graph == nullptr) {
110     if (shouldCompile) {
111       LOG(FATAL) << "Could not build graph in optimizing compiler";
112     }
113     return nullptr;
114   }
115 
116   CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, instruction_set);
117   if (codegen == nullptr) {
118     if (shouldCompile) {
119       LOG(FATAL) << "Could not find code generator for optimizing compiler";
120     }
121     return nullptr;
122   }
123 
124   HGraphVisualizer visualizer(
125       visualizer_output_.get(), graph, kStringFilter, *codegen, dex_compilation_unit);
126   visualizer.DumpGraph("builder");
127 
128   CodeVectorAllocator allocator;
129 
130   if (RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
131     graph->BuildDominatorTree();
132     graph->TransformToSSA();
133     visualizer.DumpGraph("ssa");
134     graph->FindNaturalLoops();
135 
136     SsaRedundantPhiElimination(graph).Run();
137     SsaDeadPhiElimination(graph).Run();
138 
139     SsaLivenessAnalysis liveness(*graph, codegen);
140     liveness.Analyze();
141     visualizer.DumpGraph(kLivenessPassName);
142 
143     RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
144     register_allocator.AllocateRegisters();
145 
146     visualizer.DumpGraph(kRegisterAllocatorPassName);
147     codegen->CompileOptimized(&allocator);
148   } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
149     LOG(FATAL) << "Could not allocate registers in optimizing compiler";
150   } else {
151     codegen->CompileBaseline(&allocator);
152 
153     // Run these phases to get some test coverage.
154     graph->BuildDominatorTree();
155     graph->TransformToSSA();
156     visualizer.DumpGraph("ssa");
157     graph->FindNaturalLoops();
158     SsaLivenessAnalysis liveness(*graph, codegen);
159     liveness.Analyze();
160     visualizer.DumpGraph(kLivenessPassName);
161   }
162 
163   std::vector<uint8_t> mapping_table;
164   codegen->BuildMappingTable(&mapping_table);
165   std::vector<uint8_t> vmap_table;
166   codegen->BuildVMapTable(&vmap_table);
167   std::vector<uint8_t> gc_map;
168   codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
169 
170   return CompiledMethod::SwapAllocCompiledMethod(GetCompilerDriver(),
171                                                  instruction_set,
172                                                  ArrayRef<const uint8_t>(allocator.GetMemory()),
173                                                  codegen->GetFrameSize(),
174                                                  codegen->GetCoreSpillMask(),
175                                                  0, /* FPR spill mask, unused */
176                                                  ArrayRef<const uint8_t>(mapping_table),
177                                                  ArrayRef<const uint8_t>(vmap_table),
178                                                  ArrayRef<const uint8_t>(gc_map),
179                                                  ArrayRef<const uint8_t>());
180 }
181 
182 }  // namespace art
183