Home | History | Annotate | Download | only in jit
      1 /*
      2  * Copyright (C) 2015 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 "profiling_info.h"
     18 
     19 #include "art_method-inl.h"
     20 #include "dex_instruction.h"
     21 #include "jit/jit.h"
     22 #include "jit/jit_code_cache.h"
     23 #include "scoped_thread_state_change.h"
     24 #include "thread.h"
     25 
     26 namespace art {
     27 
     28 bool ProfilingInfo::Create(Thread* self, ArtMethod* method, bool retry_allocation) {
     29   // Walk over the dex instructions of the method and keep track of
     30   // instructions we are interested in profiling.
     31   DCHECK(!method->IsNative());
     32   const DexFile::CodeItem& code_item = *method->GetCodeItem();
     33   const uint16_t* code_ptr = code_item.insns_;
     34   const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
     35 
     36   uint32_t dex_pc = 0;
     37   std::vector<uint32_t> entries;
     38   while (code_ptr < code_end) {
     39     const Instruction& instruction = *Instruction::At(code_ptr);
     40     switch (instruction.Opcode()) {
     41       case Instruction::INVOKE_VIRTUAL:
     42       case Instruction::INVOKE_VIRTUAL_RANGE:
     43       case Instruction::INVOKE_VIRTUAL_QUICK:
     44       case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
     45       case Instruction::INVOKE_INTERFACE:
     46       case Instruction::INVOKE_INTERFACE_RANGE:
     47         entries.push_back(dex_pc);
     48         break;
     49 
     50       default:
     51         break;
     52     }
     53     dex_pc += instruction.SizeInCodeUnits();
     54     code_ptr += instruction.SizeInCodeUnits();
     55   }
     56 
     57   // We always create a `ProfilingInfo` object, even if there is no instruction we are
     58   // interested in. The JIT code cache internally uses it.
     59 
     60   // Allocate the `ProfilingInfo` object int the JIT's data space.
     61   jit::JitCodeCache* code_cache = Runtime::Current()->GetJit()->GetCodeCache();
     62   return code_cache->AddProfilingInfo(self, method, entries, retry_allocation) != nullptr;
     63 }
     64 
     65 InlineCache* ProfilingInfo::GetInlineCache(uint32_t dex_pc) {
     66   InlineCache* cache = nullptr;
     67   // TODO: binary search if array is too long.
     68   for (size_t i = 0; i < number_of_inline_caches_; ++i) {
     69     if (cache_[i].dex_pc_ == dex_pc) {
     70       cache = &cache_[i];
     71       break;
     72     }
     73   }
     74   return cache;
     75 }
     76 
     77 void ProfilingInfo::AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) {
     78   InlineCache* cache = GetInlineCache(dex_pc);
     79   CHECK(cache != nullptr) << PrettyMethod(method_) << "@" << dex_pc;
     80   for (size_t i = 0; i < InlineCache::kIndividualCacheSize; ++i) {
     81     mirror::Class* existing = cache->classes_[i].Read();
     82     if (existing == cls) {
     83       // Receiver type is already in the cache, nothing else to do.
     84       return;
     85     } else if (existing == nullptr) {
     86       // Cache entry is empty, try to put `cls` in it.
     87       GcRoot<mirror::Class> expected_root(nullptr);
     88       GcRoot<mirror::Class> desired_root(cls);
     89       if (!reinterpret_cast<Atomic<GcRoot<mirror::Class>>*>(&cache->classes_[i])->
     90               CompareExchangeStrongSequentiallyConsistent(expected_root, desired_root)) {
     91         // Some other thread put a class in the cache, continue iteration starting at this
     92         // entry in case the entry contains `cls`.
     93         --i;
     94       } else {
     95         // We successfully set `cls`, just return.
     96         return;
     97       }
     98     }
     99   }
    100   // Unsuccessfull - cache is full, making it megamorphic. We do not DCHECK it though,
    101   // as the garbage collector might clear the entries concurrently.
    102 }
    103 
    104 }  // namespace art
    105