frontend.cc revision 4e97c539408f47145526f0062c1c06df99146a73
1/* 2 * Copyright (C) 2011 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 <llvm/Support/Threading.h> 18 19#include "compiler_internals.h" 20#include "driver/compiler_driver.h" 21#include "dataflow_iterator-inl.h" 22#include "leb128.h" 23#include "mirror/object.h" 24#include "pass_driver.h" 25#include "runtime.h" 26#include "backend.h" 27#include "base/logging.h" 28#include "base/timing_logger.h" 29 30#if defined(ART_USE_PORTABLE_COMPILER) 31#include "dex/portable/mir_to_gbc.h" 32#include "llvm/llvm_compilation_unit.h" 33#endif 34 35#include "dex/quick/dex_file_to_method_inliner_map.h" 36 37namespace { 38#if !defined(ART_USE_PORTABLE_COMPILER) 39 pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT; 40#endif 41 void InitializeLLVMForQuick() { 42 ::llvm::llvm_start_multithreaded(); 43 } 44} 45 46namespace art { 47namespace llvm { 48::llvm::Module* makeLLVMModuleContents(::llvm::Module* module); 49} 50 51LLVMInfo::LLVMInfo() { 52#if !defined(ART_USE_PORTABLE_COMPILER) 53 pthread_once(&llvm_multi_init, InitializeLLVMForQuick); 54#endif 55 // Create context, module, intrinsic helper & ir builder 56 llvm_context_.reset(new ::llvm::LLVMContext()); 57 llvm_module_ = new ::llvm::Module("art", *llvm_context_); 58 ::llvm::StructType::create(*llvm_context_, "JavaObject"); 59 art::llvm::makeLLVMModuleContents(llvm_module_); 60 intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_)); 61 ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_)); 62} 63 64LLVMInfo::~LLVMInfo() { 65} 66 67extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver) { 68 CHECK(driver.GetCompilerContext() == NULL); 69} 70 71extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver) { 72 CHECK(driver.GetCompilerContext() == NULL); 73} 74 75/* Default optimizer/debug setting for the compiler. */ 76static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations 77 (1 << kLoadStoreElimination) | 78 // (1 << kLoadHoisting) | 79 // (1 << kSuppressLoads) | 80 // (1 << kNullCheckElimination) | 81 // (1 << kPromoteRegs) | 82 // (1 << kTrackLiveTemps) | 83 // (1 << kSafeOptimizations) | 84 // (1 << kBBOpt) | 85 // (1 << kMatch) | 86 // (1 << kPromoteCompilerTemps) | 87 // (1 << kSuppressExceptionEdges) | 88 0; 89 90static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes 91 // (1 << kDebugDisplayMissingTargets) | 92 // (1 << kDebugVerbose) | 93 // (1 << kDebugDumpCFG) | 94 // (1 << kDebugSlowFieldPath) | 95 // (1 << kDebugSlowInvokePath) | 96 // (1 << kDebugSlowStringPath) | 97 // (1 << kDebugSlowestFieldPath) | 98 // (1 << kDebugSlowestStringPath) | 99 // (1 << kDebugExerciseResolveMethod) | 100 // (1 << kDebugVerifyDataflow) | 101 // (1 << kDebugShowMemoryUsage) | 102 // (1 << kDebugShowNops) | 103 // (1 << kDebugCountOpcodes) | 104 // (1 << kDebugDumpCheckStats) | 105 // (1 << kDebugDumpBitcodeFile) | 106 // (1 << kDebugVerifyBitcode) | 107 // (1 << kDebugShowSummaryMemoryUsage) | 108 // (1 << kDebugShowFilterStats) | 109 // (1 << kDebugTimings) | 110 0; 111 112CompilationUnit::CompilationUnit(ArenaPool* pool) 113 : compiler_driver(NULL), 114 class_linker(NULL), 115 dex_file(NULL), 116 class_loader(NULL), 117 class_def_idx(0), 118 method_idx(0), 119 code_item(NULL), 120 access_flags(0), 121 invoke_type(kDirect), 122 shorty(NULL), 123 disable_opt(0), 124 enable_debug(0), 125 verbose(false), 126 compiler_backend(kNoBackend), 127 instruction_set(kNone), 128 num_dalvik_registers(0), 129 insns(NULL), 130 num_ins(0), 131 num_outs(0), 132 num_regs(0), 133 num_compiler_temps(0), 134 compiler_flip_match(false), 135 arena(pool), 136 mir_graph(NULL), 137 cg(NULL), 138 timings("QuickCompiler", true, false) { 139} 140 141CompilationUnit::~CompilationUnit() { 142} 143 144// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing 145void CompilationUnit::StartTimingSplit(const char* label) { 146 if (enable_debug & (1 << kDebugTimings)) { 147 timings.StartSplit(label); 148 } 149} 150 151void CompilationUnit::NewTimingSplit(const char* label) { 152 if (enable_debug & (1 << kDebugTimings)) { 153 timings.NewSplit(label); 154 } 155} 156 157void CompilationUnit::EndTiming() { 158 if (enable_debug & (1 << kDebugTimings)) { 159 timings.EndSplit(); 160 LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file); 161 LOG(INFO) << Dumpable<TimingLogger>(timings); 162 } 163} 164 165static CompiledMethod* CompileMethod(CompilerDriver& compiler, 166 const CompilerBackend compiler_backend, 167 const DexFile::CodeItem* code_item, 168 uint32_t access_flags, InvokeType invoke_type, 169 uint16_t class_def_idx, uint32_t method_idx, 170 jobject class_loader, const DexFile& dex_file 171#if defined(ART_USE_PORTABLE_COMPILER) 172 , llvm::LlvmCompilationUnit* llvm_compilation_unit 173#endif 174) { 175 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; 176 if (code_item->insns_size_in_code_units_ >= 0x10000) { 177 LOG(INFO) << "Method size exceeds compiler limits: " << code_item->insns_size_in_code_units_ 178 << " in " << PrettyMethod(method_idx, dex_file); 179 return NULL; 180 } 181 182 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 183 CompilationUnit cu(&compiler.GetArenaPool()); 184 185 cu.compiler_driver = &compiler; 186 cu.class_linker = class_linker; 187 cu.instruction_set = compiler.GetInstructionSet(); 188 cu.compiler_backend = compiler_backend; 189 DCHECK((cu.instruction_set == kThumb2) || 190 (cu.instruction_set == kX86) || 191 (cu.instruction_set == kMips)); 192 193 194 /* Adjust this value accordingly once inlining is performed */ 195 cu.num_dalvik_registers = code_item->registers_size_; 196 // TODO: set this from command line 197 cu.compiler_flip_match = false; 198 bool use_match = !cu.compiler_method_match.empty(); 199 bool match = use_match && (cu.compiler_flip_match ^ 200 (PrettyMethod(method_idx, dex_file).find(cu.compiler_method_match) != 201 std::string::npos)); 202 if (!use_match || match) { 203 cu.disable_opt = kCompilerOptimizerDisableFlags; 204 cu.enable_debug = kCompilerDebugFlags; 205 cu.verbose = VLOG_IS_ON(compiler) || 206 (cu.enable_debug & (1 << kDebugVerbose)); 207 } 208 209 /* 210 * TODO: rework handling of optimization and debug flags. Should we split out 211 * MIR and backend flags? Need command-line setting as well. 212 */ 213 214 if (compiler_backend == kPortable) { 215 // Fused long branches not currently useful in bitcode. 216 cu.disable_opt |= 217 (1 << kBranchFusing) | 218 (1 << kSuppressExceptionEdges); 219 } 220 221 if (cu.instruction_set == kMips) { 222 // Disable some optimizations for mips for now 223 cu.disable_opt |= ( 224 (1 << kLoadStoreElimination) | 225 (1 << kLoadHoisting) | 226 (1 << kSuppressLoads) | 227 (1 << kNullCheckElimination) | 228 (1 << kPromoteRegs) | 229 (1 << kTrackLiveTemps) | 230 (1 << kSafeOptimizations) | 231 (1 << kBBOpt) | 232 (1 << kMatch) | 233 (1 << kPromoteCompilerTemps)); 234 } 235 236 cu.StartTimingSplit("BuildMIRGraph"); 237 cu.mir_graph.reset(new MIRGraph(&cu, &cu.arena)); 238 239 /* Gathering opcode stats? */ 240 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { 241 cu.mir_graph->EnableOpcodeCounting(); 242 } 243 244 /* Build the raw MIR graph */ 245 cu.mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, 246 class_loader, dex_file); 247 248 cu.NewTimingSplit("MIROpt:CheckFilters"); 249#if !defined(ART_USE_PORTABLE_COMPILER) 250 if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) { 251 return NULL; 252 } 253#endif 254 255 /* Create the pass driver and launch it */ 256 PassDriver driver(&cu); 257 driver.Launch(); 258 259 if (cu.enable_debug & (1 << kDebugDumpCheckStats)) { 260 cu.mir_graph->DumpCheckStats(); 261 } 262 263 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) { 264 cu.mir_graph->ShowOpcodeStats(); 265 } 266 267 /* Reassociate sreg names with original Dalvik vreg names. */ 268 cu.mir_graph->RemapRegLocations(); 269 270 CompiledMethod* result = NULL; 271 272#if defined(ART_USE_PORTABLE_COMPILER) 273 if (compiler_backend == kPortable) { 274 cu.cg.reset(PortableCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena, llvm_compilation_unit)); 275 } else { 276#endif 277 switch (compiler.GetInstructionSet()) { 278 case kThumb2: 279 cu.cg.reset(ArmCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena)); 280 break; 281 case kMips: 282 cu.cg.reset(MipsCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena)); 283 break; 284 case kX86: 285 cu.cg.reset(X86CodeGenerator(&cu, cu.mir_graph.get(), &cu.arena)); 286 break; 287 default: 288 LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet(); 289 } 290#if defined(ART_USE_PORTABLE_COMPILER) 291 } 292#endif 293 294 cu.cg->Materialize(); 295 296 cu.NewTimingSplit("Dedupe"); /* deduping takes up the vast majority of time in GetCompiledMethod(). */ 297 result = cu.cg->GetCompiledMethod(); 298 cu.NewTimingSplit("Cleanup"); 299 300 if (result) { 301 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file); 302 } else { 303 VLOG(compiler) << "Deferred " << PrettyMethod(method_idx, dex_file); 304 } 305 306 if (cu.enable_debug & (1 << kDebugShowMemoryUsage)) { 307 if (cu.arena.BytesAllocated() > (5 * 1024 *1024)) { 308 MemStats mem_stats(cu.arena); 309 LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats); 310 } 311 } 312 313 if (cu.enable_debug & (1 << kDebugShowSummaryMemoryUsage)) { 314 LOG(INFO) << "MEMINFO " << cu.arena.BytesAllocated() << " " << cu.mir_graph->GetNumBlocks() 315 << " " << PrettyMethod(method_idx, dex_file); 316 } 317 318 cu.EndTiming(); 319 return result; 320} 321 322CompiledMethod* CompileOneMethod(CompilerDriver& compiler, 323 const CompilerBackend backend, 324 const DexFile::CodeItem* code_item, 325 uint32_t access_flags, 326 InvokeType invoke_type, 327 uint16_t class_def_idx, 328 uint32_t method_idx, 329 jobject class_loader, 330 const DexFile& dex_file, 331 llvm::LlvmCompilationUnit* llvm_compilation_unit) { 332 return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx, 333 method_idx, class_loader, dex_file 334#if defined(ART_USE_PORTABLE_COMPILER) 335 , llvm_compilation_unit 336#endif 337 ); // NOLINT(whitespace/parens) 338} 339 340} // namespace art 341 342extern "C" art::CompiledMethod* 343 ArtQuickCompileMethod(art::CompilerDriver& compiler, 344 const art::DexFile::CodeItem* code_item, 345 uint32_t access_flags, art::InvokeType invoke_type, 346 uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, 347 const art::DexFile& dex_file) { 348 // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default 349 art::CompilerBackend backend = compiler.GetCompilerBackend(); 350 return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type, 351 class_def_idx, method_idx, class_loader, dex_file, 352 NULL /* use thread llvm_info */); 353} 354