jit_compiler.cc revision bcd94c8ea9bde4e075c25fbdfb3a2ef6858eed7b
1/* 2 * Copyright 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 "jit_compiler.h" 18 19#include "arch/instruction_set.h" 20#include "arch/instruction_set_features.h" 21#include "art_method-inl.h" 22#include "base/stringpiece.h" 23#include "base/time_utils.h" 24#include "base/timing_logger.h" 25#include "base/unix_file/fd_file.h" 26#include "debug/elf_debug_writer.h" 27#include "driver/compiler_driver.h" 28#include "driver/compiler_options.h" 29#include "jit/debugger_interface.h" 30#include "jit/jit.h" 31#include "jit/jit_code_cache.h" 32#include "oat_file-inl.h" 33#include "oat_quick_method_header.h" 34#include "object_lock.h" 35#include "thread_list.h" 36 37namespace art { 38namespace jit { 39 40JitCompiler* JitCompiler::Create() { 41 return new JitCompiler(); 42} 43 44extern "C" void* jit_load(bool* generate_debug_info) { 45 VLOG(jit) << "loading jit compiler"; 46 auto* const jit_compiler = JitCompiler::Create(); 47 CHECK(jit_compiler != nullptr); 48 *generate_debug_info = jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo(); 49 VLOG(jit) << "Done loading jit compiler"; 50 return jit_compiler; 51} 52 53extern "C" void jit_unload(void* handle) { 54 DCHECK(handle != nullptr); 55 delete reinterpret_cast<JitCompiler*>(handle); 56} 57 58extern "C" bool jit_compile_method( 59 void* handle, ArtMethod* method, Thread* self, bool osr) 60 SHARED_REQUIRES(Locks::mutator_lock_) { 61 auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle); 62 DCHECK(jit_compiler != nullptr); 63 return jit_compiler->CompileMethod(self, method, osr); 64} 65 66extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t count) 67 SHARED_REQUIRES(Locks::mutator_lock_) { 68 auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle); 69 DCHECK(jit_compiler != nullptr); 70 if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) { 71 const ArrayRef<mirror::Class*> types_array(types, count); 72 ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForClasses(kRuntimeISA, types_array); 73 CreateJITCodeEntry(std::unique_ptr<const uint8_t[]>(elf_file.data()), elf_file.size()); 74 } 75} 76 77// Callers of this method assume it has NO_RETURN. 78NO_RETURN static void Usage(const char* fmt, ...) { 79 va_list ap; 80 va_start(ap, fmt); 81 std::string error; 82 StringAppendV(&error, fmt, ap); 83 LOG(FATAL) << error; 84 va_end(ap); 85 exit(EXIT_FAILURE); 86} 87 88JitCompiler::JitCompiler() { 89 compiler_options_.reset(new CompilerOptions( 90 CompilerOptions::kDefaultCompilerFilter, 91 CompilerOptions::kDefaultHugeMethodThreshold, 92 CompilerOptions::kDefaultLargeMethodThreshold, 93 CompilerOptions::kDefaultSmallMethodThreshold, 94 CompilerOptions::kDefaultTinyMethodThreshold, 95 CompilerOptions::kDefaultNumDexMethodsThreshold, 96 CompilerOptions::kDefaultInlineDepthLimit, 97 CompilerOptions::kDefaultInlineMaxCodeUnits, 98 /* no_inline_from */ nullptr, 99 /* include_patch_information */ false, 100 CompilerOptions::kDefaultTopKProfileThreshold, 101 Runtime::Current()->IsDebuggable(), 102 CompilerOptions::kDefaultGenerateDebugInfo, 103 /* implicit_null_checks */ true, 104 /* implicit_so_checks */ true, 105 /* implicit_suspend_checks */ false, 106 /* pic */ true, // TODO: Support non-PIC in optimizing. 107 /* verbose_methods */ nullptr, 108 /* init_failure_output */ nullptr, 109 /* abort_on_hard_verifier_failure */ false, 110 /* dump_cfg_file_name */ "", 111 /* dump_cfg_append */ false, 112 /* force_determinism */ false)); 113 for (const std::string& argument : Runtime::Current()->GetCompilerOptions()) { 114 compiler_options_->ParseCompilerOption(argument, Usage); 115 } 116 const InstructionSet instruction_set = kRuntimeISA; 117 for (const StringPiece option : Runtime::Current()->GetCompilerOptions()) { 118 VLOG(compiler) << "JIT compiler option " << option; 119 std::string error_msg; 120 if (option.starts_with("--instruction-set-variant=")) { 121 StringPiece str = option.substr(strlen("--instruction-set-variant=")).data(); 122 VLOG(compiler) << "JIT instruction set variant " << str; 123 instruction_set_features_.reset(InstructionSetFeatures::FromVariant( 124 instruction_set, str.as_string(), &error_msg)); 125 if (instruction_set_features_ == nullptr) { 126 LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; 127 } 128 } else if (option.starts_with("--instruction-set-features=")) { 129 StringPiece str = option.substr(strlen("--instruction-set-features=")).data(); 130 VLOG(compiler) << "JIT instruction set features " << str; 131 if (instruction_set_features_.get() == nullptr) { 132 instruction_set_features_.reset(InstructionSetFeatures::FromVariant( 133 instruction_set, "default", &error_msg)); 134 if (instruction_set_features_ == nullptr) { 135 LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; 136 } 137 } 138 instruction_set_features_.reset( 139 instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg)); 140 if (instruction_set_features_ == nullptr) { 141 LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; 142 } 143 } 144 } 145 if (instruction_set_features_ == nullptr) { 146 instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines()); 147 } 148 cumulative_logger_.reset(new CumulativeLogger("jit times")); 149 method_inliner_map_.reset(new DexFileToMethodInlinerMap); 150 compiler_driver_.reset(new CompilerDriver( 151 compiler_options_.get(), 152 /* verification_results */ nullptr, 153 method_inliner_map_.get(), 154 Compiler::kOptimizing, 155 instruction_set, 156 instruction_set_features_.get(), 157 /* image */ false, 158 /* image_classes */ nullptr, 159 /* compiled_classes */ nullptr, 160 /* compiled_methods */ nullptr, 161 /* thread_count */ 1, 162 /* dump_stats */ false, 163 /* dump_passes */ false, 164 cumulative_logger_.get(), 165 /* swap_fd */ -1, 166 /* profile_compilation_info */ nullptr)); 167 // Disable dedupe so we can remove compiled methods. 168 compiler_driver_->SetDedupeEnabled(false); 169 compiler_driver_->SetSupportBootImageFixup(false); 170 171 if (compiler_options_->GetGenerateDebugInfo()) { 172#ifdef __ANDROID__ 173 const char* prefix = "/data/misc/trace"; 174#else 175 const char* prefix = "/tmp"; 176#endif 177 DCHECK_EQ(compiler_driver_->GetThreadCount(), 1u) 178 << "Generating debug info only works with one compiler thread"; 179 std::string perf_filename = std::string(prefix) + "/perf-" + std::to_string(getpid()) + ".map"; 180 perf_file_.reset(OS::CreateEmptyFileWriteOnly(perf_filename.c_str())); 181 if (perf_file_ == nullptr) { 182 LOG(ERROR) << "Could not create perf file at " << perf_filename << 183 " Are you on a user build? Perf only works on userdebug/eng builds"; 184 } 185 } 186} 187 188JitCompiler::~JitCompiler() { 189 if (perf_file_ != nullptr) { 190 UNUSED(perf_file_->Flush()); 191 UNUSED(perf_file_->Close()); 192 } 193} 194 195bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) { 196 DCHECK(!method->IsProxyMethod()); 197 TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit)); 198 StackHandleScope<2> hs(self); 199 self->AssertNoPendingException(); 200 Runtime* runtime = Runtime::Current(); 201 202 // Ensure the class is initialized. 203 Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass())); 204 if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { 205 VLOG(jit) << "JIT failed to initialize " << PrettyMethod(method); 206 return false; 207 } 208 209 // Do the compilation. 210 bool success = false; 211 { 212 TimingLogger::ScopedTiming t2("Compiling", &logger); 213 JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache(); 214 success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method, osr); 215 if (success && (perf_file_ != nullptr)) { 216 const void* ptr = method->GetEntryPointFromQuickCompiledCode(); 217 std::ostringstream stream; 218 stream << std::hex 219 << reinterpret_cast<uintptr_t>(ptr) 220 << " " 221 << code_cache->GetMemorySizeOfCodePointer(ptr) 222 << " " 223 << PrettyMethod(method) 224 << std::endl; 225 std::string str = stream.str(); 226 bool res = perf_file_->WriteFully(str.c_str(), str.size()); 227 CHECK(res); 228 } 229 } 230 231 // Trim maps to reduce memory usage. 232 // TODO: move this to an idle phase. 233 { 234 TimingLogger::ScopedTiming t2("TrimMaps", &logger); 235 runtime->GetJitArenaPool()->TrimMaps(); 236 } 237 238 runtime->GetJit()->AddTimingLogger(logger); 239 return success; 240} 241 242} // namespace jit 243} // namespace art 244