optimizing_compiler.cc revision 26a25ef62a13f409f941aa39825a51b4d6f0f047
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 "optimizing_compiler.h" 18 19#include <fstream> 20#include <stdint.h> 21 22#include "builder.h" 23#include "code_generator.h" 24#include "compiler.h" 25#include "driver/compiler_driver.h" 26#include "driver/dex_compilation_unit.h" 27#include "graph_visualizer.h" 28#include "gvn.h" 29#include "instruction_simplifier.h" 30#include "nodes.h" 31#include "prepare_for_register_allocation.h" 32#include "register_allocator.h" 33#include "ssa_phi_elimination.h" 34#include "ssa_liveness_analysis.h" 35#include "utils/arena_allocator.h" 36 37namespace art { 38 39/** 40 * Used by the code generator, to allocate the code in a vector. 41 */ 42class CodeVectorAllocator FINAL : public CodeAllocator { 43 public: 44 CodeVectorAllocator() {} 45 46 virtual uint8_t* Allocate(size_t size) { 47 size_ = size; 48 memory_.resize(size); 49 return &memory_[0]; 50 } 51 52 size_t GetSize() const { return size_; } 53 const std::vector<uint8_t>& GetMemory() const { return memory_; } 54 55 private: 56 std::vector<uint8_t> memory_; 57 size_t size_; 58 59 DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator); 60}; 61 62/** 63 * If set to true, generates a file suitable for the c1visualizer tool and IRHydra. 64 */ 65static bool kIsVisualizerEnabled = false; 66 67/** 68 * Filter to apply to the visualizer. Methods whose name contain that filter will 69 * be in the file. 70 */ 71static const char* kStringFilter = ""; 72 73class OptimizingCompiler FINAL : public Compiler { 74 public: 75 explicit OptimizingCompiler(CompilerDriver* driver); 76 ~OptimizingCompiler(); 77 78 bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const 79 OVERRIDE; 80 81 CompiledMethod* Compile(const DexFile::CodeItem* code_item, 82 uint32_t access_flags, 83 InvokeType invoke_type, 84 uint16_t class_def_idx, 85 uint32_t method_idx, 86 jobject class_loader, 87 const DexFile& dex_file) const OVERRIDE; 88 89 CompiledMethod* TryCompile(const DexFile::CodeItem* code_item, 90 uint32_t access_flags, 91 InvokeType invoke_type, 92 uint16_t class_def_idx, 93 uint32_t method_idx, 94 jobject class_loader, 95 const DexFile& dex_file) const; 96 97 // For the following methods we will use the fallback. This is a delegation pattern. 98 CompiledMethod* JniCompile(uint32_t access_flags, 99 uint32_t method_idx, 100 const DexFile& dex_file) const OVERRIDE; 101 102 uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const OVERRIDE 103 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 104 105 bool WriteElf(art::File* file, 106 OatWriter* oat_writer, 107 const std::vector<const art::DexFile*>& dex_files, 108 const std::string& android_root, 109 bool is_host) const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); 110 111 Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE; 112 113 void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE; 114 115 void Init() const OVERRIDE; 116 117 void UnInit() const OVERRIDE; 118 119 private: 120 // Whether we should run any optimization or register allocation. If false, will 121 // just run the code generation after the graph was built. 122 const bool run_optimizations_; 123 mutable AtomicInteger total_compiled_methods_; 124 mutable AtomicInteger unoptimized_compiled_methods_; 125 mutable AtomicInteger optimized_compiled_methods_; 126 127 std::unique_ptr<std::ostream> visualizer_output_; 128 129 // Delegate to another compiler in case the optimizing compiler cannot compile a method. 130 // Currently the fallback is the quick compiler. 131 std::unique_ptr<Compiler> delegate_; 132 133 DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler); 134}; 135 136static const int kMaximumCompilationTimeBeforeWarning = 100; /* ms */ 137 138OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) 139 : Compiler(driver, kMaximumCompilationTimeBeforeWarning), 140 run_optimizations_( 141 driver->GetCompilerOptions().GetCompilerFilter() != CompilerOptions::kTime), 142 total_compiled_methods_(0), 143 unoptimized_compiled_methods_(0), 144 optimized_compiled_methods_(0), 145 delegate_(Create(driver, Compiler::Kind::kQuick)) { 146 if (kIsVisualizerEnabled) { 147 visualizer_output_.reset(new std::ofstream("art.cfg")); 148 } 149} 150 151void OptimizingCompiler::Init() const { 152 delegate_->Init(); 153} 154 155void OptimizingCompiler::UnInit() const { 156 delegate_->UnInit(); 157} 158 159OptimizingCompiler::~OptimizingCompiler() { 160 if (total_compiled_methods_ == 0) { 161 LOG(INFO) << "Did not compile any method."; 162 } else { 163 size_t unoptimized_percent = (unoptimized_compiled_methods_ * 100 / total_compiled_methods_); 164 size_t optimized_percent = (optimized_compiled_methods_ * 100 / total_compiled_methods_); 165 LOG(INFO) << "Compiled " << total_compiled_methods_ << " methods: " 166 << unoptimized_percent << "% (" << unoptimized_compiled_methods_ << ") unoptimized, " 167 << optimized_percent << "% (" << optimized_compiled_methods_ << ") optimized."; 168 } 169} 170 171bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, 172 CompilationUnit* cu) const { 173 return delegate_->CanCompileMethod(method_idx, dex_file, cu); 174} 175 176CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, 177 uint32_t method_idx, 178 const DexFile& dex_file) const { 179 return delegate_->JniCompile(access_flags, method_idx, dex_file); 180} 181 182uintptr_t OptimizingCompiler::GetEntryPointOf(mirror::ArtMethod* method) const { 183 return delegate_->GetEntryPointOf(method); 184} 185 186bool OptimizingCompiler::WriteElf(art::File* file, OatWriter* oat_writer, 187 const std::vector<const art::DexFile*>& dex_files, 188 const std::string& android_root, bool is_host) const { 189 return delegate_->WriteElf(file, oat_writer, dex_files, android_root, is_host); 190} 191 192Backend* OptimizingCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { 193 return delegate_->GetCodeGenerator(cu, compilation_unit); 194} 195 196void OptimizingCompiler::InitCompilationUnit(CompilationUnit& cu) const { 197 delegate_->InitCompilationUnit(cu); 198} 199 200CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item, 201 uint32_t access_flags, 202 InvokeType invoke_type, 203 uint16_t class_def_idx, 204 uint32_t method_idx, 205 jobject class_loader, 206 const DexFile& dex_file) const { 207 total_compiled_methods_++; 208 InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet(); 209 // Always use the thumb2 assembler: some runtime functionality (like implicit stack 210 // overflow checks) assume thumb2. 211 if (instruction_set == kArm) { 212 instruction_set = kThumb2; 213 } 214 215 // Do not attempt to compile on architectures we do not support. 216 if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) { 217 return nullptr; 218 } 219 220 DexCompilationUnit dex_compilation_unit( 221 nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item, 222 class_def_idx, method_idx, access_flags, 223 GetCompilerDriver()->GetVerifiedMethod(&dex_file, method_idx)); 224 225 // For testing purposes, we put a special marker on method names that should be compiled 226 // with this compiler. This makes sure we're not regressing. 227 bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos; 228 bool shouldOptimize = 229 dex_compilation_unit.GetSymbol().find("00024reg_00024") != std::string::npos; 230 231 ArenaPool pool; 232 ArenaAllocator arena(&pool); 233 HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file, GetCompilerDriver()); 234 235 HGraph* graph = builder.BuildGraph(*code_item); 236 if (graph == nullptr) { 237 if (shouldCompile) { 238 LOG(FATAL) << "Could not build graph in optimizing compiler"; 239 } 240 return nullptr; 241 } 242 243 CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, instruction_set); 244 if (codegen == nullptr) { 245 if (shouldCompile) { 246 LOG(FATAL) << "Could not find code generator for optimizing compiler"; 247 } 248 return nullptr; 249 } 250 251 HGraphVisualizer visualizer( 252 visualizer_output_.get(), graph, kStringFilter, *codegen, dex_compilation_unit); 253 visualizer.DumpGraph("builder"); 254 255 CodeVectorAllocator allocator; 256 257 if (run_optimizations_ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) { 258 optimized_compiled_methods_++; 259 graph->BuildDominatorTree(); 260 graph->TransformToSSA(); 261 visualizer.DumpGraph("ssa"); 262 graph->FindNaturalLoops(); 263 264 SsaRedundantPhiElimination(graph).Run(); 265 SsaDeadPhiElimination(graph).Run(); 266 InstructionSimplifier(graph).Run(); 267 GlobalValueNumberer(graph->GetArena(), graph).Run(); 268 visualizer.DumpGraph(kGVNPassName); 269 PrepareForRegisterAllocation(graph).Run(); 270 271 SsaLivenessAnalysis liveness(*graph, codegen); 272 liveness.Analyze(); 273 visualizer.DumpGraph(kLivenessPassName); 274 275 RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness); 276 register_allocator.AllocateRegisters(); 277 278 visualizer.DumpGraph(kRegisterAllocatorPassName); 279 codegen->CompileOptimized(&allocator); 280 281 std::vector<uint8_t> mapping_table; 282 SrcMap src_mapping_table; 283 codegen->BuildMappingTable(&mapping_table, 284 GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ? 285 &src_mapping_table : nullptr); 286 287 std::vector<uint8_t> stack_map; 288 codegen->BuildStackMaps(&stack_map); 289 290 return new CompiledMethod(GetCompilerDriver(), 291 instruction_set, 292 allocator.GetMemory(), 293 codegen->GetFrameSize(), 294 codegen->GetCoreSpillMask(), 295 0, /* FPR spill mask, unused */ 296 mapping_table, 297 stack_map); 298 } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) { 299 LOG(FATAL) << "Could not allocate registers in optimizing compiler"; 300 return nullptr; 301 } else { 302 unoptimized_compiled_methods_++; 303 codegen->CompileBaseline(&allocator); 304 305 // Run these phases to get some test coverage. 306 graph->BuildDominatorTree(); 307 graph->TransformToSSA(); 308 visualizer.DumpGraph("ssa"); 309 graph->FindNaturalLoops(); 310 SsaRedundantPhiElimination(graph).Run(); 311 SsaDeadPhiElimination(graph).Run(); 312 GlobalValueNumberer(graph->GetArena(), graph).Run(); 313 SsaLivenessAnalysis liveness(*graph, codegen); 314 liveness.Analyze(); 315 visualizer.DumpGraph(kLivenessPassName); 316 317 std::vector<uint8_t> mapping_table; 318 SrcMap src_mapping_table; 319 codegen->BuildMappingTable(&mapping_table, 320 GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ? 321 &src_mapping_table : nullptr); 322 std::vector<uint8_t> vmap_table; 323 codegen->BuildVMapTable(&vmap_table); 324 std::vector<uint8_t> gc_map; 325 codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit); 326 327 return new CompiledMethod(GetCompilerDriver(), 328 instruction_set, 329 allocator.GetMemory(), 330 codegen->GetFrameSize(), 331 codegen->GetCoreSpillMask(), 332 0, /* FPR spill mask, unused */ 333 &src_mapping_table, 334 mapping_table, 335 vmap_table, 336 gc_map, 337 nullptr); 338 } 339} 340 341CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, 342 uint32_t access_flags, 343 InvokeType invoke_type, 344 uint16_t class_def_idx, 345 uint32_t method_idx, 346 jobject class_loader, 347 const DexFile& dex_file) const { 348 CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, 349 method_idx, class_loader, dex_file); 350 if (method != nullptr) { 351 return method; 352 } 353 354 return delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, 355 class_loader, dex_file); 356} 357 358Compiler* CreateOptimizingCompiler(CompilerDriver* driver) { 359 return new OptimizingCompiler(driver); 360} 361 362} // namespace art 363