1 /*
2 * Copyright (C) 2023 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_builder.h"
18
19 #include "art_method-inl.h"
20 #include "code_generator.h"
21 #include "driver/compiler_options.h"
22 #include "dex/code_item_accessors-inl.h"
23 #include "inliner.h"
24 #include "jit/profiling_info.h"
25 #include "optimizing_compiler_stats.h"
26 #include "scoped_thread_state_change-inl.h"
27
28 namespace art HIDDEN {
29
Run()30 void ProfilingInfoBuilder::Run() {
31 DCHECK(GetGraph()->IsUsefulOptimizing());
32 DCHECK_EQ(GetGraph()->GetProfilingInfo(), nullptr);
33 // Order does not matter.
34 for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
35 // No need to visit the phis.
36 VisitNonPhiInstructions(block);
37 }
38
39 ScopedObjectAccess soa(Thread::Current());
40 GetGraph()->SetProfilingInfo(
41 ProfilingInfo::Create(soa.Self(), GetGraph()->GetArtMethod(), inline_caches_));
42 }
43
44
EncodeInlinedDexPc(const HInliner * inliner,const CompilerOptions & compiler_options,HInvoke * invoke)45 uint32_t ProfilingInfoBuilder::EncodeInlinedDexPc(const HInliner* inliner,
46 const CompilerOptions& compiler_options,
47 HInvoke* invoke) {
48 DCHECK(inliner->GetCallerEnvironment() != nullptr);
49 DCHECK(inliner->GetParent() != nullptr);
50 std::vector<uint32_t> temp_vector;
51 temp_vector.push_back(invoke->GetDexPc());
52 while (inliner->GetCallerEnvironment() != nullptr) {
53 temp_vector.push_back(inliner->GetCallerEnvironment()->GetDexPc());
54 inliner = inliner->GetParent();
55 }
56
57 DCHECK_EQ(inliner->GetOutermostGraph(), inliner->GetGraph());
58 return InlineCache::EncodeDexPc(
59 inliner->GetOutermostGraph()->GetArtMethod(),
60 temp_vector,
61 compiler_options.GetInlineMaxCodeUnits());
62 }
63
EncodeDexPc(HInvoke * invoke,const CompilerOptions & compiler_options)64 static uint32_t EncodeDexPc(HInvoke* invoke, const CompilerOptions& compiler_options) {
65 std::vector<uint32_t> dex_pcs;
66 ArtMethod* outer_method = nullptr;
67 for (HEnvironment* environment = invoke->GetEnvironment();
68 environment != nullptr;
69 environment = environment->GetParent()) {
70 outer_method = environment->GetMethod();
71 dex_pcs.push_back(environment->GetDexPc());
72 }
73
74 ScopedObjectAccess soa(Thread::Current());
75 return InlineCache::EncodeDexPc(
76 outer_method,
77 dex_pcs,
78 compiler_options.GetInlineMaxCodeUnits());
79 }
80
HandleInvoke(HInvoke * invoke)81 void ProfilingInfoBuilder::HandleInvoke(HInvoke* invoke) {
82 if (IsInlineCacheUseful(invoke, codegen_)) {
83 uint32_t dex_pc = EncodeDexPc(invoke, compiler_options_);
84 if (dex_pc != kNoDexPc) {
85 inline_caches_.push_back(dex_pc);
86 } else {
87 ScopedObjectAccess soa(Thread::Current());
88 LOG(WARNING) << "Could not encode dex pc for "
89 << invoke->GetResolvedMethod()->PrettyMethod();
90 }
91 }
92 }
93
VisitInvokeInterface(HInvokeInterface * invoke)94 void ProfilingInfoBuilder::VisitInvokeInterface(HInvokeInterface* invoke) {
95 HandleInvoke(invoke);
96 }
97
VisitInvokeVirtual(HInvokeVirtual * invoke)98 void ProfilingInfoBuilder::VisitInvokeVirtual(HInvokeVirtual* invoke) {
99 HandleInvoke(invoke);
100 }
101
IsInlineCacheUseful(HInvoke * invoke,CodeGenerator * codegen)102 bool ProfilingInfoBuilder::IsInlineCacheUseful(HInvoke* invoke, CodeGenerator* codegen) {
103 DCHECK(invoke->IsInvokeVirtual() || invoke->IsInvokeInterface());
104 if (codegen->IsImplementedIntrinsic(invoke)) {
105 return false;
106 }
107 if (!invoke->GetBlock()->GetGraph()->IsCompilingBaseline()) {
108 return false;
109 }
110 if (Runtime::Current()->IsAotCompiler()) {
111 return false;
112 }
113 if (invoke->InputAt(0)->GetReferenceTypeInfo().IsExact()) {
114 return false;
115 }
116 if (invoke->GetResolvedMethod() != nullptr) {
117 ScopedObjectAccess soa(Thread::Current());
118 if (invoke->GetResolvedMethod()->IsFinal() ||
119 invoke->GetResolvedMethod()->GetDeclaringClass()->IsFinal()) {
120 return false;
121 }
122 }
123
124 if (!codegen->GetGraph()->IsUsefulOptimizing()) {
125 // Earlier pass knew what the calling target was. No need for an inline
126 // cache.
127 return false;
128 }
129 return true;
130 }
131
GetInlineCache(ProfilingInfo * info,const CompilerOptions & compiler_options,HInvoke * instruction)132 InlineCache* ProfilingInfoBuilder::GetInlineCache(ProfilingInfo* info,
133 const CompilerOptions& compiler_options,
134 HInvoke* instruction) {
135 ScopedObjectAccess soa(Thread::Current());
136 uint32_t dex_pc = EncodeDexPc(instruction, compiler_options);
137 if (dex_pc == kNoDexPc) {
138 return nullptr;
139 }
140 return info->GetInlineCache(dex_pc);
141 }
142
143 } // namespace art
144