Home | History | Annotate | Download | only in jit
      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 "art_method-inl.h"
     20 #include "arch/instruction_set.h"
     21 #include "arch/instruction_set_features.h"
     22 #include "base/time_utils.h"
     23 #include "base/timing_logger.h"
     24 #include "compiler_callbacks.h"
     25 #include "dex/pass_manager.h"
     26 #include "dex/quick_compiler_callbacks.h"
     27 #include "driver/compiler_driver.h"
     28 #include "driver/compiler_options.h"
     29 #include "jit/jit.h"
     30 #include "jit/jit_code_cache.h"
     31 #include "oat_file-inl.h"
     32 #include "object_lock.h"
     33 #include "thread_list.h"
     34 #include "verifier/method_verifier-inl.h"
     35 
     36 namespace art {
     37 namespace jit {
     38 
     39 JitCompiler* JitCompiler::Create() {
     40   return new JitCompiler();
     41 }
     42 
     43 extern "C" void* jit_load(CompilerCallbacks** callbacks) {
     44   VLOG(jit) << "loading jit compiler";
     45   auto* const jit_compiler = JitCompiler::Create();
     46   CHECK(jit_compiler != nullptr);
     47   *callbacks = jit_compiler->GetCompilerCallbacks();
     48   VLOG(jit) << "Done loading jit compiler";
     49   return jit_compiler;
     50 }
     51 
     52 extern "C" void jit_unload(void* handle) {
     53   DCHECK(handle != nullptr);
     54   delete reinterpret_cast<JitCompiler*>(handle);
     55 }
     56 
     57 extern "C" bool jit_compile_method(void* handle, ArtMethod* method, Thread* self)
     58     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     59   auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
     60   DCHECK(jit_compiler != nullptr);
     61   return jit_compiler->CompileMethod(self, method);
     62 }
     63 
     64 JitCompiler::JitCompiler() : total_time_(0) {
     65   auto* pass_manager_options = new PassManagerOptions;
     66   pass_manager_options->SetDisablePassList("GVN,DCE,GVNCleanup");
     67   compiler_options_.reset(new CompilerOptions(
     68       CompilerOptions::kDefaultCompilerFilter,
     69       CompilerOptions::kDefaultHugeMethodThreshold,
     70       CompilerOptions::kDefaultLargeMethodThreshold,
     71       CompilerOptions::kDefaultSmallMethodThreshold,
     72       CompilerOptions::kDefaultTinyMethodThreshold,
     73       CompilerOptions::kDefaultNumDexMethodsThreshold,
     74       CompilerOptions::kDefaultInlineDepthLimit,
     75       CompilerOptions::kDefaultInlineMaxCodeUnits,
     76       false,
     77       CompilerOptions::kDefaultTopKProfileThreshold,
     78       false,  // TODO: Think about debuggability of JIT-compiled code.
     79       CompilerOptions::kDefaultGenerateDebugInfo,
     80       false,
     81       false,
     82       false,
     83       false,  // pic
     84       nullptr,
     85       pass_manager_options,
     86       nullptr,
     87       false));
     88   const InstructionSet instruction_set = kRuntimeISA;
     89   instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
     90   cumulative_logger_.reset(new CumulativeLogger("jit times"));
     91   verification_results_.reset(new VerificationResults(compiler_options_.get()));
     92   method_inliner_map_.reset(new DexFileToMethodInlinerMap);
     93   callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
     94                                               method_inliner_map_.get(),
     95                                               CompilerCallbacks::CallbackMode::kCompileApp));
     96   compiler_driver_.reset(new CompilerDriver(
     97       compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(),
     98       Compiler::kQuick, instruction_set, instruction_set_features_.get(), false,
     99       nullptr, nullptr, nullptr, 1, false, true,
    100       std::string(), cumulative_logger_.get(), -1, std::string()));
    101   // Disable dedupe so we can remove compiled methods.
    102   compiler_driver_->SetDedupeEnabled(false);
    103   compiler_driver_->SetSupportBootImageFixup(false);
    104 }
    105 
    106 JitCompiler::~JitCompiler() {
    107 }
    108 
    109 bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method) {
    110   TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
    111   const uint64_t start_time = NanoTime();
    112   StackHandleScope<2> hs(self);
    113   self->AssertNoPendingException();
    114   Runtime* runtime = Runtime::Current();
    115   if (runtime->GetJit()->GetCodeCache()->ContainsMethod(method)) {
    116     VLOG(jit) << "Already compiled " << PrettyMethod(method);
    117     return true;  // Already compiled
    118   }
    119   Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass()));
    120   {
    121     TimingLogger::ScopedTiming t2("Initializing", &logger);
    122     if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) {
    123       VLOG(jit) << "JIT failed to initialize " << PrettyMethod(method);
    124       return false;
    125     }
    126   }
    127   const DexFile* dex_file = h_class->GetDexCache()->GetDexFile();
    128   MethodReference method_ref(dex_file, method->GetDexMethodIndex());
    129   // Only verify if we don't already have verification results.
    130   if (verification_results_->GetVerifiedMethod(method_ref) == nullptr) {
    131     TimingLogger::ScopedTiming t2("Verifying", &logger);
    132     std::string error;
    133     if (verifier::MethodVerifier::VerifyMethod(method, true, &error) ==
    134         verifier::MethodVerifier::kHardFailure) {
    135       VLOG(jit) << "Not compile method " << PrettyMethod(method)
    136           << " due to verification failure " << error;
    137       return false;
    138     }
    139   }
    140   CompiledMethod* compiled_method = nullptr;
    141   {
    142     TimingLogger::ScopedTiming t2("Compiling", &logger);
    143     compiled_method = compiler_driver_->CompileMethod(self, method);
    144   }
    145   {
    146     TimingLogger::ScopedTiming t2("TrimMaps", &logger);
    147     // Trim maps to reduce memory usage, TODO: measure how much this increases compile time.
    148     runtime->GetArenaPool()->TrimMaps();
    149   }
    150   if (compiled_method == nullptr) {
    151     return false;
    152   }
    153   total_time_ += NanoTime() - start_time;
    154   // Don't add the method if we are supposed to be deoptimized.
    155   bool result = false;
    156   if (!runtime->GetInstrumentation()->AreAllMethodsDeoptimized()) {
    157     const void* code = runtime->GetClassLinker()->GetOatMethodQuickCodeFor(method);
    158     if (code != nullptr) {
    159       // Already have some compiled code, just use this instead of linking.
    160       // TODO: Fix recompilation.
    161       method->SetEntryPointFromQuickCompiledCode(code);
    162       result = true;
    163     } else {
    164       TimingLogger::ScopedTiming t2("MakeExecutable", &logger);
    165       result = MakeExecutable(compiled_method, method);
    166     }
    167   }
    168   // Remove the compiled method to save memory.
    169   compiler_driver_->RemoveCompiledMethod(method_ref);
    170   runtime->GetJit()->AddTimingLogger(logger);
    171   return result;
    172 }
    173 
    174 CompilerCallbacks* JitCompiler::GetCompilerCallbacks() const {
    175   return callbacks_.get();
    176 }
    177 
    178 uint8_t* JitCompiler::WriteMethodHeaderAndCode(const CompiledMethod* compiled_method,
    179                                                uint8_t* reserve_begin, uint8_t* reserve_end,
    180                                                const uint8_t* mapping_table,
    181                                                const uint8_t* vmap_table,
    182                                                const uint8_t* gc_map) {
    183   reserve_begin += sizeof(OatQuickMethodHeader);
    184   reserve_begin = reinterpret_cast<uint8_t*>(
    185       compiled_method->AlignCode(reinterpret_cast<uintptr_t>(reserve_begin)));
    186   const auto* quick_code = compiled_method->GetQuickCode();
    187   CHECK_LE(reserve_begin, reserve_end);
    188   CHECK_LE(quick_code->size(), static_cast<size_t>(reserve_end - reserve_begin));
    189   auto* code_ptr = reserve_begin;
    190   OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(code_ptr) - 1;
    191   // Construct the header last.
    192   const auto frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
    193   const auto core_spill_mask = compiled_method->GetCoreSpillMask();
    194   const auto fp_spill_mask = compiled_method->GetFpSpillMask();
    195   const auto code_size = quick_code->size();
    196   CHECK_NE(code_size, 0U);
    197   std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr);
    198   // After we are done writing we need to update the method header.
    199   // Write out the method header last.
    200   method_header = new(method_header)OatQuickMethodHeader(
    201       code_ptr - mapping_table, code_ptr - vmap_table, code_ptr - gc_map, frame_size_in_bytes,
    202       core_spill_mask, fp_spill_mask, code_size);
    203   // Return the code ptr.
    204   return code_ptr;
    205 }
    206 
    207 bool JitCompiler::AddToCodeCache(ArtMethod* method, const CompiledMethod* compiled_method,
    208                                  OatFile::OatMethod* out_method) {
    209   Runtime* runtime = Runtime::Current();
    210   JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
    211   const auto* quick_code = compiled_method->GetQuickCode();
    212   if (quick_code == nullptr) {
    213     return false;
    214   }
    215   const auto code_size = quick_code->size();
    216   Thread* const self = Thread::Current();
    217   const uint8_t* base = code_cache->CodeCachePtr();
    218   auto* const mapping_table = compiled_method->GetMappingTable();
    219   auto* const vmap_table = compiled_method->GetVmapTable();
    220   auto* const gc_map = compiled_method->GetGcMap();
    221   CHECK(gc_map != nullptr) << PrettyMethod(method);
    222   // Write out pre-header stuff.
    223   uint8_t* const mapping_table_ptr = code_cache->AddDataArray(
    224       self, mapping_table->data(), mapping_table->data() + mapping_table->size());
    225   if (mapping_table_ptr == nullptr) {
    226     return false;  // Out of data cache.
    227   }
    228   uint8_t* const vmap_table_ptr = code_cache->AddDataArray(
    229       self, vmap_table->data(), vmap_table->data() + vmap_table->size());
    230   if (vmap_table_ptr == nullptr) {
    231     return false;  // Out of data cache.
    232   }
    233   uint8_t* const gc_map_ptr = code_cache->AddDataArray(
    234       self, gc_map->data(), gc_map->data() + gc_map->size());
    235   if (gc_map_ptr == nullptr) {
    236     return false;  // Out of data cache.
    237   }
    238   // Don't touch this until you protect / unprotect the code.
    239   const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32;
    240   uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size);
    241   if (code_reserve == nullptr) {
    242     return false;
    243   }
    244   auto* code_ptr = WriteMethodHeaderAndCode(
    245       compiled_method, code_reserve, code_reserve + reserve_size, mapping_table_ptr,
    246       vmap_table_ptr, gc_map_ptr);
    247 
    248   __builtin___clear_cache(reinterpret_cast<char*>(code_ptr),
    249                           reinterpret_cast<char*>(code_ptr + quick_code->size()));
    250 
    251   const size_t thumb_offset = compiled_method->CodeDelta();
    252   const uint32_t code_offset = code_ptr - base + thumb_offset;
    253   *out_method = OatFile::OatMethod(base, code_offset);
    254   DCHECK_EQ(out_method->GetGcMap(), gc_map_ptr);
    255   DCHECK_EQ(out_method->GetMappingTable(), mapping_table_ptr);
    256   DCHECK_EQ(out_method->GetVmapTable(), vmap_table_ptr);
    257   DCHECK_EQ(out_method->GetFrameSizeInBytes(), compiled_method->GetFrameSizeInBytes());
    258   DCHECK_EQ(out_method->GetCoreSpillMask(), compiled_method->GetCoreSpillMask());
    259   DCHECK_EQ(out_method->GetFpSpillMask(), compiled_method->GetFpSpillMask());
    260   VLOG(jit)  << "JIT added " << PrettyMethod(method) << "@" << method << " ccache_size="
    261       << PrettySize(code_cache->CodeCacheSize()) << ": " << reinterpret_cast<void*>(code_ptr)
    262       << "," << reinterpret_cast<void*>(code_ptr + code_size);
    263   return true;
    264 }
    265 
    266 bool JitCompiler::MakeExecutable(CompiledMethod* compiled_method, ArtMethod* method) {
    267   CHECK(method != nullptr);
    268   CHECK(compiled_method != nullptr);
    269   OatFile::OatMethod oat_method(nullptr, 0);
    270   if (!AddToCodeCache(method, compiled_method, &oat_method)) {
    271     return false;
    272   }
    273   // TODO: Flush instruction cache.
    274   oat_method.LinkMethod(method);
    275   CHECK(Runtime::Current()->GetJit()->GetCodeCache()->ContainsMethod(method))
    276       << PrettyMethod(method);
    277   return true;
    278 }
    279 
    280 }  // namespace jit
    281 }  // namespace art
    282