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 32namespace art { 33 34/** 35 * Used by the code generator, to allocate the code in a vector. 36 */ 37class CodeVectorAllocator FINAL : public CodeAllocator { 38 public: 39 CodeVectorAllocator() { } 40 41 virtual uint8_t* Allocate(size_t size) { 42 size_ = size; 43 memory_.resize(size); 44 return &memory_[0]; 45 } 46 47 size_t GetSize() const { return size_; } 48 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 */ 60static 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 */ 66static const char* kStringFilter = ""; 67 68OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) { 69 if (kIsVisualizerEnabled) { 70 visualizer_output_.reset(new std::ofstream("art.cfg")); 71 } 72} 73 74CompiledMethod* 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