optimizing_compiler.cc revision a5ae3c3f468ffe3a317b498d7fde1f8e9325346a
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 "art_method-inl.h" 23#include "base/arena_allocator.h" 24#include "base/dumpable.h" 25#include "base/timing_logger.h" 26#include "boolean_simplifier.h" 27#include "bounds_check_elimination.h" 28#include "builder.h" 29#include "code_generator.h" 30#include "compiled_method.h" 31#include "compiler.h" 32#include "constant_folding.h" 33#include "dead_code_elimination.h" 34#include "dex/quick/dex_file_to_method_inliner_map.h" 35#include "dex/verified_method.h" 36#include "dex/verification_results.h" 37#include "driver/compiler_driver.h" 38#include "driver/compiler_driver-inl.h" 39#include "driver/compiler_options.h" 40#include "driver/dex_compilation_unit.h" 41#include "elf_writer_quick.h" 42#include "graph_checker.h" 43#include "graph_visualizer.h" 44#include "gvn.h" 45#include "inliner.h" 46#include "instruction_simplifier.h" 47#include "intrinsics.h" 48#include "licm.h" 49#include "jni/quick/jni_compiler.h" 50#include "nodes.h" 51#include "prepare_for_register_allocation.h" 52#include "reference_type_propagation.h" 53#include "register_allocator.h" 54#include "side_effects_analysis.h" 55#include "ssa_builder.h" 56#include "ssa_phi_elimination.h" 57#include "ssa_liveness_analysis.h" 58#include "utils/assembler.h" 59 60namespace art { 61 62/** 63 * Used by the code generator, to allocate the code in a vector. 64 */ 65class CodeVectorAllocator FINAL : public CodeAllocator { 66 public: 67 CodeVectorAllocator() : size_(0) {} 68 69 virtual uint8_t* Allocate(size_t size) { 70 size_ = size; 71 memory_.resize(size); 72 return &memory_[0]; 73 } 74 75 size_t GetSize() const { return size_; } 76 const std::vector<uint8_t>& GetMemory() const { return memory_; } 77 78 private: 79 std::vector<uint8_t> memory_; 80 size_t size_; 81 82 DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator); 83}; 84 85/** 86 * Filter to apply to the visualizer. Methods whose name contain that filter will 87 * be dumped. 88 */ 89static constexpr const char kStringFilter[] = ""; 90 91class PassScope; 92 93class PassObserver : public ValueObject { 94 public: 95 PassObserver(HGraph* graph, 96 const char* method_name, 97 CodeGenerator* codegen, 98 std::ostream* visualizer_output, 99 CompilerDriver* compiler_driver) 100 : graph_(graph), 101 method_name_(method_name), 102 timing_logger_enabled_(compiler_driver->GetDumpPasses()), 103 timing_logger_(method_name, true, true), 104 disasm_info_(graph->GetArena()), 105 visualizer_enabled_(!compiler_driver->GetDumpCfgFileName().empty()), 106 visualizer_(visualizer_output, graph, *codegen), 107 graph_in_bad_state_(false) { 108 if (timing_logger_enabled_ || visualizer_enabled_) { 109 if (!IsVerboseMethod(compiler_driver, method_name)) { 110 timing_logger_enabled_ = visualizer_enabled_ = false; 111 } 112 if (visualizer_enabled_) { 113 visualizer_.PrintHeader(method_name_); 114 codegen->SetDisassemblyInformation(&disasm_info_); 115 } 116 } 117 } 118 119 ~PassObserver() { 120 if (timing_logger_enabled_) { 121 LOG(INFO) << "TIMINGS " << method_name_; 122 LOG(INFO) << Dumpable<TimingLogger>(timing_logger_); 123 } 124 } 125 126 void DumpDisassembly() const { 127 if (visualizer_enabled_) { 128 visualizer_.DumpGraphWithDisassembly(); 129 } 130 } 131 132 void SetGraphInBadState() { graph_in_bad_state_ = true; } 133 134 private: 135 void StartPass(const char* pass_name) { 136 // Dump graph first, then start timer. 137 if (visualizer_enabled_) { 138 visualizer_.DumpGraph(pass_name, /* is_after_pass */ false, graph_in_bad_state_); 139 } 140 if (timing_logger_enabled_) { 141 timing_logger_.StartTiming(pass_name); 142 } 143 } 144 145 void EndPass(const char* pass_name) { 146 // Pause timer first, then dump graph. 147 if (timing_logger_enabled_) { 148 timing_logger_.EndTiming(); 149 } 150 if (visualizer_enabled_) { 151 visualizer_.DumpGraph(pass_name, /* is_after_pass */ true, graph_in_bad_state_); 152 } 153 154 // Validate the HGraph if running in debug mode. 155 if (kIsDebugBuild) { 156 if (!graph_in_bad_state_) { 157 if (graph_->IsInSsaForm()) { 158 SSAChecker checker(graph_->GetArena(), graph_); 159 checker.Run(); 160 if (!checker.IsValid()) { 161 LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<SSAChecker>(checker); 162 } 163 } else { 164 GraphChecker checker(graph_->GetArena(), graph_); 165 checker.Run(); 166 if (!checker.IsValid()) { 167 LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<GraphChecker>(checker); 168 } 169 } 170 } 171 } 172 } 173 174 static bool IsVerboseMethod(CompilerDriver* compiler_driver, const char* method_name) { 175 // Test an exact match to --verbose-methods. If verbose-methods is set, this overrides an 176 // empty kStringFilter matching all methods. 177 if (compiler_driver->GetCompilerOptions().HasVerboseMethods()) { 178 return compiler_driver->GetCompilerOptions().IsVerboseMethod(method_name); 179 } 180 181 // Test the kStringFilter sub-string. constexpr helper variable to silence unreachable-code 182 // warning when the string is empty. 183 constexpr bool kStringFilterEmpty = arraysize(kStringFilter) <= 1; 184 if (kStringFilterEmpty || strstr(method_name, kStringFilter) != nullptr) { 185 return true; 186 } 187 188 return false; 189 } 190 191 HGraph* const graph_; 192 const char* method_name_; 193 194 bool timing_logger_enabled_; 195 TimingLogger timing_logger_; 196 197 DisassemblyInformation disasm_info_; 198 199 bool visualizer_enabled_; 200 HGraphVisualizer visualizer_; 201 202 // Flag to be set by the compiler if the pass failed and the graph is not 203 // expected to validate. 204 bool graph_in_bad_state_; 205 206 friend PassScope; 207 208 DISALLOW_COPY_AND_ASSIGN(PassObserver); 209}; 210 211class PassScope : public ValueObject { 212 public: 213 PassScope(const char *pass_name, PassObserver* pass_observer) 214 : pass_name_(pass_name), 215 pass_observer_(pass_observer) { 216 pass_observer_->StartPass(pass_name_); 217 } 218 219 ~PassScope() { 220 pass_observer_->EndPass(pass_name_); 221 } 222 223 private: 224 const char* const pass_name_; 225 PassObserver* const pass_observer_; 226}; 227 228class OptimizingCompiler FINAL : public Compiler { 229 public: 230 explicit OptimizingCompiler(CompilerDriver* driver); 231 ~OptimizingCompiler(); 232 233 bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const 234 OVERRIDE; 235 236 CompiledMethod* Compile(const DexFile::CodeItem* code_item, 237 uint32_t access_flags, 238 InvokeType invoke_type, 239 uint16_t class_def_idx, 240 uint32_t method_idx, 241 jobject class_loader, 242 const DexFile& dex_file) const OVERRIDE; 243 244 CompiledMethod* TryCompile(const DexFile::CodeItem* code_item, 245 uint32_t access_flags, 246 InvokeType invoke_type, 247 uint16_t class_def_idx, 248 uint32_t method_idx, 249 jobject class_loader, 250 const DexFile& dex_file) const; 251 252 CompiledMethod* JniCompile(uint32_t access_flags, 253 uint32_t method_idx, 254 const DexFile& dex_file) const OVERRIDE { 255 return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file); 256 } 257 258 uintptr_t GetEntryPointOf(ArtMethod* method) const OVERRIDE 259 SHARED_REQUIRES(Locks::mutator_lock_) { 260 return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize( 261 InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet()))); 262 } 263 264 void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE; 265 266 void Init() OVERRIDE; 267 268 void UnInit() const OVERRIDE; 269 270 void MaybeRecordStat(MethodCompilationStat compilation_stat) const { 271 if (compilation_stats_.get() != nullptr) { 272 compilation_stats_->RecordStat(compilation_stat); 273 } 274 } 275 276 private: 277 // Whether we should run any optimization or register allocation. If false, will 278 // just run the code generation after the graph was built. 279 const bool run_optimizations_; 280 281 // Optimize and compile `graph`. 282 CompiledMethod* CompileOptimized(HGraph* graph, 283 CodeGenerator* codegen, 284 CompilerDriver* driver, 285 const DexCompilationUnit& dex_compilation_unit, 286 PassObserver* pass_observer) const; 287 288 // Just compile without doing optimizations. 289 CompiledMethod* CompileBaseline(CodeGenerator* codegen, 290 CompilerDriver* driver, 291 const DexCompilationUnit& dex_compilation_unit, 292 PassObserver* pass_observer) const; 293 294 std::unique_ptr<OptimizingCompilerStats> compilation_stats_; 295 296 std::unique_ptr<std::ostream> visualizer_output_; 297 298 // Delegate to Quick in case the optimizing compiler cannot compile a method. 299 std::unique_ptr<Compiler> delegate_; 300 301 DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler); 302}; 303 304static const int kMaximumCompilationTimeBeforeWarning = 100; /* ms */ 305 306OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) 307 : Compiler(driver, kMaximumCompilationTimeBeforeWarning), 308 run_optimizations_( 309 (driver->GetCompilerOptions().GetCompilerFilter() != CompilerOptions::kTime) 310 && !driver->GetCompilerOptions().GetDebuggable()), 311 delegate_(Create(driver, Compiler::Kind::kQuick)) {} 312 313void OptimizingCompiler::Init() { 314 delegate_->Init(); 315 // Enable C1visualizer output. Must be done in Init() because the compiler 316 // driver is not fully initialized when passed to the compiler's constructor. 317 CompilerDriver* driver = GetCompilerDriver(); 318 const std::string cfg_file_name = driver->GetDumpCfgFileName(); 319 if (!cfg_file_name.empty()) { 320 CHECK_EQ(driver->GetThreadCount(), 1U) 321 << "Graph visualizer requires the compiler to run single-threaded. " 322 << "Invoke the compiler with '-j1'."; 323 visualizer_output_.reset(new std::ofstream(cfg_file_name)); 324 } 325 if (driver->GetDumpStats()) { 326 compilation_stats_.reset(new OptimizingCompilerStats()); 327 } 328} 329 330void OptimizingCompiler::UnInit() const { 331 delegate_->UnInit(); 332} 333 334OptimizingCompiler::~OptimizingCompiler() { 335 if (compilation_stats_.get() != nullptr) { 336 compilation_stats_->Log(); 337 } 338} 339 340void OptimizingCompiler::InitCompilationUnit(CompilationUnit& cu) const { 341 delegate_->InitCompilationUnit(cu); 342} 343 344bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx ATTRIBUTE_UNUSED, 345 const DexFile& dex_file ATTRIBUTE_UNUSED, 346 CompilationUnit* cu ATTRIBUTE_UNUSED) const { 347 return true; 348} 349 350static bool IsInstructionSetSupported(InstructionSet instruction_set) { 351 return instruction_set == kArm64 352 || (instruction_set == kThumb2 && !kArm32QuickCodeUseSoftFloat) 353 || instruction_set == kMips64 354 || instruction_set == kX86 355 || instruction_set == kX86_64; 356} 357 358static bool CanOptimize(const DexFile::CodeItem& code_item) { 359 // TODO: We currently cannot optimize methods with try/catch. 360 return code_item.tries_size_ == 0; 361} 362 363static void RunOptimizations(HOptimization* optimizations[], 364 size_t length, 365 PassObserver* pass_observer) { 366 for (size_t i = 0; i < length; ++i) { 367 PassScope scope(optimizations[i]->GetPassName(), pass_observer); 368 optimizations[i]->Run(); 369 } 370} 371 372static void RunOptimizations(HGraph* graph, 373 CompilerDriver* driver, 374 OptimizingCompilerStats* stats, 375 const DexCompilationUnit& dex_compilation_unit, 376 PassObserver* pass_observer, 377 StackHandleScopeCollection* handles) { 378 ArenaAllocator* arena = graph->GetArena(); 379 HDeadCodeElimination* dce1 = new (arena) HDeadCodeElimination( 380 graph, stats, HDeadCodeElimination::kInitialDeadCodeEliminationPassName); 381 HDeadCodeElimination* dce2 = new (arena) HDeadCodeElimination( 382 graph, stats, HDeadCodeElimination::kFinalDeadCodeEliminationPassName); 383 HConstantFolding* fold1 = new (arena) HConstantFolding(graph); 384 InstructionSimplifier* simplify1 = new (arena) InstructionSimplifier(graph, stats); 385 HBooleanSimplifier* boolean_simplify = new (arena) HBooleanSimplifier(graph); 386 387 HInliner* inliner = new (arena) HInliner( 388 graph, dex_compilation_unit, dex_compilation_unit, driver, handles, stats); 389 390 HConstantFolding* fold2 = new (arena) HConstantFolding(graph, "constant_folding_after_inlining"); 391 SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph); 392 GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects); 393 LICM* licm = new (arena) LICM(graph, *side_effects); 394 BoundsCheckElimination* bce = new (arena) BoundsCheckElimination(graph); 395 ReferenceTypePropagation* type_propagation = 396 new (arena) ReferenceTypePropagation(graph, handles); 397 InstructionSimplifier* simplify2 = new (arena) InstructionSimplifier( 398 graph, stats, "instruction_simplifier_after_types"); 399 InstructionSimplifier* simplify3 = new (arena) InstructionSimplifier( 400 graph, stats, "instruction_simplifier_after_bce"); 401 ReferenceTypePropagation* type_propagation2 = 402 new (arena) ReferenceTypePropagation( 403 graph, handles, "reference_type_propagation_after_inlining"); 404 InstructionSimplifier* simplify4 = new (arena) InstructionSimplifier( 405 graph, stats, "instruction_simplifier_before_codegen"); 406 407 IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, driver); 408 409 HOptimization* optimizations[] = { 410 intrinsics, 411 fold1, 412 simplify1, 413 type_propagation, 414 dce1, 415 simplify2, 416 inliner, 417 // Run another type propagation phase: inlining will open up more opprotunities 418 // to remove checkast/instanceof and null checks. 419 type_propagation2, 420 // BooleanSimplifier depends on the InstructionSimplifier removing redundant 421 // suspend checks to recognize empty blocks. 422 boolean_simplify, 423 fold2, 424 side_effects, 425 gvn, 426 licm, 427 bce, 428 simplify3, 429 dce2, 430 // The codegen has a few assumptions that only the instruction simplifier can 431 // satisfy. For example, the code generator does not expect to see a 432 // HTypeConversion from a type to the same type. 433 simplify4, 434 }; 435 436 RunOptimizations(optimizations, arraysize(optimizations), pass_observer); 437} 438 439// The stack map we generate must be 4-byte aligned on ARM. Since existing 440// maps are generated alongside these stack maps, we must also align them. 441static ArrayRef<const uint8_t> AlignVectorSize(std::vector<uint8_t>& vector) { 442 size_t size = vector.size(); 443 size_t aligned_size = RoundUp(size, 4); 444 for (; size < aligned_size; ++size) { 445 vector.push_back(0); 446 } 447 return ArrayRef<const uint8_t>(vector); 448} 449 450static void AllocateRegisters(HGraph* graph, 451 CodeGenerator* codegen, 452 PassObserver* pass_observer) { 453 PrepareForRegisterAllocation(graph).Run(); 454 SsaLivenessAnalysis liveness(graph, codegen); 455 { 456 PassScope scope(SsaLivenessAnalysis::kLivenessPassName, pass_observer); 457 liveness.Analyze(); 458 } 459 { 460 PassScope scope(RegisterAllocator::kRegisterAllocatorPassName, pass_observer); 461 RegisterAllocator(graph->GetArena(), codegen, liveness).AllocateRegisters(); 462 } 463} 464 465CompiledMethod* OptimizingCompiler::CompileOptimized(HGraph* graph, 466 CodeGenerator* codegen, 467 CompilerDriver* compiler_driver, 468 const DexCompilationUnit& dex_compilation_unit, 469 PassObserver* pass_observer) const { 470 StackHandleScopeCollection handles(Thread::Current()); 471 RunOptimizations(graph, compiler_driver, compilation_stats_.get(), 472 dex_compilation_unit, pass_observer, &handles); 473 474 AllocateRegisters(graph, codegen, pass_observer); 475 476 CodeVectorAllocator allocator; 477 codegen->CompileOptimized(&allocator); 478 479 DefaultSrcMap src_mapping_table; 480 if (compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()) { 481 codegen->BuildSourceMap(&src_mapping_table); 482 } 483 484 std::vector<uint8_t> stack_map; 485 codegen->BuildStackMaps(&stack_map); 486 487 MaybeRecordStat(MethodCompilationStat::kCompiledOptimized); 488 489 CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod( 490 compiler_driver, 491 codegen->GetInstructionSet(), 492 ArrayRef<const uint8_t>(allocator.GetMemory()), 493 // Follow Quick's behavior and set the frame size to zero if it is 494 // considered "empty" (see the definition of 495 // art::CodeGenerator::HasEmptyFrame). 496 codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), 497 codegen->GetCoreSpillMask(), 498 codegen->GetFpuSpillMask(), 499 &src_mapping_table, 500 ArrayRef<const uint8_t>(), // mapping_table. 501 ArrayRef<const uint8_t>(stack_map), 502 ArrayRef<const uint8_t>(), // native_gc_map. 503 ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()), 504 ArrayRef<const LinkerPatch>()); 505 pass_observer->DumpDisassembly(); 506 return compiled_method; 507} 508 509CompiledMethod* OptimizingCompiler::CompileBaseline( 510 CodeGenerator* codegen, 511 CompilerDriver* compiler_driver, 512 const DexCompilationUnit& dex_compilation_unit, 513 PassObserver* pass_observer) const { 514 CodeVectorAllocator allocator; 515 codegen->CompileBaseline(&allocator); 516 517 std::vector<uint8_t> mapping_table; 518 codegen->BuildMappingTable(&mapping_table); 519 DefaultSrcMap src_mapping_table; 520 if (compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()) { 521 codegen->BuildSourceMap(&src_mapping_table); 522 } 523 std::vector<uint8_t> vmap_table; 524 codegen->BuildVMapTable(&vmap_table); 525 std::vector<uint8_t> gc_map; 526 codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit); 527 528 MaybeRecordStat(MethodCompilationStat::kCompiledBaseline); 529 CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod( 530 compiler_driver, 531 codegen->GetInstructionSet(), 532 ArrayRef<const uint8_t>(allocator.GetMemory()), 533 // Follow Quick's behavior and set the frame size to zero if it is 534 // considered "empty" (see the definition of 535 // art::CodeGenerator::HasEmptyFrame). 536 codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), 537 codegen->GetCoreSpillMask(), 538 codegen->GetFpuSpillMask(), 539 &src_mapping_table, 540 AlignVectorSize(mapping_table), 541 AlignVectorSize(vmap_table), 542 AlignVectorSize(gc_map), 543 ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()), 544 ArrayRef<const LinkerPatch>()); 545 pass_observer->DumpDisassembly(); 546 return compiled_method; 547} 548 549CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item, 550 uint32_t access_flags, 551 InvokeType invoke_type, 552 uint16_t class_def_idx, 553 uint32_t method_idx, 554 jobject class_loader, 555 const DexFile& dex_file) const { 556 UNUSED(invoke_type); 557 std::string method_name = PrettyMethod(method_idx, dex_file); 558 MaybeRecordStat(MethodCompilationStat::kAttemptCompilation); 559 CompilerDriver* compiler_driver = GetCompilerDriver(); 560 InstructionSet instruction_set = compiler_driver->GetInstructionSet(); 561 // Always use the thumb2 assembler: some runtime functionality (like implicit stack 562 // overflow checks) assume thumb2. 563 if (instruction_set == kArm) { 564 instruction_set = kThumb2; 565 } 566 567 // Do not attempt to compile on architectures we do not support. 568 if (!IsInstructionSetSupported(instruction_set)) { 569 MaybeRecordStat(MethodCompilationStat::kNotCompiledUnsupportedIsa); 570 return nullptr; 571 } 572 573 if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) { 574 MaybeRecordStat(MethodCompilationStat::kNotCompiledPathological); 575 return nullptr; 576 } 577 578 // Implementation of the space filter: do not compile a code item whose size in 579 // code units is bigger than 128. 580 static constexpr size_t kSpaceFilterOptimizingThreshold = 128; 581 const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); 582 if ((compiler_options.GetCompilerFilter() == CompilerOptions::kSpace) 583 && (code_item->insns_size_in_code_units_ > kSpaceFilterOptimizingThreshold)) { 584 MaybeRecordStat(MethodCompilationStat::kNotCompiledSpaceFilter); 585 return nullptr; 586 } 587 588 DexCompilationUnit dex_compilation_unit( 589 nullptr, class_loader, Runtime::Current()->GetClassLinker(), dex_file, code_item, 590 class_def_idx, method_idx, access_flags, 591 compiler_driver->GetVerifiedMethod(&dex_file, method_idx)); 592 593 bool requires_barrier = dex_compilation_unit.IsConstructor() 594 && compiler_driver->RequiresConstructorBarrier(Thread::Current(), 595 dex_compilation_unit.GetDexFile(), 596 dex_compilation_unit.GetClassDefIndex()); 597 ArenaAllocator arena(Runtime::Current()->GetArenaPool()); 598 HGraph* graph = new (&arena) HGraph( 599 &arena, dex_file, method_idx, requires_barrier, compiler_driver->GetInstructionSet(), 600 kInvalidInvokeType, compiler_driver->GetCompilerOptions().GetDebuggable()); 601 602 // For testing purposes, we put a special marker on method names that should be compiled 603 // with this compiler. This makes sure we're not regressing. 604 bool shouldCompile = method_name.find("$opt$") != std::string::npos; 605 bool shouldOptimize = method_name.find("$opt$reg$") != std::string::npos && run_optimizations_; 606 607 std::unique_ptr<CodeGenerator> codegen( 608 CodeGenerator::Create(graph, 609 instruction_set, 610 *compiler_driver->GetInstructionSetFeatures(), 611 compiler_driver->GetCompilerOptions())); 612 if (codegen.get() == nullptr) { 613 CHECK(!shouldCompile) << "Could not find code generator for optimizing compiler"; 614 MaybeRecordStat(MethodCompilationStat::kNotCompiledNoCodegen); 615 return nullptr; 616 } 617 codegen->GetAssembler()->cfi().SetEnabled( 618 compiler_driver->GetCompilerOptions().GetGenerateDebugInfo()); 619 620 PassObserver pass_observer(graph, 621 method_name.c_str(), 622 codegen.get(), 623 visualizer_output_.get(), 624 compiler_driver); 625 626 const uint8_t* interpreter_metadata = nullptr; 627 { 628 ScopedObjectAccess soa(Thread::Current()); 629 StackHandleScope<4> hs(soa.Self()); 630 ClassLinker* class_linker = dex_compilation_unit.GetClassLinker(); 631 Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(dex_file))); 632 Handle<mirror::ClassLoader> loader(hs.NewHandle( 633 soa.Decode<mirror::ClassLoader*>(class_loader))); 634 ArtMethod* art_method = compiler_driver->ResolveMethod( 635 soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type); 636 // We may not get a method, for example if its class is erroneous. 637 // TODO: Clean this up, the compiler driver should just pass the ArtMethod to compile. 638 if (art_method != nullptr) { 639 interpreter_metadata = art_method->GetQuickenedInfo(); 640 } 641 } 642 HGraphBuilder builder(graph, 643 &dex_compilation_unit, 644 &dex_compilation_unit, 645 &dex_file, 646 compiler_driver, 647 compilation_stats_.get(), 648 interpreter_metadata); 649 650 VLOG(compiler) << "Building " << method_name; 651 652 { 653 PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer); 654 if (!builder.BuildGraph(*code_item)) { 655 DCHECK(!(IsCompilingWithCoreImage() && shouldCompile)) 656 << "Could not build graph in optimizing compiler"; 657 pass_observer.SetGraphInBadState(); 658 return nullptr; 659 } 660 } 661 662 bool can_optimize = CanOptimize(*code_item); 663 bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set); 664 665 // `run_optimizations_` is set explicitly (either through a compiler filter 666 // or the debuggable flag). If it is set, we can run baseline. Otherwise, we fall back 667 // to Quick. 668 bool can_use_baseline = !run_optimizations_ && builder.CanUseBaselineForStringInit(); 669 if (run_optimizations_ && can_allocate_registers) { 670 VLOG(compiler) << "Optimizing " << method_name; 671 672 { 673 PassScope scope(SsaBuilder::kSsaBuilderPassName, &pass_observer); 674 if (!graph->TryBuildingSsa()) { 675 // We could not transform the graph to SSA, bailout. 676 LOG(INFO) << "Skipping compilation of " << method_name << ": it contains a non natural loop"; 677 MaybeRecordStat(MethodCompilationStat::kNotCompiledCannotBuildSSA); 678 pass_observer.SetGraphInBadState(); 679 return nullptr; 680 } 681 } 682 683 if (can_optimize) { 684 return CompileOptimized(graph, 685 codegen.get(), 686 compiler_driver, 687 dex_compilation_unit, 688 &pass_observer); 689 } 690 } 691 692 if (shouldOptimize && can_allocate_registers) { 693 LOG(FATAL) << "Could not allocate registers in optimizing compiler"; 694 UNREACHABLE(); 695 } else if (can_use_baseline) { 696 VLOG(compiler) << "Compile baseline " << method_name; 697 698 if (!run_optimizations_) { 699 MaybeRecordStat(MethodCompilationStat::kNotOptimizedDisabled); 700 } else if (!can_optimize) { 701 MaybeRecordStat(MethodCompilationStat::kNotOptimizedTryCatch); 702 } else if (!can_allocate_registers) { 703 MaybeRecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator); 704 } 705 706 return CompileBaseline(codegen.get(), 707 compiler_driver, 708 dex_compilation_unit, 709 &pass_observer); 710 } else { 711 return nullptr; 712 } 713} 714 715CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, 716 uint32_t access_flags, 717 InvokeType invoke_type, 718 uint16_t class_def_idx, 719 uint32_t method_idx, 720 jobject jclass_loader, 721 const DexFile& dex_file) const { 722 CompilerDriver* compiler_driver = GetCompilerDriver(); 723 CompiledMethod* method = nullptr; 724 if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) && 725 !compiler_driver->GetVerifiedMethod(&dex_file, method_idx)->HasRuntimeThrow()) { 726 method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, 727 method_idx, jclass_loader, dex_file); 728 } else { 729 if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) { 730 MaybeRecordStat(MethodCompilationStat::kNotCompiledVerifyAtRuntime); 731 } else { 732 MaybeRecordStat(MethodCompilationStat::kNotCompiledClassNotVerified); 733 } 734 } 735 736 if (method != nullptr) { 737 return method; 738 } 739 method = delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, 740 jclass_loader, dex_file); 741 742 if (method != nullptr) { 743 MaybeRecordStat(MethodCompilationStat::kCompiledQuick); 744 } 745 return method; 746} 747 748Compiler* CreateOptimizingCompiler(CompilerDriver* driver) { 749 return new OptimizingCompiler(driver); 750} 751 752bool IsCompilingWithCoreImage() { 753 const std::string& image = Runtime::Current()->GetImageLocation(); 754 return EndsWith(image, "core.art") || EndsWith(image, "core-optimizing.art"); 755} 756 757} // namespace art 758