/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "profiling_info_builder.h" #include "art_method-inl.h" #include "code_generator.h" #include "driver/compiler_options.h" #include "dex/code_item_accessors-inl.h" #include "inliner.h" #include "jit/profiling_info.h" #include "optimizing_compiler_stats.h" #include "scoped_thread_state_change-inl.h" namespace art HIDDEN { void ProfilingInfoBuilder::Run() { DCHECK(GetGraph()->IsUsefulOptimizing()); DCHECK_EQ(GetGraph()->GetProfilingInfo(), nullptr); // Order does not matter. for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { // No need to visit the phis. VisitNonPhiInstructions(block); } ScopedObjectAccess soa(Thread::Current()); GetGraph()->SetProfilingInfo( ProfilingInfo::Create(soa.Self(), GetGraph()->GetArtMethod(), inline_caches_)); } uint32_t ProfilingInfoBuilder::EncodeInlinedDexPc(const HInliner* inliner, const CompilerOptions& compiler_options, HInvoke* invoke) { DCHECK(inliner->GetCallerEnvironment() != nullptr); DCHECK(inliner->GetParent() != nullptr); std::vector temp_vector; temp_vector.push_back(invoke->GetDexPc()); while (inliner->GetCallerEnvironment() != nullptr) { temp_vector.push_back(inliner->GetCallerEnvironment()->GetDexPc()); inliner = inliner->GetParent(); } DCHECK_EQ(inliner->GetOutermostGraph(), inliner->GetGraph()); return InlineCache::EncodeDexPc( inliner->GetOutermostGraph()->GetArtMethod(), temp_vector, compiler_options.GetInlineMaxCodeUnits()); } static uint32_t EncodeDexPc(HInvoke* invoke, const CompilerOptions& compiler_options) { std::vector dex_pcs; ArtMethod* outer_method = nullptr; for (HEnvironment* environment = invoke->GetEnvironment(); environment != nullptr; environment = environment->GetParent()) { outer_method = environment->GetMethod(); dex_pcs.push_back(environment->GetDexPc()); } ScopedObjectAccess soa(Thread::Current()); return InlineCache::EncodeDexPc( outer_method, dex_pcs, compiler_options.GetInlineMaxCodeUnits()); } void ProfilingInfoBuilder::HandleInvoke(HInvoke* invoke) { if (IsInlineCacheUseful(invoke, codegen_)) { uint32_t dex_pc = EncodeDexPc(invoke, compiler_options_); if (dex_pc != kNoDexPc) { inline_caches_.push_back(dex_pc); } else { ScopedObjectAccess soa(Thread::Current()); LOG(WARNING) << "Could not encode dex pc for " << invoke->GetResolvedMethod()->PrettyMethod(); } } } void ProfilingInfoBuilder::VisitInvokeInterface(HInvokeInterface* invoke) { HandleInvoke(invoke); } void ProfilingInfoBuilder::VisitInvokeVirtual(HInvokeVirtual* invoke) { HandleInvoke(invoke); } bool ProfilingInfoBuilder::IsInlineCacheUseful(HInvoke* invoke, CodeGenerator* codegen) { DCHECK(invoke->IsInvokeVirtual() || invoke->IsInvokeInterface()); if (codegen->IsImplementedIntrinsic(invoke)) { return false; } if (!invoke->GetBlock()->GetGraph()->IsCompilingBaseline()) { return false; } if (Runtime::Current()->IsAotCompiler()) { return false; } if (invoke->InputAt(0)->GetReferenceTypeInfo().IsExact()) { return false; } if (invoke->GetResolvedMethod() != nullptr) { ScopedObjectAccess soa(Thread::Current()); if (invoke->GetResolvedMethod()->IsFinal() || invoke->GetResolvedMethod()->GetDeclaringClass()->IsFinal()) { return false; } } if (!codegen->GetGraph()->IsUsefulOptimizing()) { // Earlier pass knew what the calling target was. No need for an inline // cache. return false; } return true; } InlineCache* ProfilingInfoBuilder::GetInlineCache(ProfilingInfo* info, const CompilerOptions& compiler_options, HInvoke* instruction) { ScopedObjectAccess soa(Thread::Current()); uint32_t dex_pc = EncodeDexPc(instruction, compiler_options); if (dex_pc == kNoDexPc) { return nullptr; } return info->GetInlineCache(dex_pc); } } // namespace art