diff options
-rw-r--r-- | compiler/Android.bp | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 35 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 40 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.cc | 50 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 46 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 34 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 17 | ||||
-rw-r--r-- | compiler/optimizing/profiling_info_builder.cc | 89 | ||||
-rw-r--r-- | compiler/optimizing/profiling_info_builder.h | 60 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 12 | ||||
-rw-r--r-- | runtime/jit/profiling_info.cc | 16 | ||||
-rw-r--r-- | runtime/jit/profiling_info.h | 4 | ||||
-rw-r--r-- | test/570-checker-osr/osr.cc | 15 | ||||
-rw-r--r-- | test/570-checker-osr/src/Main.java | 5 | ||||
-rw-r--r-- | test/595-profile-saving/expected-stdout.txt | 1 | ||||
-rw-r--r-- | test/595-profile-saving/profile-saving.cc | 11 | ||||
-rw-r--r-- | test/595-profile-saving/run.py | 2 | ||||
-rw-r--r-- | test/595-profile-saving/src/Main.java | 15 | ||||
-rw-r--r-- | test/common/runtime_state.cc | 1 |
19 files changed, 154 insertions, 300 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index e0c1744ce3..4427cd0f22 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -177,7 +177,6 @@ art_cc_defaults { "optimizing/optimizing_compiler.cc", "optimizing/parallel_move_resolver.cc", "optimizing/prepare_for_register_allocation.cc", - "optimizing/profiling_info_builder.cc", "optimizing/reference_type_propagation.cc", "optimizing/register_allocation_resolver.cc", "optimizing/register_allocator.cc", diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 4be0542236..4f5db1f1c2 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -45,7 +45,6 @@ #include "offsets.h" #include "optimizing/common_arm64.h" #include "optimizing/nodes.h" -#include "profiling_info_builder.h" #include "thread.h" #include "trace.h" #include "utils/arm64/assembler_arm64.h" @@ -4594,26 +4593,24 @@ void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) { void CodeGeneratorARM64::MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass) { DCHECK_EQ(klass.GetCode(), 0u); - if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke())) { + // We know the destination of an intrinsic, so no need to record inline + // caches. + if (!instruction->GetLocations()->Intrinsified() && + GetGraph()->IsCompilingBaseline() && + !Runtime::Current()->IsAotCompiler()) { + DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke()); ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); - if (cache != nullptr) { - uint64_t address = reinterpret_cast64<uint64_t>(cache); - vixl::aarch64::Label done; - __ Mov(x8, address); - __ Ldr(w9, MemOperand(x8, InlineCache::ClassesOffset().Int32Value())); - // Fast path for a monomorphic cache. - __ Cmp(klass.W(), w9); - __ B(eq, &done); - InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc()); - __ Bind(&done); - } else { - // This is unexpected, but we don't guarantee stable compilation across - // JIT runs so just warn about it. - ScopedObjectAccess soa(Thread::Current()); - LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod(); - } + InlineCache* cache = info->GetInlineCache(instruction->GetDexPc()); + uint64_t address = reinterpret_cast64<uint64_t>(cache); + vixl::aarch64::Label done; + __ Mov(x8, address); + __ Ldr(w9, MemOperand(x8, InlineCache::ClassesOffset().Int32Value())); + // Fast path for a monomorphic cache. + __ Cmp(klass.W(), w9); + __ B(eq, &done); + InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc()); + __ Bind(&done); } } diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 627c9bcf0b..dacf034327 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -39,7 +39,6 @@ #include "mirror/array-inl.h" #include "mirror/class-inl.h" #include "mirror/var_handle.h" -#include "profiling_info_builder.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "trace.h" @@ -3685,27 +3684,26 @@ void LocationsBuilderARMVIXL::VisitInvokeInterface(HInvokeInterface* invoke) { void CodeGeneratorARMVIXL::MaybeGenerateInlineCacheCheck(HInstruction* instruction, vixl32::Register klass) { DCHECK_EQ(r0.GetCode(), klass.GetCode()); - if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke())) { + // We know the destination of an intrinsic, so no need to record inline + // caches. + if (!instruction->GetLocations()->Intrinsified() && + GetGraph()->IsCompilingBaseline() && + !Runtime::Current()->IsAotCompiler()) { + DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke()); ProfilingInfo* info = GetGraph()->GetProfilingInfo(); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); - if (cache != nullptr) { - uint32_t address = reinterpret_cast32<uint32_t>(cache); - vixl32::Label done; - UseScratchRegisterScope temps(GetVIXLAssembler()); - temps.Exclude(ip); - __ Mov(r4, address); - __ Ldr(ip, MemOperand(r4, InlineCache::ClassesOffset().Int32Value())); - // Fast path for a monomorphic cache. - __ Cmp(klass, ip); - __ B(eq, &done, /* is_far_target= */ false); - InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc()); - __ Bind(&done); - } else { - // This is unexpected, but we don't guarantee stable compilation across - // JIT runs so just warn about it. - ScopedObjectAccess soa(Thread::Current()); - LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod(); - } + DCHECK(info != nullptr); + InlineCache* cache = info->GetInlineCache(instruction->GetDexPc()); + uint32_t address = reinterpret_cast32<uint32_t>(cache); + vixl32::Label done; + UseScratchRegisterScope temps(GetVIXLAssembler()); + temps.Exclude(ip); + __ Mov(r4, address); + __ Ldr(ip, MemOperand(r4, InlineCache::ClassesOffset().Int32Value())); + // Fast path for a monomorphic cache. + __ Cmp(klass, ip); + __ B(eq, &done, /* is_far_target= */ false); + InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc()); + __ Bind(&done); } } diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index f5b16d43d1..1e1dd4ab3b 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -34,7 +34,6 @@ #include "linker/linker_patch.h" #include "mirror/class-inl.h" #include "optimizing/nodes.h" -#include "optimizing/profiling_info_builder.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "stack_map_stream.h" @@ -6721,35 +6720,32 @@ void CodeGeneratorRISCV64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* inv void CodeGeneratorRISCV64::MaybeGenerateInlineCacheCheck(HInstruction* instruction, XRegister klass) { - if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke())) { + // We know the destination of an intrinsic, so no need to record inline caches. + if (!instruction->GetLocations()->Intrinsified() && + GetGraph()->IsCompilingBaseline() && + !Runtime::Current()->IsAotCompiler()) { + DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke()); ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); - if (cache != nullptr) { - uint64_t address = reinterpret_cast64<uint64_t>(cache); - Riscv64Label done; - // The `art_quick_update_inline_cache` expects the inline cache in T5. - XRegister ic_reg = T5; - ScratchRegisterScope srs(GetAssembler()); - DCHECK_EQ(srs.AvailableXRegisters(), 2u); - srs.ExcludeXRegister(ic_reg); - DCHECK_EQ(srs.AvailableXRegisters(), 1u); - __ LoadConst64(ic_reg, address); - { - ScratchRegisterScope srs2(GetAssembler()); - XRegister tmp = srs2.AllocateXRegister(); - __ Loadd(tmp, ic_reg, InlineCache::ClassesOffset().Int32Value()); - // Fast path for a monomorphic cache. - __ Beq(klass, tmp, &done); - } - InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc()); - __ Bind(&done); - } else { - // This is unexpected, but we don't guarantee stable compilation across - // JIT runs so just warn about it. - ScopedObjectAccess soa(Thread::Current()); - LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod(); + InlineCache* cache = info->GetInlineCache(instruction->GetDexPc()); + uint64_t address = reinterpret_cast64<uint64_t>(cache); + Riscv64Label done; + // The `art_quick_update_inline_cache` expects the inline cache in T5. + XRegister ic_reg = T5; + ScratchRegisterScope srs(GetAssembler()); + DCHECK_EQ(srs.AvailableXRegisters(), 2u); + srs.ExcludeXRegister(ic_reg); + DCHECK_EQ(srs.AvailableXRegisters(), 1u); + __ LoadConst64(ic_reg, address); + { + ScratchRegisterScope srs2(GetAssembler()); + XRegister tmp = srs2.AllocateXRegister(); + __ Loadd(tmp, ic_reg, InlineCache::ClassesOffset().Int32Value()); + // Fast path for a monomorphic cache. + __ Beq(klass, tmp, &done); } + InvokeRuntime(kQuickUpdateInlineCache, instruction, instruction->GetDexPc()); + __ Bind(&done); } } diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index f07860031d..a923e578c0 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -37,7 +37,6 @@ #include "mirror/class-inl.h" #include "mirror/var_handle.h" #include "optimizing/nodes.h" -#include "profiling_info_builder.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "trace.h" @@ -2799,7 +2798,7 @@ void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { HandleInvoke(invoke); - if (ProfilingInfoBuilder::IsInlineCacheUseful(invoke)) { + if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) { // Add one temporary for inline cache update. invoke->GetLocations()->AddTemp(Location::RegisterLocation(EBP)); } @@ -2827,7 +2826,7 @@ void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) { // Add the hidden argument. invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7)); - if (ProfilingInfoBuilder::IsInlineCacheUseful(invoke)) { + if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) { // Add one temporary for inline cache update. invoke->GetLocations()->AddTemp(Location::RegisterLocation(EBP)); } @@ -2845,30 +2844,29 @@ void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) { void CodeGeneratorX86::MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass) { DCHECK_EQ(EAX, klass); - if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke())) { + // We know the destination of an intrinsic, so no need to record inline + // caches (also the intrinsic location builder doesn't request an additional + // temporary). + if (!instruction->GetLocations()->Intrinsified() && + GetGraph()->IsCompilingBaseline() && + !Runtime::Current()->IsAotCompiler()) { + DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke()); ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); - if (cache != nullptr) { - uint32_t address = reinterpret_cast32<uint32_t>(cache); - if (kIsDebugBuild) { - uint32_t temp_index = instruction->GetLocations()->GetTempCount() - 1u; - CHECK_EQ(EBP, instruction->GetLocations()->GetTemp(temp_index).AsRegister<Register>()); - } - Register temp = EBP; - NearLabel done; - __ movl(temp, Immediate(address)); - // Fast path for a monomorphic cache. - __ cmpl(klass, Address(temp, InlineCache::ClassesOffset().Int32Value())); - __ j(kEqual, &done); - GenerateInvokeRuntime(GetThreadOffset<kX86PointerSize>(kQuickUpdateInlineCache).Int32Value()); - __ Bind(&done); - } else { - // This is unexpected, but we don't guarantee stable compilation across - // JIT runs so just warn about it. - ScopedObjectAccess soa(Thread::Current()); - LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod(); + InlineCache* cache = info->GetInlineCache(instruction->GetDexPc()); + uint32_t address = reinterpret_cast32<uint32_t>(cache); + if (kIsDebugBuild) { + uint32_t temp_index = instruction->GetLocations()->GetTempCount() - 1u; + CHECK_EQ(EBP, instruction->GetLocations()->GetTemp(temp_index).AsRegister<Register>()); } + Register temp = EBP; + NearLabel done; + __ movl(temp, Immediate(address)); + // Fast path for a monomorphic cache. + __ cmpl(klass, Address(temp, InlineCache::ClassesOffset().Int32Value())); + __ j(kEqual, &done); + GenerateInvokeRuntime(GetThreadOffset<kX86PointerSize>(kQuickUpdateInlineCache).Int32Value()); + __ Bind(&done); } } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index c777258201..24cb0c30b7 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -38,7 +38,6 @@ #include "mirror/object_reference.h" #include "mirror/var_handle.h" #include "optimizing/nodes.h" -#include "profiling_info_builder.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "trace.h" @@ -3095,26 +3094,23 @@ void LocationsBuilderX86_64::VisitInvokeInterface(HInvokeInterface* invoke) { void CodeGeneratorX86_64::MaybeGenerateInlineCacheCheck(HInstruction* instruction, CpuRegister klass) { DCHECK_EQ(RDI, klass.AsRegister()); - if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke())) { + // We know the destination of an intrinsic, so no need to record inline + // caches. + if (!instruction->GetLocations()->Intrinsified() && + GetGraph()->IsCompilingBaseline() && + !Runtime::Current()->IsAotCompiler()) { ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); - if (cache != nullptr) { - uint64_t address = reinterpret_cast64<uint64_t>(cache); - NearLabel done; - __ movq(CpuRegister(TMP), Immediate(address)); - // Fast path for a monomorphic cache. - __ cmpl(Address(CpuRegister(TMP), InlineCache::ClassesOffset().Int32Value()), klass); - __ j(kEqual, &done); - GenerateInvokeRuntime( - GetThreadOffset<kX86_64PointerSize>(kQuickUpdateInlineCache).Int32Value()); - __ Bind(&done); - } else { - // This is unexpected, but we don't guarantee stable compilation across - // JIT runs so just warn about it. - ScopedObjectAccess soa(Thread::Current()); - LOG(WARNING) << "Missing inline cache for " << GetGraph()->GetArtMethod()->PrettyMethod(); - } + InlineCache* cache = info->GetInlineCache(instruction->GetDexPc()); + uint64_t address = reinterpret_cast64<uint64_t>(cache); + NearLabel done; + __ movq(CpuRegister(TMP), Immediate(address)); + // Fast path for a monomorphic cache. + __ cmpl(Address(CpuRegister(TMP), InlineCache::ClassesOffset().Int32Value()), klass); + __ j(kEqual, &done); + GenerateInvokeRuntime( + GetThreadOffset<kX86_64PointerSize>(kQuickUpdateInlineCache).Int32Value()); + __ Bind(&done); } } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 2886e731b5..0069a20a26 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -53,7 +53,6 @@ #include "oat_quick_method_header.h" #include "optimizing/write_barrier_elimination.h" #include "prepare_for_register_allocation.h" -#include "profiling_info_builder.h" #include "reference_type_propagation.h" #include "register_allocator_linear_scan.h" #include "select_generator.h" @@ -836,6 +835,8 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, jit::Jit* jit = Runtime::Current()->GetJit(); if (jit != nullptr) { ProfilingInfo* info = jit->GetCodeCache()->GetProfilingInfo(method, Thread::Current()); + DCHECK_IMPLIES(compilation_kind == CompilationKind::kBaseline, info != nullptr) + << "Compiling a method baseline should always have a ProfilingInfo"; graph->SetProfilingInfo(info); } @@ -919,20 +920,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, &pass_observer, regalloc_strategy, compilation_stats_.get()); - // If we are compiling baseline and we haven't created a profiling info for - // this method already, do it now. - if (jit != nullptr && - compilation_kind == CompilationKind::kBaseline && - graph->GetProfilingInfo() == nullptr) { - ProfilingInfoBuilder(graph, codegen->GetCompilerOptions(), compilation_stats_.get()).Run(); - // We expect a profiling info to be created and attached to the graph. - // However, we may have run out of memory trying to create it, so in this - // case just abort the compilation. - if (graph->GetProfilingInfo() == nullptr) { - MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit); - return nullptr; - } - } codegen->Compile(); pass_observer.DumpDisassembly(); diff --git a/compiler/optimizing/profiling_info_builder.cc b/compiler/optimizing/profiling_info_builder.cc deleted file mode 100644 index 7e8cdb1454..0000000000 --- a/compiler/optimizing/profiling_info_builder.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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 "driver/compiler_options.h" -#include "dex/code_item_accessors-inl.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_EQ(GetGraph()->GetProfilingInfo(), nullptr); - // Order does not matter. - for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { - // No need to visit the phis. - for (HInstructionIteratorHandleChanges inst_it(block->GetInstructions()); !inst_it.Done(); - inst_it.Advance()) { - inst_it.Current()->Accept(this); - } - } - - ScopedObjectAccess soa(Thread::Current()); - GetGraph()->SetProfilingInfo( - ProfilingInfo::Create(soa.Self(), GetGraph()->GetArtMethod(), inline_caches_)); -} - -void ProfilingInfoBuilder::HandleInvoke(HInvoke* invoke) { - DCHECK(!invoke->GetEnvironment()->IsFromInlinedInvoke()); - if (IsInlineCacheUseful(invoke)) { - inline_caches_.push_back(invoke->GetDexPc()); - } -} - -void ProfilingInfoBuilder::VisitInvokeInterface(HInvokeInterface* invoke) { - HandleInvoke(invoke); -} - -void ProfilingInfoBuilder::VisitInvokeVirtual(HInvokeVirtual* invoke) { - HandleInvoke(invoke); -} - -bool ProfilingInfoBuilder::IsInlineCacheUseful(HInvoke* invoke) { - DCHECK(invoke->IsInvokeVirtual() || invoke->IsInvokeInterface()); - if (invoke->IsIntrinsic()) { - 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; - } - } - return true; -} - -InlineCache* ProfilingInfoBuilder::GetInlineCache(ProfilingInfo* info, HInvoke* instruction) { - DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke()); - ScopedObjectAccess soa(Thread::Current()); - return info->GetInlineCache(instruction->GetDexPc()); -} - -} // namespace art diff --git a/compiler/optimizing/profiling_info_builder.h b/compiler/optimizing/profiling_info_builder.h deleted file mode 100644 index 315b7de418..0000000000 --- a/compiler/optimizing/profiling_info_builder.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -#ifndef ART_COMPILER_OPTIMIZING_PROFILING_INFO_BUILDER_H_ -#define ART_COMPILER_OPTIMIZING_PROFILING_INFO_BUILDER_H_ - -#include "base/macros.h" -#include "nodes.h" - -namespace art HIDDEN { - -class CompilerOptions; -class InlineCache; -class ProfilingInfo; - -class ProfilingInfoBuilder : public HGraphDelegateVisitor { - public: - ProfilingInfoBuilder(HGraph* graph, - const CompilerOptions& compiler_options, - OptimizingCompilerStats* stats = nullptr) - : HGraphDelegateVisitor(graph, stats), - compiler_options_(compiler_options) {} - - void Run(); - - static constexpr const char* kProfilingInfoBuilderPassName = - "profiling_info_builder"; - - static InlineCache* GetInlineCache(ProfilingInfo* info, HInvoke* invoke); - static bool IsInlineCacheUseful(HInvoke* invoke); - - private: - void VisitInvokeVirtual(HInvokeVirtual* invoke) override; - void VisitInvokeInterface(HInvokeInterface* invoke) override; - - void HandleInvoke(HInvoke* invoke); - - [[maybe_unused]] const CompilerOptions& compiler_options_; - std::vector<uint32_t> inline_caches_; - - DISALLOW_COPY_AND_ASSIGN(ProfilingInfoBuilder); -}; - -} // namespace art - - -#endif // ART_COMPILER_OPTIMIZING_PROFILING_INFO_BUILDER_H_ diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index d05baf2c57..6a7820b207 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -1599,6 +1599,18 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, } else { if (compilation_kind == CompilationKind::kBaseline) { DCHECK(CanAllocateProfilingInfo()); + bool has_profiling_info = false; + { + MutexLock mu(self, *Locks::jit_lock_); + has_profiling_info = (profiling_infos_.find(method) != profiling_infos_.end()); + } + if (!has_profiling_info) { + if (ProfilingInfo::Create(self, method) == nullptr) { + VLOG(jit) << method->PrettyMethod() << " needs a ProfilingInfo to be compiled baseline"; + ClearMethodCounter(method, /*was_warm=*/ false); + return false; + } + } } } return true; diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc index 2e94a41093..31bee69896 100644 --- a/runtime/jit/profiling_info.cc +++ b/runtime/jit/profiling_info.cc @@ -50,16 +50,22 @@ uint16_t ProfilingInfo::GetOptimizeThreshold() { return Runtime::Current()->GetJITOptions()->GetOptimizeThreshold(); } -ProfilingInfo* ProfilingInfo::Create(Thread* self, - ArtMethod* method, - const std::vector<uint32_t>& inline_cache_entries) { +ProfilingInfo* ProfilingInfo::Create(Thread* self, ArtMethod* method) { // Walk over the dex instructions of the method and keep track of // instructions we are interested in profiling. DCHECK(!method->IsNative()); + std::vector<uint32_t> inline_cache_entries; std::vector<uint32_t> branch_cache_entries; for (const DexInstructionPcPair& inst : method->DexInstructions()) { switch (inst->Opcode()) { + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_VIRTUAL_RANGE: + case Instruction::INVOKE_INTERFACE: + case Instruction::INVOKE_INTERFACE_RANGE: + inline_cache_entries.push_back(inst.DexPc()); + break; + case Instruction::IF_EQ: case Instruction::IF_EQZ: case Instruction::IF_NE: @@ -96,7 +102,9 @@ InlineCache* ProfilingInfo::GetInlineCache(uint32_t dex_pc) { return &caches[i]; } } - return nullptr; + ScopedObjectAccess soa(Thread::Current()); + LOG(FATAL) << "No inline cache found for " << ArtMethod::PrettyMethod(method_) << "@" << dex_pc; + UNREACHABLE(); } BranchCache* ProfilingInfo::GetBranchCache(uint32_t dex_pc) { diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h index 62b431d7a2..219699421f 100644 --- a/runtime/jit/profiling_info.h +++ b/runtime/jit/profiling_info.h @@ -99,9 +99,7 @@ class BranchCache { class ProfilingInfo { public: // Create a ProfilingInfo for 'method'. - static ProfilingInfo* Create(Thread* self, - ArtMethod* method, - const std::vector<uint32_t>& inline_cache_entries) + static ProfilingInfo* Create(Thread* self, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Add information from an executed INVOKE instruction to the profile. diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc index 506887a8ea..d1caf3fc8c 100644 --- a/test/570-checker-osr/osr.cc +++ b/test/570-checker-osr/osr.cc @@ -98,6 +98,21 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInInterpreter(JNIEnv* env, return in_interpreter; } +extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasProfilingInfo(JNIEnv* env, + jclass, + jstring method_name) { + if (!Runtime::Current()->UseJitCompilation()) { + return; + } + ProcessMethodWithName( + env, + method_name, + [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* m = stack_visitor->GetMethod(); + ProfilingInfo::Create(Thread::Current(), m); + }); +} + extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasOsrCode(JNIEnv* env, jclass, jstring method_name) { diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java index 752d338bfa..78f3c32d2f 100644 --- a/test/570-checker-osr/src/Main.java +++ b/test/570-checker-osr/src/Main.java @@ -297,11 +297,8 @@ public class Main { public static native boolean isInOsrCode(String methodName); public static native boolean isInInterpreter(String methodName); - public static void ensureHasProfilingInfo(String methodName) { - ensureJitBaselineCompiled(Main.class, methodName); - } + public static native void ensureHasProfilingInfo(String methodName); public static native void ensureHasOsrCode(String methodName); - public static native void ensureJitBaselineCompiled(Class<?> cls, String methodName); } class SubMain extends Main { diff --git a/test/595-profile-saving/expected-stdout.txt b/test/595-profile-saving/expected-stdout.txt index 6a5618ebc6..9e28e07261 100644 --- a/test/595-profile-saving/expected-stdout.txt +++ b/test/595-profile-saving/expected-stdout.txt @@ -1 +1,2 @@ JNI_OnLoad called +IsForBootImage: true diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc index 912762c33d..bec4ae923f 100644 --- a/test/595-profile-saving/profile-saving.cc +++ b/test/595-profile-saving/profile-saving.cc @@ -32,6 +32,17 @@ namespace art { namespace { +extern "C" JNIEXPORT void JNICALL Java_Main_ensureProfilingInfo(JNIEnv* env, + jclass, + jobject method) { + CHECK(method != nullptr); + ScopedObjectAccess soa(env); + ObjPtr<mirror::Executable> exec = soa.Decode<mirror::Executable>(method); + ArtMethod* art_method = exec->GetArtMethod(); + if (ProfilingInfo::Create(soa.Self(), art_method) == nullptr) { + LOG(ERROR) << "Failed to create profiling info for method " << art_method->PrettyMethod(); + } +} extern "C" JNIEXPORT void JNICALL Java_Main_ensureProfileProcessing(JNIEnv*, jclass) { ProfileSaver::ForceProcessProfiles(); diff --git a/test/595-profile-saving/run.py b/test/595-profile-saving/run.py index 3375b0ebb4..599f76a6fc 100644 --- a/test/595-profile-saving/run.py +++ b/test/595-profile-saving/run.py @@ -20,6 +20,7 @@ def run(ctx, args): # --compiler-filter=verify to make sure that the test is not compiled AOT # and to make sure the test is not compiled when loaded (by PathClassLoader) # -Xjitsaveprofilinginfo to enable profile saving + # -Xusejit:false to disable jit and only test profiles. # -Xjitinitialsize:32M to prevent profiling info creation failure. ctx.default_run( args, @@ -28,5 +29,6 @@ def run(ctx, args): "-Xcompiler-option --compiler-filter=verify", "-Xjitinitialsize:32M", "-Xjitsaveprofilinginfo", + "-Xusejit:false", "-Xps-profile-boot-class-path", ]) diff --git a/test/595-profile-saving/src/Main.java b/test/595-profile-saving/src/Main.java index 8fdc4e1ede..3229b53d7d 100644 --- a/test/595-profile-saving/src/Main.java +++ b/test/595-profile-saving/src/Main.java @@ -23,11 +23,6 @@ public class Main { public static void main(String[] args) throws Exception { System.loadLibrary(args[0]); - if (!hasJit()) { - // Test requires JIT for creating profiling infos. - return; - } - File file = null; File file2 = null; File file3 = null; @@ -93,9 +88,7 @@ public class Main { testProfileNotExist(file2); - if (!isForBootImage(file.getPath())) { - throw new Error("Expected profile to be for boot image"); - } + System.out.println("IsForBootImage: " + isForBootImage(file.getPath())); } finally { if (file != null) { file.delete(); @@ -136,17 +129,13 @@ public class Main { } // Ensure a method has a profiling info. - public static void ensureProfilingInfo(Method method) { - ensureJitBaselineCompiled(method.getDeclaringClass(), method.getName()); - } - public static native void ensureJitBaselineCompiled(Class<?> cls, String methodName); + public static native void ensureProfilingInfo(Method method); // Ensures the profile saver does its usual processing. public static native void ensureProfileProcessing(); // Checks if the profiles saver knows about the method. public static native boolean presentInProfile(String profile, Method method); // Returns true if the profile is for the boot image. public static native boolean isForBootImage(String profile); - public static native boolean hasJit(); private static final String TEMP_FILE_NAME_PREFIX = "temp"; private static final String TEMP_FILE_NAME_SUFFIX = "-file"; diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index a530bd4794..c1c8936e9e 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -51,7 +51,6 @@ static jit::Jit* GetJitIfEnabled() { bool can_jit = runtime != nullptr && runtime->GetJit() != nullptr - && runtime->UseJitCompilation() && runtime->GetInstrumentation()->GetCurrentInstrumentationLevel() != instrumentation::Instrumentation::InstrumentationLevel::kInstrumentWithInterpreter; return can_jit ? runtime->GetJit() : nullptr; |