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