1 /*
2 * Copyright (C) 2014 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 "inliner.h"
18
19 #include "art_method-inl.h"
20 #include "base/enums.h"
21 #include "base/logging.h"
22 #include "builder.h"
23 #include "class_linker.h"
24 #include "class_root-inl.h"
25 #include "constant_folding.h"
26 #include "data_type-inl.h"
27 #include "dead_code_elimination.h"
28 #include "dex/inline_method_analyser.h"
29 #include "dex/verification_results.h"
30 #include "dex/verified_method.h"
31 #include "driver/compiler_options.h"
32 #include "driver/dex_compilation_unit.h"
33 #include "instruction_simplifier.h"
34 #include "intrinsics.h"
35 #include "jit/jit.h"
36 #include "jit/jit_code_cache.h"
37 #include "mirror/class_loader.h"
38 #include "mirror/dex_cache.h"
39 #include "mirror/object_array-alloc-inl.h"
40 #include "mirror/object_array-inl.h"
41 #include "nodes.h"
42 #include "reference_type_propagation.h"
43 #include "register_allocator_linear_scan.h"
44 #include "scoped_thread_state_change-inl.h"
45 #include "sharpening.h"
46 #include "ssa_builder.h"
47 #include "ssa_phi_elimination.h"
48 #include "thread.h"
49
50 namespace art {
51
52 // Instruction limit to control memory.
53 static constexpr size_t kMaximumNumberOfTotalInstructions = 1024;
54
55 // Maximum number of instructions for considering a method small,
56 // which we will always try to inline if the other non-instruction limits
57 // are not reached.
58 static constexpr size_t kMaximumNumberOfInstructionsForSmallMethod = 3;
59
60 // Limit the number of dex registers that we accumulate while inlining
61 // to avoid creating large amount of nested environments.
62 static constexpr size_t kMaximumNumberOfCumulatedDexRegisters = 32;
63
64 // Limit recursive call inlining, which do not benefit from too
65 // much inlining compared to code locality.
66 static constexpr size_t kMaximumNumberOfRecursiveCalls = 4;
67
68 // Controls the use of inline caches in AOT mode.
69 static constexpr bool kUseAOTInlineCaches = true;
70
71 // We check for line numbers to make sure the DepthString implementation
72 // aligns the output nicely.
73 #define LOG_INTERNAL(msg) \
74 static_assert(__LINE__ > 10, "Unhandled line number"); \
75 static_assert(__LINE__ < 10000, "Unhandled line number"); \
76 VLOG(compiler) << DepthString(__LINE__) << msg
77
78 #define LOG_TRY() LOG_INTERNAL("Try inlinining call: ")
79 #define LOG_NOTE() LOG_INTERNAL("Note: ")
80 #define LOG_SUCCESS() LOG_INTERNAL("Success: ")
81 #define LOG_FAIL(stats_ptr, stat) MaybeRecordStat(stats_ptr, stat); LOG_INTERNAL("Fail: ")
82 #define LOG_FAIL_NO_STAT() LOG_INTERNAL("Fail: ")
83
DepthString(int line) const84 std::string HInliner::DepthString(int line) const {
85 std::string value;
86 // Indent according to the inlining depth.
87 size_t count = depth_;
88 // Line numbers get printed in the log, so add a space if the log's line is less
89 // than 1000, and two if less than 100. 10 cannot be reached as it's the copyright.
90 if (!kIsTargetBuild) {
91 if (line < 100) {
92 value += " ";
93 }
94 if (line < 1000) {
95 value += " ";
96 }
97 // Safeguard if this file reaches more than 10000 lines.
98 DCHECK_LT(line, 10000);
99 }
100 for (size_t i = 0; i < count; ++i) {
101 value += " ";
102 }
103 return value;
104 }
105
CountNumberOfInstructions(HGraph * graph)106 static size_t CountNumberOfInstructions(HGraph* graph) {
107 size_t number_of_instructions = 0;
108 for (HBasicBlock* block : graph->GetReversePostOrderSkipEntryBlock()) {
109 for (HInstructionIterator instr_it(block->GetInstructions());
110 !instr_it.Done();
111 instr_it.Advance()) {
112 ++number_of_instructions;
113 }
114 }
115 return number_of_instructions;
116 }
117
UpdateInliningBudget()118 void HInliner::UpdateInliningBudget() {
119 if (total_number_of_instructions_ >= kMaximumNumberOfTotalInstructions) {
120 // Always try to inline small methods.
121 inlining_budget_ = kMaximumNumberOfInstructionsForSmallMethod;
122 } else {
123 inlining_budget_ = std::max(
124 kMaximumNumberOfInstructionsForSmallMethod,
125 kMaximumNumberOfTotalInstructions - total_number_of_instructions_);
126 }
127 }
128
Run()129 bool HInliner::Run() {
130 if (codegen_->GetCompilerOptions().GetInlineMaxCodeUnits() == 0) {
131 // Inlining effectively disabled.
132 return false;
133 } else if (graph_->IsDebuggable()) {
134 // For simplicity, we currently never inline when the graph is debuggable. This avoids
135 // doing some logic in the runtime to discover if a method could have been inlined.
136 return false;
137 }
138
139 bool didInline = false;
140
141 // Initialize the number of instructions for the method being compiled. Recursive calls
142 // to HInliner::Run have already updated the instruction count.
143 if (outermost_graph_ == graph_) {
144 total_number_of_instructions_ = CountNumberOfInstructions(graph_);
145 }
146
147 UpdateInliningBudget();
148 DCHECK_NE(total_number_of_instructions_, 0u);
149 DCHECK_NE(inlining_budget_, 0u);
150
151 // If we're compiling tests, honor inlining directives in method names:
152 // - if a method's name contains the substring "$noinline$", do not
153 // inline that method;
154 // - if a method's name contains the substring "$inline$", ensure
155 // that this method is actually inlined.
156 // We limit the latter to AOT compilation, as the JIT may or may not inline
157 // depending on the state of classes at runtime.
158 const bool honor_noinline_directives = codegen_->GetCompilerOptions().CompileArtTest();
159 const bool honor_inline_directives =
160 honor_noinline_directives && Runtime::Current()->IsAotCompiler();
161
162 // Keep a copy of all blocks when starting the visit.
163 ArenaVector<HBasicBlock*> blocks = graph_->GetReversePostOrder();
164 DCHECK(!blocks.empty());
165 // Because we are changing the graph when inlining,
166 // we just iterate over the blocks of the outer method.
167 // This avoids doing the inlining work again on the inlined blocks.
168 for (HBasicBlock* block : blocks) {
169 for (HInstruction* instruction = block->GetFirstInstruction(); instruction != nullptr;) {
170 HInstruction* next = instruction->GetNext();
171 HInvoke* call = instruction->AsInvoke();
172 // As long as the call is not intrinsified, it is worth trying to inline.
173 if (call != nullptr && call->GetIntrinsic() == Intrinsics::kNone) {
174 if (honor_noinline_directives) {
175 // Debugging case: directives in method names control or assert on inlining.
176 std::string callee_name =
177 call->GetMethodReference().PrettyMethod(/* with_signature= */ false);
178 // Tests prevent inlining by having $noinline$ in their method names.
179 if (callee_name.find("$noinline$") == std::string::npos) {
180 if (TryInline(call)) {
181 didInline = true;
182 } else if (honor_inline_directives) {
183 bool should_have_inlined = (callee_name.find("$inline$") != std::string::npos);
184 CHECK(!should_have_inlined) << "Could not inline " << callee_name;
185 }
186 }
187 } else {
188 DCHECK(!honor_inline_directives);
189 // Normal case: try to inline.
190 if (TryInline(call)) {
191 didInline = true;
192 }
193 }
194 }
195 instruction = next;
196 }
197 }
198
199 return didInline;
200 }
201
IsMethodOrDeclaringClassFinal(ArtMethod * method)202 static bool IsMethodOrDeclaringClassFinal(ArtMethod* method)
203 REQUIRES_SHARED(Locks::mutator_lock_) {
204 return method->IsFinal() || method->GetDeclaringClass()->IsFinal();
205 }
206
207 /**
208 * Given the `resolved_method` looked up in the dex cache, try to find
209 * the actual runtime target of an interface or virtual call.
210 * Return nullptr if the runtime target cannot be proven.
211 */
FindVirtualOrInterfaceTarget(HInvoke * invoke)212 static ArtMethod* FindVirtualOrInterfaceTarget(HInvoke* invoke)
213 REQUIRES_SHARED(Locks::mutator_lock_) {
214 ArtMethod* resolved_method = invoke->GetResolvedMethod();
215 if (IsMethodOrDeclaringClassFinal(resolved_method)) {
216 // No need to lookup further, the resolved method will be the target.
217 return resolved_method;
218 }
219
220 HInstruction* receiver = invoke->InputAt(0);
221 if (receiver->IsNullCheck()) {
222 // Due to multiple levels of inlining within the same pass, it might be that
223 // null check does not have the reference type of the actual receiver.
224 receiver = receiver->InputAt(0);
225 }
226 ReferenceTypeInfo info = receiver->GetReferenceTypeInfo();
227 DCHECK(info.IsValid()) << "Invalid RTI for " << receiver->DebugName();
228 if (!info.IsExact()) {
229 // We currently only support inlining with known receivers.
230 // TODO: Remove this check, we should be able to inline final methods
231 // on unknown receivers.
232 return nullptr;
233 } else if (info.GetTypeHandle()->IsInterface()) {
234 // Statically knowing that the receiver has an interface type cannot
235 // help us find what is the target method.
236 return nullptr;
237 } else if (!resolved_method->GetDeclaringClass()->IsAssignableFrom(info.GetTypeHandle().Get())) {
238 // The method that we're trying to call is not in the receiver's class or super classes.
239 return nullptr;
240 } else if (info.GetTypeHandle()->IsErroneous()) {
241 // If the type is erroneous, do not go further, as we are going to query the vtable or
242 // imt table, that we can only safely do on non-erroneous classes.
243 return nullptr;
244 }
245
246 ClassLinker* cl = Runtime::Current()->GetClassLinker();
247 PointerSize pointer_size = cl->GetImagePointerSize();
248 if (invoke->IsInvokeInterface()) {
249 resolved_method = info.GetTypeHandle()->FindVirtualMethodForInterface(
250 resolved_method, pointer_size);
251 } else {
252 DCHECK(invoke->IsInvokeVirtual());
253 resolved_method = info.GetTypeHandle()->FindVirtualMethodForVirtual(
254 resolved_method, pointer_size);
255 }
256
257 if (resolved_method == nullptr) {
258 // The information we had on the receiver was not enough to find
259 // the target method. Since we check above the exact type of the receiver,
260 // the only reason this can happen is an IncompatibleClassChangeError.
261 return nullptr;
262 } else if (!resolved_method->IsInvokable()) {
263 // The information we had on the receiver was not enough to find
264 // the target method. Since we check above the exact type of the receiver,
265 // the only reason this can happen is an IncompatibleClassChangeError.
266 return nullptr;
267 } else if (IsMethodOrDeclaringClassFinal(resolved_method)) {
268 // A final method has to be the target method.
269 return resolved_method;
270 } else if (info.IsExact()) {
271 // If we found a method and the receiver's concrete type is statically
272 // known, we know for sure the target.
273 return resolved_method;
274 } else {
275 // Even if we did find a method, the receiver type was not enough to
276 // statically find the runtime target.
277 return nullptr;
278 }
279 }
280
FindMethodIndexIn(ArtMethod * method,const DexFile & dex_file,uint32_t name_and_signature_index)281 static uint32_t FindMethodIndexIn(ArtMethod* method,
282 const DexFile& dex_file,
283 uint32_t name_and_signature_index)
284 REQUIRES_SHARED(Locks::mutator_lock_) {
285 if (IsSameDexFile(*method->GetDexFile(), dex_file)) {
286 return method->GetDexMethodIndex();
287 } else {
288 return method->FindDexMethodIndexInOtherDexFile(dex_file, name_and_signature_index);
289 }
290 }
291
FindClassIndexIn(ObjPtr<mirror::Class> cls,const DexCompilationUnit & compilation_unit)292 static dex::TypeIndex FindClassIndexIn(ObjPtr<mirror::Class> cls,
293 const DexCompilationUnit& compilation_unit)
294 REQUIRES_SHARED(Locks::mutator_lock_) {
295 const DexFile& dex_file = *compilation_unit.GetDexFile();
296 dex::TypeIndex index;
297 if (cls->GetDexCache() == nullptr) {
298 DCHECK(cls->IsArrayClass()) << cls->PrettyClass();
299 index = cls->FindTypeIndexInOtherDexFile(dex_file);
300 } else if (!cls->GetDexTypeIndex().IsValid()) {
301 DCHECK(cls->IsProxyClass()) << cls->PrettyClass();
302 // TODO: deal with proxy classes.
303 } else if (IsSameDexFile(cls->GetDexFile(), dex_file)) {
304 DCHECK_EQ(cls->GetDexCache(), compilation_unit.GetDexCache().Get());
305 index = cls->GetDexTypeIndex();
306 } else {
307 index = cls->FindTypeIndexInOtherDexFile(dex_file);
308 // We cannot guarantee the entry will resolve to the same class,
309 // as there may be different class loaders. So only return the index if it's
310 // the right class already resolved with the class loader.
311 if (index.IsValid()) {
312 ObjPtr<mirror::Class> resolved = compilation_unit.GetClassLinker()->LookupResolvedType(
313 index, compilation_unit.GetDexCache().Get(), compilation_unit.GetClassLoader().Get());
314 if (resolved != cls) {
315 index = dex::TypeIndex::Invalid();
316 }
317 }
318 }
319
320 return index;
321 }
322
GetInlineCacheType(const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)323 HInliner::InlineCacheType HInliner::GetInlineCacheType(
324 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
325 DCHECK_EQ(classes.NumberOfReferences(), InlineCache::kIndividualCacheSize);
326 uint8_t number_of_types = InlineCache::kIndividualCacheSize - classes.RemainingSlots();
327 if (number_of_types == 0) {
328 return kInlineCacheUninitialized;
329 } else if (number_of_types == 1) {
330 return kInlineCacheMonomorphic;
331 } else if (number_of_types == InlineCache::kIndividualCacheSize) {
332 return kInlineCacheMegamorphic;
333 } else {
334 return kInlineCachePolymorphic;
335 }
336 }
337
GetMonomorphicType(const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)338 static inline ObjPtr<mirror::Class> GetMonomorphicType(
339 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes)
340 REQUIRES_SHARED(Locks::mutator_lock_) {
341 DCHECK(classes.GetReference(0) != nullptr);
342 return classes.GetReference(0)->AsClass();
343 }
344
FindMethodFromCHA(ArtMethod * resolved_method)345 ArtMethod* HInliner::FindMethodFromCHA(ArtMethod* resolved_method) {
346 if (!resolved_method->HasSingleImplementation()) {
347 return nullptr;
348 }
349 if (Runtime::Current()->IsAotCompiler()) {
350 // No CHA-based devirtulization for AOT compiler (yet).
351 return nullptr;
352 }
353 if (Runtime::Current()->IsZygote()) {
354 // No CHA-based devirtulization for Zygote, as it compiles with
355 // offline information.
356 return nullptr;
357 }
358 if (outermost_graph_->IsCompilingOsr()) {
359 // We do not support HDeoptimize in OSR methods.
360 return nullptr;
361 }
362 PointerSize pointer_size = caller_compilation_unit_.GetClassLinker()->GetImagePointerSize();
363 ArtMethod* single_impl = resolved_method->GetSingleImplementation(pointer_size);
364 if (single_impl == nullptr) {
365 return nullptr;
366 }
367 if (single_impl->IsProxyMethod()) {
368 // Proxy method is a generic invoker that's not worth
369 // devirtualizing/inlining. It also causes issues when the proxy
370 // method is in another dex file if we try to rewrite invoke-interface to
371 // invoke-virtual because a proxy method doesn't have a real dex file.
372 return nullptr;
373 }
374 if (!single_impl->GetDeclaringClass()->IsResolved()) {
375 // There's a race with the class loading, which updates the CHA info
376 // before setting the class to resolved. So we just bail for this
377 // rare occurence.
378 return nullptr;
379 }
380 return single_impl;
381 }
382
IsMethodUnverified(const CompilerOptions & compiler_options,ArtMethod * method)383 static bool IsMethodUnverified(const CompilerOptions& compiler_options, ArtMethod* method)
384 REQUIRES_SHARED(Locks::mutator_lock_) {
385 if (!method->GetDeclaringClass()->IsVerified()) {
386 if (compiler_options.IsJitCompiler()) {
387 // We're at runtime, we know this is cold code if the class
388 // is not verified, so don't bother analyzing.
389 return true;
390 }
391 uint16_t class_def_idx = method->GetDeclaringClass()->GetDexClassDefIndex();
392 if (!compiler_options.IsMethodVerifiedWithoutFailures(method->GetDexMethodIndex(),
393 class_def_idx,
394 *method->GetDexFile())) {
395 // Method has soft or hard failures, don't analyze.
396 return true;
397 }
398 }
399 return false;
400 }
401
AlwaysThrows(const CompilerOptions & compiler_options,ArtMethod * method)402 static bool AlwaysThrows(const CompilerOptions& compiler_options, ArtMethod* method)
403 REQUIRES_SHARED(Locks::mutator_lock_) {
404 DCHECK(method != nullptr);
405 // Skip non-compilable and unverified methods.
406 if (!method->IsCompilable() || IsMethodUnverified(compiler_options, method)) {
407 return false;
408 }
409 // Skip native methods, methods with try blocks, and methods that are too large.
410 CodeItemDataAccessor accessor(method->DexInstructionData());
411 if (!accessor.HasCodeItem() ||
412 accessor.TriesSize() != 0 ||
413 accessor.InsnsSizeInCodeUnits() > kMaximumNumberOfTotalInstructions) {
414 return false;
415 }
416 // Scan for exits.
417 bool throw_seen = false;
418 for (const DexInstructionPcPair& pair : accessor) {
419 switch (pair.Inst().Opcode()) {
420 case Instruction::RETURN:
421 case Instruction::RETURN_VOID:
422 case Instruction::RETURN_WIDE:
423 case Instruction::RETURN_OBJECT:
424 return false; // found regular control flow back
425 case Instruction::THROW:
426 throw_seen = true;
427 break;
428 default:
429 break;
430 }
431 }
432 return throw_seen;
433 }
434
TryInline(HInvoke * invoke_instruction)435 bool HInliner::TryInline(HInvoke* invoke_instruction) {
436 MaybeRecordStat(stats_, MethodCompilationStat::kTryInline);
437
438 // Don't bother to move further if we know the method is unresolved or the invocation is
439 // polymorphic (invoke-{polymorphic,custom}).
440 if (invoke_instruction->IsInvokeUnresolved()) {
441 MaybeRecordStat(stats_, MethodCompilationStat::kNotInlinedUnresolved);
442 return false;
443 } else if (invoke_instruction->IsInvokePolymorphic()) {
444 MaybeRecordStat(stats_, MethodCompilationStat::kNotInlinedPolymorphic);
445 return false;
446 } else if (invoke_instruction->IsInvokeCustom()) {
447 MaybeRecordStat(stats_, MethodCompilationStat::kNotInlinedCustom);
448 return false;
449 }
450
451 ScopedObjectAccess soa(Thread::Current());
452 LOG_TRY() << invoke_instruction->GetMethodReference().PrettyMethod();
453
454 ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
455 if (resolved_method == nullptr) {
456 DCHECK(invoke_instruction->IsInvokeStaticOrDirect());
457 DCHECK(invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit());
458 LOG_FAIL_NO_STAT() << "Not inlining a String.<init> method";
459 return false;
460 }
461
462 ArtMethod* actual_method = invoke_instruction->IsInvokeStaticOrDirect()
463 ? invoke_instruction->GetResolvedMethod()
464 : FindVirtualOrInterfaceTarget(invoke_instruction);
465
466 if (actual_method != nullptr) {
467 // Single target.
468 bool result = TryInlineAndReplace(invoke_instruction,
469 actual_method,
470 ReferenceTypeInfo::CreateInvalid(),
471 /* do_rtp= */ true);
472 if (result) {
473 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvokeVirtualOrInterface);
474 } else {
475 HInvoke* invoke_to_analyze = nullptr;
476 if (TryDevirtualize(invoke_instruction, actual_method, &invoke_to_analyze)) {
477 // Consider devirtualization as inlining.
478 result = true;
479 MaybeRecordStat(stats_, MethodCompilationStat::kDevirtualized);
480 } else {
481 invoke_to_analyze = invoke_instruction;
482 }
483 // Set always throws property for non-inlined method call with single
484 // target.
485 if (AlwaysThrows(codegen_->GetCompilerOptions(), actual_method)) {
486 invoke_to_analyze->SetAlwaysThrows(true);
487 }
488 }
489 return result;
490 }
491
492 DCHECK(!invoke_instruction->IsInvokeStaticOrDirect());
493
494 if (TryInlineFromCHA(invoke_instruction)) {
495 return true;
496 }
497 return TryInlineFromInlineCache(invoke_instruction);
498 }
499
TryInlineFromCHA(HInvoke * invoke_instruction)500 bool HInliner::TryInlineFromCHA(HInvoke* invoke_instruction) {
501 ArtMethod* method = FindMethodFromCHA(invoke_instruction->GetResolvedMethod());
502 if (method == nullptr) {
503 return false;
504 }
505 LOG_NOTE() << "Try CHA-based inlining of " << method->PrettyMethod();
506
507 uint32_t dex_pc = invoke_instruction->GetDexPc();
508 HInstruction* cursor = invoke_instruction->GetPrevious();
509 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
510 if (!TryInlineAndReplace(invoke_instruction,
511 method,
512 ReferenceTypeInfo::CreateInvalid(),
513 /* do_rtp= */ true)) {
514 return false;
515 }
516 AddCHAGuard(invoke_instruction, dex_pc, cursor, bb_cursor);
517 // Add dependency due to devirtualization: we are assuming the resolved method
518 // has a single implementation.
519 outermost_graph_->AddCHASingleImplementationDependency(invoke_instruction->GetResolvedMethod());
520 MaybeRecordStat(stats_, MethodCompilationStat::kCHAInline);
521 return true;
522 }
523
UseOnlyPolymorphicInliningWithNoDeopt()524 bool HInliner::UseOnlyPolymorphicInliningWithNoDeopt() {
525 // If we are compiling AOT or OSR, pretend the call using inline caches is polymorphic and
526 // do not generate a deopt.
527 //
528 // For AOT:
529 // Generating a deopt does not ensure that we will actually capture the new types;
530 // and the danger is that we could be stuck in a loop with "forever" deoptimizations.
531 // Take for example the following scenario:
532 // - we capture the inline cache in one run
533 // - the next run, we deoptimize because we miss a type check, but the method
534 // never becomes hot again
535 // In this case, the inline cache will not be updated in the profile and the AOT code
536 // will keep deoptimizing.
537 // Another scenario is if we use profile compilation for a process which is not allowed
538 // to JIT (e.g. system server). If we deoptimize we will run interpreted code for the
539 // rest of the lifetime.
540 // TODO(calin):
541 // This is a compromise because we will most likely never update the inline cache
542 // in the profile (unless there's another reason to deopt). So we might be stuck with
543 // a sub-optimal inline cache.
544 // We could be smarter when capturing inline caches to mitigate this.
545 // (e.g. by having different thresholds for new and old methods).
546 //
547 // For OSR:
548 // We may come from the interpreter and it may have seen different receiver types.
549 return Runtime::Current()->IsAotCompiler() || outermost_graph_->IsCompilingOsr();
550 }
TryInlineFromInlineCache(HInvoke * invoke_instruction)551 bool HInliner::TryInlineFromInlineCache(HInvoke* invoke_instruction)
552 REQUIRES_SHARED(Locks::mutator_lock_) {
553 if (Runtime::Current()->IsAotCompiler() && !kUseAOTInlineCaches) {
554 return false;
555 }
556
557 StackHandleScope<InlineCache::kIndividualCacheSize> classes(Thread::Current());
558 // The Zygote JIT compiles based on a profile, so we shouldn't use runtime inline caches
559 // for it.
560 InlineCacheType inline_cache_type =
561 (Runtime::Current()->IsAotCompiler() || Runtime::Current()->IsZygote())
562 ? GetInlineCacheAOT(invoke_instruction, &classes)
563 : GetInlineCacheJIT(invoke_instruction, &classes);
564
565 switch (inline_cache_type) {
566 case kInlineCacheNoData: {
567 LOG_FAIL_NO_STAT()
568 << "No inline cache information for call to "
569 << invoke_instruction->GetMethodReference().PrettyMethod();
570 return false;
571 }
572
573 case kInlineCacheUninitialized: {
574 LOG_FAIL_NO_STAT()
575 << "Interface or virtual call to "
576 << invoke_instruction->GetMethodReference().PrettyMethod()
577 << " is not hit and not inlined";
578 return false;
579 }
580
581 case kInlineCacheMonomorphic: {
582 MaybeRecordStat(stats_, MethodCompilationStat::kMonomorphicCall);
583 if (UseOnlyPolymorphicInliningWithNoDeopt()) {
584 return TryInlinePolymorphicCall(invoke_instruction, classes);
585 } else {
586 return TryInlineMonomorphicCall(invoke_instruction, classes);
587 }
588 }
589
590 case kInlineCachePolymorphic: {
591 MaybeRecordStat(stats_, MethodCompilationStat::kPolymorphicCall);
592 return TryInlinePolymorphicCall(invoke_instruction, classes);
593 }
594
595 case kInlineCacheMegamorphic: {
596 LOG_FAIL_NO_STAT()
597 << "Interface or virtual call to "
598 << invoke_instruction->GetMethodReference().PrettyMethod()
599 << " is megamorphic and not inlined";
600 MaybeRecordStat(stats_, MethodCompilationStat::kMegamorphicCall);
601 return false;
602 }
603
604 case kInlineCacheMissingTypes: {
605 LOG_FAIL_NO_STAT()
606 << "Interface or virtual call to "
607 << invoke_instruction->GetMethodReference().PrettyMethod()
608 << " is missing types and not inlined";
609 return false;
610 }
611 }
612 UNREACHABLE();
613 }
614
GetInlineCacheJIT(HInvoke * invoke_instruction,StackHandleScope<InlineCache::kIndividualCacheSize> * classes)615 HInliner::InlineCacheType HInliner::GetInlineCacheJIT(
616 HInvoke* invoke_instruction,
617 /*out*/StackHandleScope<InlineCache::kIndividualCacheSize>* classes) {
618 DCHECK(codegen_->GetCompilerOptions().IsJitCompiler());
619
620 ArtMethod* caller = graph_->GetArtMethod();
621 // Under JIT, we should always know the caller.
622 DCHECK(caller != nullptr);
623 ScopedProfilingInfoUse spiu(Runtime::Current()->GetJit(), caller, Thread::Current());
624 ProfilingInfo* profiling_info = spiu.GetProfilingInfo();
625
626 if (profiling_info == nullptr) {
627 return kInlineCacheNoData;
628 }
629
630 Runtime::Current()->GetJit()->GetCodeCache()->CopyInlineCacheInto(
631 *profiling_info->GetInlineCache(invoke_instruction->GetDexPc()),
632 classes);
633 return GetInlineCacheType(*classes);
634 }
635
GetInlineCacheAOT(HInvoke * invoke_instruction,StackHandleScope<InlineCache::kIndividualCacheSize> * classes)636 HInliner::InlineCacheType HInliner::GetInlineCacheAOT(
637 HInvoke* invoke_instruction,
638 /*out*/StackHandleScope<InlineCache::kIndividualCacheSize>* classes) {
639 DCHECK_EQ(classes->NumberOfReferences(), InlineCache::kIndividualCacheSize);
640 DCHECK_EQ(classes->RemainingSlots(), InlineCache::kIndividualCacheSize);
641
642 const ProfileCompilationInfo* pci = codegen_->GetCompilerOptions().GetProfileCompilationInfo();
643 if (pci == nullptr) {
644 return kInlineCacheNoData;
645 }
646
647 ProfileCompilationInfo::MethodHotness hotness = pci->GetMethodHotness(MethodReference(
648 caller_compilation_unit_.GetDexFile(), caller_compilation_unit_.GetDexMethodIndex()));
649 if (!hotness.IsHot()) {
650 return kInlineCacheNoData; // no profile information for this invocation.
651 }
652
653 const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap();
654 DCHECK(inline_caches != nullptr);
655 const auto it = inline_caches->find(invoke_instruction->GetDexPc());
656 if (it == inline_caches->end()) {
657 return kInlineCacheUninitialized;
658 }
659
660 const ProfileCompilationInfo::DexPcData& dex_pc_data = it->second;
661 if (dex_pc_data.is_missing_types) {
662 return kInlineCacheMissingTypes;
663 }
664 if (dex_pc_data.is_megamorphic) {
665 return kInlineCacheMegamorphic;
666 }
667 DCHECK_LE(dex_pc_data.classes.size(), InlineCache::kIndividualCacheSize);
668
669 // Walk over the class descriptors and look up the actual classes.
670 // If we cannot find a type we return kInlineCacheMissingTypes.
671 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
672 for (const dex::TypeIndex& type_index : dex_pc_data.classes) {
673 const DexFile* dex_file = caller_compilation_unit_.GetDexFile();
674 const char* descriptor = pci->GetTypeDescriptor(dex_file, type_index);
675 ObjPtr<mirror::ClassLoader> class_loader = caller_compilation_unit_.GetClassLoader().Get();
676 ObjPtr<mirror::Class> clazz = class_linker->LookupResolvedType(descriptor, class_loader);
677 if (clazz == nullptr) {
678 VLOG(compiler) << "Could not find class from inline cache in AOT mode "
679 << invoke_instruction->GetMethodReference().PrettyMethod()
680 << " : "
681 << descriptor;
682 return kInlineCacheMissingTypes;
683 }
684 DCHECK_NE(classes->RemainingSlots(), 0u);
685 classes->NewHandle(clazz);
686 }
687
688 return GetInlineCacheType(*classes);
689 }
690
BuildGetReceiverClass(ClassLinker * class_linker,HInstruction * receiver,uint32_t dex_pc) const691 HInstanceFieldGet* HInliner::BuildGetReceiverClass(ClassLinker* class_linker,
692 HInstruction* receiver,
693 uint32_t dex_pc) const {
694 ArtField* field = GetClassRoot<mirror::Object>(class_linker)->GetInstanceField(0);
695 DCHECK_EQ(std::string(field->GetName()), "shadow$_klass_");
696 HInstanceFieldGet* result = new (graph_->GetAllocator()) HInstanceFieldGet(
697 receiver,
698 field,
699 DataType::Type::kReference,
700 field->GetOffset(),
701 field->IsVolatile(),
702 field->GetDexFieldIndex(),
703 field->GetDeclaringClass()->GetDexClassDefIndex(),
704 *field->GetDexFile(),
705 dex_pc);
706 // The class of a field is effectively final, and does not have any memory dependencies.
707 result->SetSideEffects(SideEffects::None());
708 return result;
709 }
710
ResolveMethodFromInlineCache(Handle<mirror::Class> klass,HInvoke * invoke_instruction,PointerSize pointer_size)711 static ArtMethod* ResolveMethodFromInlineCache(Handle<mirror::Class> klass,
712 HInvoke* invoke_instruction,
713 PointerSize pointer_size)
714 REQUIRES_SHARED(Locks::mutator_lock_) {
715 ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
716 if (Runtime::Current()->IsAotCompiler()) {
717 // We can get unrelated types when working with profiles (corruption,
718 // systme updates, or anyone can write to it). So first check if the class
719 // actually implements the declaring class of the method that is being
720 // called in bytecode.
721 // Note: the lookup methods used below require to have assignable types.
722 if (!resolved_method->GetDeclaringClass()->IsAssignableFrom(klass.Get())) {
723 return nullptr;
724 }
725 }
726
727 if (invoke_instruction->IsInvokeInterface()) {
728 resolved_method = klass->FindVirtualMethodForInterface(resolved_method, pointer_size);
729 } else {
730 DCHECK(invoke_instruction->IsInvokeVirtual());
731 resolved_method = klass->FindVirtualMethodForVirtual(resolved_method, pointer_size);
732 }
733 // Even if the class exists we can still not have the function the
734 // inline-cache targets if the profile is from far enough in the past/future.
735 // We need to allow this since we don't update boot-profiles very often. This
736 // can occur in boot-profiles with inline-caches.
737 DCHECK(Runtime::Current()->IsAotCompiler() || resolved_method != nullptr);
738 return resolved_method;
739 }
740
TryInlineMonomorphicCall(HInvoke * invoke_instruction,const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)741 bool HInliner::TryInlineMonomorphicCall(
742 HInvoke* invoke_instruction,
743 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
744 DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface())
745 << invoke_instruction->DebugName();
746
747 dex::TypeIndex class_index = FindClassIndexIn(
748 GetMonomorphicType(classes), caller_compilation_unit_);
749 if (!class_index.IsValid()) {
750 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedDexCache)
751 << "Call to " << ArtMethod::PrettyMethod(invoke_instruction->GetResolvedMethod())
752 << " from inline cache is not inlined because its class is not"
753 << " accessible to the caller";
754 return false;
755 }
756
757 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
758 PointerSize pointer_size = class_linker->GetImagePointerSize();
759 Handle<mirror::Class> monomorphic_type =
760 graph_->GetHandleCache()->NewHandle(GetMonomorphicType(classes));
761 ArtMethod* resolved_method = ResolveMethodFromInlineCache(
762 monomorphic_type, invoke_instruction, pointer_size);
763 if (resolved_method == nullptr) {
764 // Bogus AOT profile, bail.
765 DCHECK(Runtime::Current()->IsAotCompiler());
766 return false;
767 }
768
769 LOG_NOTE() << "Try inline monomorphic call to " << resolved_method->PrettyMethod();
770 HInstruction* receiver = invoke_instruction->InputAt(0);
771 HInstruction* cursor = invoke_instruction->GetPrevious();
772 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
773 if (!TryInlineAndReplace(invoke_instruction,
774 resolved_method,
775 ReferenceTypeInfo::Create(monomorphic_type, /* is_exact= */ true),
776 /* do_rtp= */ false)) {
777 return false;
778 }
779
780 // We successfully inlined, now add a guard.
781 AddTypeGuard(receiver,
782 cursor,
783 bb_cursor,
784 class_index,
785 monomorphic_type,
786 invoke_instruction,
787 /* with_deoptimization= */ true);
788
789 // Run type propagation to get the guard typed, and eventually propagate the
790 // type of the receiver.
791 ReferenceTypePropagation rtp_fixup(graph_,
792 outer_compilation_unit_.GetClassLoader(),
793 outer_compilation_unit_.GetDexCache(),
794 /* is_first_run= */ false);
795 rtp_fixup.Run();
796
797 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedMonomorphicCall);
798 return true;
799 }
800
AddCHAGuard(HInstruction * invoke_instruction,uint32_t dex_pc,HInstruction * cursor,HBasicBlock * bb_cursor)801 void HInliner::AddCHAGuard(HInstruction* invoke_instruction,
802 uint32_t dex_pc,
803 HInstruction* cursor,
804 HBasicBlock* bb_cursor) {
805 HShouldDeoptimizeFlag* deopt_flag = new (graph_->GetAllocator())
806 HShouldDeoptimizeFlag(graph_->GetAllocator(), dex_pc);
807 HInstruction* compare = new (graph_->GetAllocator()) HNotEqual(
808 deopt_flag, graph_->GetIntConstant(0, dex_pc));
809 HInstruction* deopt = new (graph_->GetAllocator()) HDeoptimize(
810 graph_->GetAllocator(), compare, DeoptimizationKind::kCHA, dex_pc);
811
812 if (cursor != nullptr) {
813 bb_cursor->InsertInstructionAfter(deopt_flag, cursor);
814 } else {
815 bb_cursor->InsertInstructionBefore(deopt_flag, bb_cursor->GetFirstInstruction());
816 }
817 bb_cursor->InsertInstructionAfter(compare, deopt_flag);
818 bb_cursor->InsertInstructionAfter(deopt, compare);
819
820 // Add receiver as input to aid CHA guard optimization later.
821 deopt_flag->AddInput(invoke_instruction->InputAt(0));
822 DCHECK_EQ(deopt_flag->InputCount(), 1u);
823 deopt->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
824 outermost_graph_->IncrementNumberOfCHAGuards();
825 }
826
AddTypeGuard(HInstruction * receiver,HInstruction * cursor,HBasicBlock * bb_cursor,dex::TypeIndex class_index,Handle<mirror::Class> klass,HInstruction * invoke_instruction,bool with_deoptimization)827 HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
828 HInstruction* cursor,
829 HBasicBlock* bb_cursor,
830 dex::TypeIndex class_index,
831 Handle<mirror::Class> klass,
832 HInstruction* invoke_instruction,
833 bool with_deoptimization) {
834 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
835 HInstanceFieldGet* receiver_class = BuildGetReceiverClass(
836 class_linker, receiver, invoke_instruction->GetDexPc());
837 if (cursor != nullptr) {
838 bb_cursor->InsertInstructionAfter(receiver_class, cursor);
839 } else {
840 bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction());
841 }
842
843 const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
844 bool is_referrer;
845 ArtMethod* outermost_art_method = outermost_graph_->GetArtMethod();
846 if (outermost_art_method == nullptr) {
847 DCHECK(Runtime::Current()->IsAotCompiler());
848 // We are in AOT mode and we don't have an ART method to determine
849 // if the inlined method belongs to the referrer. Assume it doesn't.
850 is_referrer = false;
851 } else {
852 is_referrer = klass.Get() == outermost_art_method->GetDeclaringClass();
853 }
854
855 // Note that we will just compare the classes, so we don't need Java semantics access checks.
856 // Note that the type index and the dex file are relative to the method this type guard is
857 // inlined into.
858 HLoadClass* load_class = new (graph_->GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
859 class_index,
860 caller_dex_file,
861 klass,
862 is_referrer,
863 invoke_instruction->GetDexPc(),
864 /* needs_access_check= */ false);
865 HLoadClass::LoadKind kind = HSharpening::ComputeLoadClassKind(
866 load_class, codegen_, caller_compilation_unit_);
867 DCHECK(kind != HLoadClass::LoadKind::kInvalid)
868 << "We should always be able to reference a class for inline caches";
869 // Load kind must be set before inserting the instruction into the graph.
870 load_class->SetLoadKind(kind);
871 bb_cursor->InsertInstructionAfter(load_class, receiver_class);
872 // In AOT mode, we will most likely load the class from BSS, which will involve a call
873 // to the runtime. In this case, the load instruction will need an environment so copy
874 // it from the invoke instruction.
875 if (load_class->NeedsEnvironment()) {
876 DCHECK(Runtime::Current()->IsAotCompiler());
877 load_class->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
878 }
879
880 HNotEqual* compare = new (graph_->GetAllocator()) HNotEqual(load_class, receiver_class);
881 bb_cursor->InsertInstructionAfter(compare, load_class);
882 if (with_deoptimization) {
883 HDeoptimize* deoptimize = new (graph_->GetAllocator()) HDeoptimize(
884 graph_->GetAllocator(),
885 compare,
886 receiver,
887 Runtime::Current()->IsAotCompiler()
888 ? DeoptimizationKind::kAotInlineCache
889 : DeoptimizationKind::kJitInlineCache,
890 invoke_instruction->GetDexPc());
891 bb_cursor->InsertInstructionAfter(deoptimize, compare);
892 deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
893 DCHECK_EQ(invoke_instruction->InputAt(0), receiver);
894 receiver->ReplaceUsesDominatedBy(deoptimize, deoptimize);
895 deoptimize->SetReferenceTypeInfo(receiver->GetReferenceTypeInfo());
896 }
897 return compare;
898 }
899
MaybeReplaceAndRemove(HInstruction * new_instruction,HInstruction * old_instruction)900 static void MaybeReplaceAndRemove(HInstruction* new_instruction, HInstruction* old_instruction) {
901 DCHECK(new_instruction != old_instruction);
902 if (new_instruction != nullptr) {
903 old_instruction->ReplaceWith(new_instruction);
904 }
905 old_instruction->GetBlock()->RemoveInstruction(old_instruction);
906 }
907
TryInlinePolymorphicCall(HInvoke * invoke_instruction,const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)908 bool HInliner::TryInlinePolymorphicCall(
909 HInvoke* invoke_instruction,
910 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
911 DCHECK(invoke_instruction->IsInvokeVirtual() || invoke_instruction->IsInvokeInterface())
912 << invoke_instruction->DebugName();
913
914 if (TryInlinePolymorphicCallToSameTarget(invoke_instruction, classes)) {
915 return true;
916 }
917
918 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
919 PointerSize pointer_size = class_linker->GetImagePointerSize();
920
921 bool all_targets_inlined = true;
922 bool one_target_inlined = false;
923 DCHECK_EQ(classes.NumberOfReferences(), InlineCache::kIndividualCacheSize);
924 uint8_t number_of_types = InlineCache::kIndividualCacheSize - classes.RemainingSlots();
925 for (size_t i = 0; i != number_of_types; ++i) {
926 DCHECK(classes.GetReference(i) != nullptr);
927 Handle<mirror::Class> handle =
928 graph_->GetHandleCache()->NewHandle(classes.GetReference(i)->AsClass());
929 ArtMethod* method = ResolveMethodFromInlineCache(handle, invoke_instruction, pointer_size);
930 if (method == nullptr) {
931 DCHECK(Runtime::Current()->IsAotCompiler());
932 // AOT profile is bogus. This loop expects to iterate over all entries,
933 // so just just continue.
934 all_targets_inlined = false;
935 continue;
936 }
937
938 HInstruction* receiver = invoke_instruction->InputAt(0);
939 HInstruction* cursor = invoke_instruction->GetPrevious();
940 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
941
942 dex::TypeIndex class_index = FindClassIndexIn(handle.Get(), caller_compilation_unit_);
943 HInstruction* return_replacement = nullptr;
944 LOG_NOTE() << "Try inline polymorphic call to " << method->PrettyMethod();
945 if (!class_index.IsValid() ||
946 !TryBuildAndInline(invoke_instruction,
947 method,
948 ReferenceTypeInfo::Create(handle, /* is_exact= */ true),
949 &return_replacement)) {
950 all_targets_inlined = false;
951 } else {
952 one_target_inlined = true;
953
954 LOG_SUCCESS() << "Polymorphic call to "
955 << invoke_instruction->GetMethodReference().PrettyMethod()
956 << " has inlined " << ArtMethod::PrettyMethod(method);
957
958 // If we have inlined all targets before, and this receiver is the last seen,
959 // we deoptimize instead of keeping the original invoke instruction.
960 bool deoptimize = !UseOnlyPolymorphicInliningWithNoDeopt() &&
961 all_targets_inlined &&
962 (i + 1 == number_of_types);
963
964 HInstruction* compare = AddTypeGuard(receiver,
965 cursor,
966 bb_cursor,
967 class_index,
968 handle,
969 invoke_instruction,
970 deoptimize);
971 if (deoptimize) {
972 MaybeReplaceAndRemove(return_replacement, invoke_instruction);
973 } else {
974 CreateDiamondPatternForPolymorphicInline(compare, return_replacement, invoke_instruction);
975 }
976 }
977 }
978
979 if (!one_target_inlined) {
980 LOG_FAIL_NO_STAT()
981 << "Call to " << invoke_instruction->GetMethodReference().PrettyMethod()
982 << " from inline cache is not inlined because none"
983 << " of its targets could be inlined";
984 return false;
985 }
986
987 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedPolymorphicCall);
988
989 // Run type propagation to get the guards typed.
990 ReferenceTypePropagation rtp_fixup(graph_,
991 outer_compilation_unit_.GetClassLoader(),
992 outer_compilation_unit_.GetDexCache(),
993 /* is_first_run= */ false);
994 rtp_fixup.Run();
995 return true;
996 }
997
CreateDiamondPatternForPolymorphicInline(HInstruction * compare,HInstruction * return_replacement,HInstruction * invoke_instruction)998 void HInliner::CreateDiamondPatternForPolymorphicInline(HInstruction* compare,
999 HInstruction* return_replacement,
1000 HInstruction* invoke_instruction) {
1001 uint32_t dex_pc = invoke_instruction->GetDexPc();
1002 HBasicBlock* cursor_block = compare->GetBlock();
1003 HBasicBlock* original_invoke_block = invoke_instruction->GetBlock();
1004 ArenaAllocator* allocator = graph_->GetAllocator();
1005
1006 // Spit the block after the compare: `cursor_block` will now be the start of the diamond,
1007 // and the returned block is the start of the then branch (that could contain multiple blocks).
1008 HBasicBlock* then = cursor_block->SplitAfterForInlining(compare);
1009
1010 // Split the block containing the invoke before and after the invoke. The returned block
1011 // of the split before will contain the invoke and will be the otherwise branch of
1012 // the diamond. The returned block of the split after will be the merge block
1013 // of the diamond.
1014 HBasicBlock* end_then = invoke_instruction->GetBlock();
1015 HBasicBlock* otherwise = end_then->SplitBeforeForInlining(invoke_instruction);
1016 HBasicBlock* merge = otherwise->SplitAfterForInlining(invoke_instruction);
1017
1018 // If the methods we are inlining return a value, we create a phi in the merge block
1019 // that will have the `invoke_instruction and the `return_replacement` as inputs.
1020 if (return_replacement != nullptr) {
1021 HPhi* phi = new (allocator) HPhi(
1022 allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke_instruction->GetType()), dex_pc);
1023 merge->AddPhi(phi);
1024 invoke_instruction->ReplaceWith(phi);
1025 phi->AddInput(return_replacement);
1026 phi->AddInput(invoke_instruction);
1027 }
1028
1029 // Add the control flow instructions.
1030 otherwise->AddInstruction(new (allocator) HGoto(dex_pc));
1031 end_then->AddInstruction(new (allocator) HGoto(dex_pc));
1032 cursor_block->AddInstruction(new (allocator) HIf(compare, dex_pc));
1033
1034 // Add the newly created blocks to the graph.
1035 graph_->AddBlock(then);
1036 graph_->AddBlock(otherwise);
1037 graph_->AddBlock(merge);
1038
1039 // Set up successor (and implictly predecessor) relations.
1040 cursor_block->AddSuccessor(otherwise);
1041 cursor_block->AddSuccessor(then);
1042 end_then->AddSuccessor(merge);
1043 otherwise->AddSuccessor(merge);
1044
1045 // Set up dominance information.
1046 then->SetDominator(cursor_block);
1047 cursor_block->AddDominatedBlock(then);
1048 otherwise->SetDominator(cursor_block);
1049 cursor_block->AddDominatedBlock(otherwise);
1050 merge->SetDominator(cursor_block);
1051 cursor_block->AddDominatedBlock(merge);
1052
1053 // Update the revert post order.
1054 size_t index = IndexOfElement(graph_->reverse_post_order_, cursor_block);
1055 MakeRoomFor(&graph_->reverse_post_order_, 1, index);
1056 graph_->reverse_post_order_[++index] = then;
1057 index = IndexOfElement(graph_->reverse_post_order_, end_then);
1058 MakeRoomFor(&graph_->reverse_post_order_, 2, index);
1059 graph_->reverse_post_order_[++index] = otherwise;
1060 graph_->reverse_post_order_[++index] = merge;
1061
1062
1063 graph_->UpdateLoopAndTryInformationOfNewBlock(
1064 then, original_invoke_block, /* replace_if_back_edge= */ false);
1065 graph_->UpdateLoopAndTryInformationOfNewBlock(
1066 otherwise, original_invoke_block, /* replace_if_back_edge= */ false);
1067
1068 // In case the original invoke location was a back edge, we need to update
1069 // the loop to now have the merge block as a back edge.
1070 graph_->UpdateLoopAndTryInformationOfNewBlock(
1071 merge, original_invoke_block, /* replace_if_back_edge= */ true);
1072 }
1073
TryInlinePolymorphicCallToSameTarget(HInvoke * invoke_instruction,const StackHandleScope<InlineCache::kIndividualCacheSize> & classes)1074 bool HInliner::TryInlinePolymorphicCallToSameTarget(
1075 HInvoke* invoke_instruction,
1076 const StackHandleScope<InlineCache::kIndividualCacheSize>& classes) {
1077 // This optimization only works under JIT for now.
1078 if (!codegen_->GetCompilerOptions().IsJitCompiler()) {
1079 return false;
1080 }
1081
1082 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
1083 PointerSize pointer_size = class_linker->GetImagePointerSize();
1084
1085 ArtMethod* actual_method = nullptr;
1086 size_t method_index = invoke_instruction->IsInvokeVirtual()
1087 ? invoke_instruction->AsInvokeVirtual()->GetVTableIndex()
1088 : invoke_instruction->AsInvokeInterface()->GetImtIndex();
1089
1090 // Check whether we are actually calling the same method among
1091 // the different types seen.
1092 DCHECK_EQ(classes.NumberOfReferences(), InlineCache::kIndividualCacheSize);
1093 uint8_t number_of_types = InlineCache::kIndividualCacheSize - classes.RemainingSlots();
1094 for (size_t i = 0; i != number_of_types; ++i) {
1095 DCHECK(classes.GetReference(i) != nullptr);
1096 ArtMethod* new_method = nullptr;
1097 if (invoke_instruction->IsInvokeInterface()) {
1098 new_method = classes.GetReference(i)->AsClass()->GetImt(pointer_size)->Get(
1099 method_index, pointer_size);
1100 if (new_method->IsRuntimeMethod()) {
1101 // Bail out as soon as we see a conflict trampoline in one of the target's
1102 // interface table.
1103 return false;
1104 }
1105 } else {
1106 DCHECK(invoke_instruction->IsInvokeVirtual());
1107 new_method =
1108 classes.GetReference(i)->AsClass()->GetEmbeddedVTableEntry(method_index, pointer_size);
1109 }
1110 DCHECK(new_method != nullptr);
1111 if (actual_method == nullptr) {
1112 actual_method = new_method;
1113 } else if (actual_method != new_method) {
1114 // Different methods, bailout.
1115 return false;
1116 }
1117 }
1118
1119 HInstruction* receiver = invoke_instruction->InputAt(0);
1120 HInstruction* cursor = invoke_instruction->GetPrevious();
1121 HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
1122
1123 HInstruction* return_replacement = nullptr;
1124 if (!TryBuildAndInline(invoke_instruction,
1125 actual_method,
1126 ReferenceTypeInfo::CreateInvalid(),
1127 &return_replacement)) {
1128 return false;
1129 }
1130
1131 // We successfully inlined, now add a guard.
1132 HInstanceFieldGet* receiver_class = BuildGetReceiverClass(
1133 class_linker, receiver, invoke_instruction->GetDexPc());
1134
1135 DataType::Type type = Is64BitInstructionSet(graph_->GetInstructionSet())
1136 ? DataType::Type::kInt64
1137 : DataType::Type::kInt32;
1138 HClassTableGet* class_table_get = new (graph_->GetAllocator()) HClassTableGet(
1139 receiver_class,
1140 type,
1141 invoke_instruction->IsInvokeVirtual() ? HClassTableGet::TableKind::kVTable
1142 : HClassTableGet::TableKind::kIMTable,
1143 method_index,
1144 invoke_instruction->GetDexPc());
1145
1146 HConstant* constant;
1147 if (type == DataType::Type::kInt64) {
1148 constant = graph_->GetLongConstant(
1149 reinterpret_cast<intptr_t>(actual_method), invoke_instruction->GetDexPc());
1150 } else {
1151 constant = graph_->GetIntConstant(
1152 reinterpret_cast<intptr_t>(actual_method), invoke_instruction->GetDexPc());
1153 }
1154
1155 HNotEqual* compare = new (graph_->GetAllocator()) HNotEqual(class_table_get, constant);
1156 if (cursor != nullptr) {
1157 bb_cursor->InsertInstructionAfter(receiver_class, cursor);
1158 } else {
1159 bb_cursor->InsertInstructionBefore(receiver_class, bb_cursor->GetFirstInstruction());
1160 }
1161 bb_cursor->InsertInstructionAfter(class_table_get, receiver_class);
1162 bb_cursor->InsertInstructionAfter(compare, class_table_get);
1163
1164 if (outermost_graph_->IsCompilingOsr()) {
1165 CreateDiamondPatternForPolymorphicInline(compare, return_replacement, invoke_instruction);
1166 } else {
1167 HDeoptimize* deoptimize = new (graph_->GetAllocator()) HDeoptimize(
1168 graph_->GetAllocator(),
1169 compare,
1170 receiver,
1171 DeoptimizationKind::kJitSameTarget,
1172 invoke_instruction->GetDexPc());
1173 bb_cursor->InsertInstructionAfter(deoptimize, compare);
1174 deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1175 MaybeReplaceAndRemove(return_replacement, invoke_instruction);
1176 receiver->ReplaceUsesDominatedBy(deoptimize, deoptimize);
1177 deoptimize->SetReferenceTypeInfo(receiver->GetReferenceTypeInfo());
1178 }
1179
1180 // Run type propagation to get the guard typed.
1181 ReferenceTypePropagation rtp_fixup(graph_,
1182 outer_compilation_unit_.GetClassLoader(),
1183 outer_compilation_unit_.GetDexCache(),
1184 /* is_first_run= */ false);
1185 rtp_fixup.Run();
1186
1187 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedPolymorphicCall);
1188
1189 LOG_SUCCESS() << "Inlined same polymorphic target " << actual_method->PrettyMethod();
1190 return true;
1191 }
1192
MaybeRunReferenceTypePropagation(HInstruction * replacement,HInvoke * invoke_instruction)1193 void HInliner::MaybeRunReferenceTypePropagation(HInstruction* replacement,
1194 HInvoke* invoke_instruction) {
1195 if (ReturnTypeMoreSpecific(replacement, invoke_instruction)) {
1196 // Actual return value has a more specific type than the method's declared
1197 // return type. Run RTP again on the outer graph to propagate it.
1198 ReferenceTypePropagation(graph_,
1199 outer_compilation_unit_.GetClassLoader(),
1200 outer_compilation_unit_.GetDexCache(),
1201 /* is_first_run= */ false).Run();
1202 }
1203 }
1204
TryDevirtualize(HInvoke * invoke_instruction,ArtMethod * method,HInvoke ** replacement)1205 bool HInliner::TryDevirtualize(HInvoke* invoke_instruction,
1206 ArtMethod* method,
1207 HInvoke** replacement) {
1208 DCHECK(invoke_instruction != *replacement);
1209 if (!invoke_instruction->IsInvokeInterface() && !invoke_instruction->IsInvokeVirtual()) {
1210 return false;
1211 }
1212
1213 // Don't bother trying to call directly a default conflict method. It
1214 // doesn't have a proper MethodReference, but also `GetCanonicalMethod`
1215 // will return an actual default implementation.
1216 if (method->IsDefaultConflicting()) {
1217 return false;
1218 }
1219 DCHECK(!method->IsProxyMethod());
1220 ClassLinker* cl = Runtime::Current()->GetClassLinker();
1221 PointerSize pointer_size = cl->GetImagePointerSize();
1222 // The sharpening logic assumes the caller isn't passing a copied method.
1223 method = method->GetCanonicalMethod(pointer_size);
1224 uint32_t dex_method_index = FindMethodIndexIn(
1225 method,
1226 *invoke_instruction->GetMethodReference().dex_file,
1227 invoke_instruction->GetMethodReference().index);
1228 if (dex_method_index == dex::kDexNoIndex) {
1229 return false;
1230 }
1231 HInvokeStaticOrDirect::DispatchInfo dispatch_info =
1232 HSharpening::SharpenLoadMethod(method,
1233 /* has_method_id= */ true,
1234 /* for_interface_call= */ false,
1235 codegen_);
1236 DCHECK_NE(dispatch_info.code_ptr_location, CodePtrLocation::kCallCriticalNative);
1237 if (dispatch_info.method_load_kind == MethodLoadKind::kRuntimeCall) {
1238 // If sharpening returns that we need to load the method at runtime, keep
1239 // the virtual/interface call which will be faster.
1240 // Also, the entrypoints for runtime calls do not handle devirtualized
1241 // calls.
1242 return false;
1243 }
1244
1245 HInvokeStaticOrDirect* new_invoke = new (graph_->GetAllocator()) HInvokeStaticOrDirect(
1246 graph_->GetAllocator(),
1247 invoke_instruction->GetNumberOfArguments(),
1248 invoke_instruction->GetType(),
1249 invoke_instruction->GetDexPc(),
1250 MethodReference(invoke_instruction->GetMethodReference().dex_file, dex_method_index),
1251 method,
1252 dispatch_info,
1253 kDirect,
1254 MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
1255 HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
1256 HInputsRef inputs = invoke_instruction->GetInputs();
1257 DCHECK_EQ(inputs.size(), invoke_instruction->GetNumberOfArguments());
1258 for (size_t index = 0; index != inputs.size(); ++index) {
1259 new_invoke->SetArgumentAt(index, inputs[index]);
1260 }
1261 if (HInvokeStaticOrDirect::NeedsCurrentMethodInput(dispatch_info)) {
1262 new_invoke->SetRawInputAt(new_invoke->GetCurrentMethodIndexUnchecked(),
1263 graph_->GetCurrentMethod());
1264 }
1265 invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
1266 new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1267 if (invoke_instruction->GetType() == DataType::Type::kReference) {
1268 new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
1269 }
1270 *replacement = new_invoke;
1271
1272 MaybeReplaceAndRemove(*replacement, invoke_instruction);
1273 // No need to call MaybeRunReferenceTypePropagation, as we know the return type
1274 // cannot be more specific.
1275 DCHECK(!ReturnTypeMoreSpecific(*replacement, invoke_instruction));
1276 return true;
1277 }
1278
1279
TryInlineAndReplace(HInvoke * invoke_instruction,ArtMethod * method,ReferenceTypeInfo receiver_type,bool do_rtp)1280 bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction,
1281 ArtMethod* method,
1282 ReferenceTypeInfo receiver_type,
1283 bool do_rtp) {
1284 DCHECK(!invoke_instruction->IsIntrinsic());
1285 HInstruction* return_replacement = nullptr;
1286
1287 if (!TryBuildAndInline(invoke_instruction, method, receiver_type, &return_replacement)) {
1288 return false;
1289 }
1290
1291 MaybeReplaceAndRemove(return_replacement, invoke_instruction);
1292 FixUpReturnReferenceType(method, return_replacement);
1293 if (do_rtp) {
1294 MaybeRunReferenceTypePropagation(return_replacement, invoke_instruction);
1295 }
1296 return true;
1297 }
1298
CountRecursiveCallsOf(ArtMethod * method) const1299 size_t HInliner::CountRecursiveCallsOf(ArtMethod* method) const {
1300 const HInliner* current = this;
1301 size_t count = 0;
1302 do {
1303 if (current->graph_->GetArtMethod() == method) {
1304 ++count;
1305 }
1306 current = current->parent_;
1307 } while (current != nullptr);
1308 return count;
1309 }
1310
MayInline(const CompilerOptions & compiler_options,const DexFile & inlined_from,const DexFile & inlined_into)1311 static inline bool MayInline(const CompilerOptions& compiler_options,
1312 const DexFile& inlined_from,
1313 const DexFile& inlined_into) {
1314 // We're not allowed to inline across dex files if we're the no-inline-from dex file.
1315 if (!IsSameDexFile(inlined_from, inlined_into) &&
1316 ContainsElement(compiler_options.GetNoInlineFromDexFile(), &inlined_from)) {
1317 return false;
1318 }
1319
1320 return true;
1321 }
1322
1323 // Returns whether inlining is allowed based on ART semantics.
IsInliningAllowed(ArtMethod * method,const CodeItemDataAccessor & accessor) const1324 bool HInliner::IsInliningAllowed(ArtMethod* method, const CodeItemDataAccessor& accessor) const {
1325 if (!accessor.HasCodeItem()) {
1326 LOG_FAIL_NO_STAT()
1327 << "Method " << method->PrettyMethod() << " is not inlined because it is native";
1328 return false;
1329 }
1330
1331 if (!method->IsCompilable()) {
1332 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified)
1333 << "Method " << method->PrettyMethod()
1334 << " has soft failures un-handled by the compiler, so it cannot be inlined";
1335 return false;
1336 }
1337
1338 if (IsMethodUnverified(codegen_->GetCompilerOptions(), method)) {
1339 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedNotVerified)
1340 << "Method " << method->PrettyMethod()
1341 << " couldn't be verified, so it cannot be inlined";
1342 return false;
1343 }
1344
1345 return true;
1346 }
1347
1348 // Returns whether ART supports inlining this method.
1349 //
1350 // Some methods are not supported because they have features for which inlining
1351 // is not implemented. For example, we do not currently support inlining throw
1352 // instructions into a try block.
IsInliningSupported(const HInvoke * invoke_instruction,ArtMethod * method,const CodeItemDataAccessor & accessor) const1353 bool HInliner::IsInliningSupported(const HInvoke* invoke_instruction,
1354 ArtMethod* method,
1355 const CodeItemDataAccessor& accessor) const {
1356 if (method->IsProxyMethod()) {
1357 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedProxy)
1358 << "Method " << method->PrettyMethod()
1359 << " is not inlined because of unimplemented inline support for proxy methods.";
1360 return false;
1361 }
1362
1363 if (accessor.TriesSize() != 0) {
1364 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatch)
1365 << "Method " << method->PrettyMethod() << " is not inlined because of try block";
1366 return false;
1367 }
1368
1369 if (invoke_instruction->IsInvokeStaticOrDirect() &&
1370 invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) {
1371 // Case of a static method that cannot be inlined because it implicitly
1372 // requires an initialization check of its declaring class.
1373 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedDexCache)
1374 << "Method " << method->PrettyMethod()
1375 << " is not inlined because it is static and requires a clinit"
1376 << " check that cannot be emitted due to Dex cache limitations";
1377 return false;
1378 }
1379
1380 return true;
1381 }
1382
1383 // Returns whether our resource limits allow inlining this method.
IsInliningBudgetAvailable(ArtMethod * method,const CodeItemDataAccessor & accessor) const1384 bool HInliner::IsInliningBudgetAvailable(ArtMethod* method,
1385 const CodeItemDataAccessor& accessor) const {
1386 if (CountRecursiveCallsOf(method) > kMaximumNumberOfRecursiveCalls) {
1387 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedRecursiveBudget)
1388 << "Method "
1389 << method->PrettyMethod()
1390 << " is not inlined because it has reached its recursive call budget.";
1391 return false;
1392 }
1393
1394 size_t inline_max_code_units = codegen_->GetCompilerOptions().GetInlineMaxCodeUnits();
1395 if (accessor.InsnsSizeInCodeUnits() > inline_max_code_units) {
1396 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem)
1397 << "Method " << method->PrettyMethod()
1398 << " is not inlined because its code item is too big: "
1399 << accessor.InsnsSizeInCodeUnits()
1400 << " > "
1401 << inline_max_code_units;
1402 return false;
1403 }
1404
1405 return true;
1406 }
1407
TryBuildAndInline(HInvoke * invoke_instruction,ArtMethod * method,ReferenceTypeInfo receiver_type,HInstruction ** return_replacement)1408 bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
1409 ArtMethod* method,
1410 ReferenceTypeInfo receiver_type,
1411 HInstruction** return_replacement) {
1412 // If invoke_instruction is devirtualized to a different method, give intrinsics
1413 // another chance before we try to inline it.
1414 if (invoke_instruction->GetResolvedMethod() != method && method->IsIntrinsic()) {
1415 MaybeRecordStat(stats_, MethodCompilationStat::kIntrinsicRecognized);
1416 // For simplicity, always create a new instruction to replace the existing
1417 // invoke.
1418 HInvokeVirtual* new_invoke = new (graph_->GetAllocator()) HInvokeVirtual(
1419 graph_->GetAllocator(),
1420 invoke_instruction->GetNumberOfArguments(),
1421 invoke_instruction->GetType(),
1422 invoke_instruction->GetDexPc(),
1423 invoke_instruction->GetMethodReference(), // Use existing invoke's method's reference.
1424 method,
1425 MethodReference(method->GetDexFile(), method->GetDexMethodIndex()),
1426 method->GetMethodIndex());
1427 DCHECK_NE(new_invoke->GetIntrinsic(), Intrinsics::kNone);
1428 HInputsRef inputs = invoke_instruction->GetInputs();
1429 for (size_t index = 0; index != inputs.size(); ++index) {
1430 new_invoke->SetArgumentAt(index, inputs[index]);
1431 }
1432 invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
1433 new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
1434 if (invoke_instruction->GetType() == DataType::Type::kReference) {
1435 new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
1436 }
1437 *return_replacement = new_invoke;
1438 return true;
1439 }
1440
1441 // Check whether we're allowed to inline. The outermost compilation unit is the relevant
1442 // dex file here (though the transitivity of an inline chain would allow checking the caller).
1443 if (!MayInline(codegen_->GetCompilerOptions(),
1444 *method->GetDexFile(),
1445 *outer_compilation_unit_.GetDexFile())) {
1446 if (TryPatternSubstitution(invoke_instruction, method, return_replacement)) {
1447 LOG_SUCCESS() << "Successfully replaced pattern of invoke "
1448 << method->PrettyMethod();
1449 MaybeRecordStat(stats_, MethodCompilationStat::kReplacedInvokeWithSimplePattern);
1450 return true;
1451 }
1452 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedWont)
1453 << "Won't inline " << method->PrettyMethod() << " in "
1454 << outer_compilation_unit_.GetDexFile()->GetLocation() << " ("
1455 << caller_compilation_unit_.GetDexFile()->GetLocation() << ") from "
1456 << method->GetDexFile()->GetLocation();
1457 return false;
1458 }
1459
1460 CodeItemDataAccessor accessor(method->DexInstructionData());
1461
1462 if (!IsInliningAllowed(method, accessor)) {
1463 return false;
1464 }
1465
1466 if (!IsInliningSupported(invoke_instruction, method, accessor)) {
1467 return false;
1468 }
1469
1470 if (!IsInliningBudgetAvailable(method, accessor)) {
1471 return false;
1472 }
1473
1474 if (!TryBuildAndInlineHelper(
1475 invoke_instruction, method, receiver_type, return_replacement)) {
1476 return false;
1477 }
1478
1479 LOG_SUCCESS() << method->PrettyMethod();
1480 MaybeRecordStat(stats_, MethodCompilationStat::kInlinedInvoke);
1481 return true;
1482 }
1483
GetInvokeInputForArgVRegIndex(HInvoke * invoke_instruction,size_t arg_vreg_index)1484 static HInstruction* GetInvokeInputForArgVRegIndex(HInvoke* invoke_instruction,
1485 size_t arg_vreg_index)
1486 REQUIRES_SHARED(Locks::mutator_lock_) {
1487 size_t input_index = 0;
1488 for (size_t i = 0; i < arg_vreg_index; ++i, ++input_index) {
1489 DCHECK_LT(input_index, invoke_instruction->GetNumberOfArguments());
1490 if (DataType::Is64BitType(invoke_instruction->InputAt(input_index)->GetType())) {
1491 ++i;
1492 DCHECK_NE(i, arg_vreg_index);
1493 }
1494 }
1495 DCHECK_LT(input_index, invoke_instruction->GetNumberOfArguments());
1496 return invoke_instruction->InputAt(input_index);
1497 }
1498
1499 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
TryPatternSubstitution(HInvoke * invoke_instruction,ArtMethod * method,HInstruction ** return_replacement)1500 bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
1501 ArtMethod* method,
1502 HInstruction** return_replacement) {
1503 InlineMethod inline_method;
1504 if (!InlineMethodAnalyser::AnalyseMethodCode(method, &inline_method)) {
1505 return false;
1506 }
1507
1508 switch (inline_method.opcode) {
1509 case kInlineOpNop:
1510 DCHECK_EQ(invoke_instruction->GetType(), DataType::Type::kVoid);
1511 *return_replacement = nullptr;
1512 break;
1513 case kInlineOpReturnArg:
1514 *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction,
1515 inline_method.d.return_data.arg);
1516 break;
1517 case kInlineOpNonWideConst:
1518 if (method->GetShorty()[0] == 'L') {
1519 DCHECK_EQ(inline_method.d.data, 0u);
1520 *return_replacement = graph_->GetNullConstant();
1521 } else {
1522 *return_replacement = graph_->GetIntConstant(static_cast<int32_t>(inline_method.d.data));
1523 }
1524 break;
1525 case kInlineOpIGet: {
1526 const InlineIGetIPutData& data = inline_method.d.ifield_data;
1527 if (data.method_is_static || data.object_arg != 0u) {
1528 // TODO: Needs null check.
1529 return false;
1530 }
1531 HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
1532 HInstanceFieldGet* iget = CreateInstanceFieldGet(data.field_idx, method, obj);
1533 DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset);
1534 DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile);
1535 invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction);
1536 *return_replacement = iget;
1537 break;
1538 }
1539 case kInlineOpIPut: {
1540 const InlineIGetIPutData& data = inline_method.d.ifield_data;
1541 if (data.method_is_static || data.object_arg != 0u) {
1542 // TODO: Needs null check.
1543 return false;
1544 }
1545 HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
1546 HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, data.src_arg);
1547 HInstanceFieldSet* iput = CreateInstanceFieldSet(data.field_idx, method, obj, value);
1548 DCHECK_EQ(iput->GetFieldOffset().Uint32Value(), data.field_offset);
1549 DCHECK_EQ(iput->IsVolatile() ? 1u : 0u, data.is_volatile);
1550 invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
1551 if (data.return_arg_plus1 != 0u) {
1552 size_t return_arg = data.return_arg_plus1 - 1u;
1553 *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction, return_arg);
1554 }
1555 break;
1556 }
1557 case kInlineOpConstructor: {
1558 const InlineConstructorData& data = inline_method.d.constructor_data;
1559 // Get the indexes to arrays for easier processing.
1560 uint16_t iput_field_indexes[] = {
1561 data.iput0_field_index, data.iput1_field_index, data.iput2_field_index
1562 };
1563 uint16_t iput_args[] = { data.iput0_arg, data.iput1_arg, data.iput2_arg };
1564 static_assert(arraysize(iput_args) == arraysize(iput_field_indexes), "Size mismatch");
1565 // Count valid field indexes.
1566 size_t number_of_iputs = 0u;
1567 while (number_of_iputs != arraysize(iput_field_indexes) &&
1568 iput_field_indexes[number_of_iputs] != DexFile::kDexNoIndex16) {
1569 // Check that there are no duplicate valid field indexes.
1570 DCHECK_EQ(0, std::count(iput_field_indexes + number_of_iputs + 1,
1571 iput_field_indexes + arraysize(iput_field_indexes),
1572 iput_field_indexes[number_of_iputs]));
1573 ++number_of_iputs;
1574 }
1575 // Check that there are no valid field indexes in the rest of the array.
1576 DCHECK_EQ(0, std::count_if(iput_field_indexes + number_of_iputs,
1577 iput_field_indexes + arraysize(iput_field_indexes),
1578 [](uint16_t index) { return index != DexFile::kDexNoIndex16; }));
1579
1580 // Create HInstanceFieldSet for each IPUT that stores non-zero data.
1581 HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction,
1582 /* arg_vreg_index= */ 0u);
1583 bool needs_constructor_barrier = false;
1584 for (size_t i = 0; i != number_of_iputs; ++i) {
1585 HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, iput_args[i]);
1586 if (!value->IsConstant() || !value->AsConstant()->IsZeroBitPattern()) {
1587 uint16_t field_index = iput_field_indexes[i];
1588 bool is_final;
1589 HInstanceFieldSet* iput =
1590 CreateInstanceFieldSet(field_index, method, obj, value, &is_final);
1591 invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
1592
1593 // Check whether the field is final. If it is, we need to add a barrier.
1594 if (is_final) {
1595 needs_constructor_barrier = true;
1596 }
1597 }
1598 }
1599 if (needs_constructor_barrier) {
1600 // See DexCompilationUnit::RequiresConstructorBarrier for more details.
1601 DCHECK(obj != nullptr) << "only non-static methods can have a constructor fence";
1602
1603 HConstructorFence* constructor_fence =
1604 new (graph_->GetAllocator()) HConstructorFence(obj, kNoDexPc, graph_->GetAllocator());
1605 invoke_instruction->GetBlock()->InsertInstructionBefore(constructor_fence,
1606 invoke_instruction);
1607 }
1608 *return_replacement = nullptr;
1609 break;
1610 }
1611 default:
1612 LOG(FATAL) << "UNREACHABLE";
1613 UNREACHABLE();
1614 }
1615 return true;
1616 }
1617
CreateInstanceFieldGet(uint32_t field_index,ArtMethod * referrer,HInstruction * obj)1618 HInstanceFieldGet* HInliner::CreateInstanceFieldGet(uint32_t field_index,
1619 ArtMethod* referrer,
1620 HInstruction* obj)
1621 REQUIRES_SHARED(Locks::mutator_lock_) {
1622 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
1623 ArtField* resolved_field =
1624 class_linker->LookupResolvedField(field_index, referrer, /* is_static= */ false);
1625 DCHECK(resolved_field != nullptr);
1626 HInstanceFieldGet* iget = new (graph_->GetAllocator()) HInstanceFieldGet(
1627 obj,
1628 resolved_field,
1629 DataType::FromShorty(resolved_field->GetTypeDescriptor()[0]),
1630 resolved_field->GetOffset(),
1631 resolved_field->IsVolatile(),
1632 field_index,
1633 resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
1634 *referrer->GetDexFile(),
1635 // Read barrier generates a runtime call in slow path and we need a valid
1636 // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
1637 /* dex_pc= */ 0);
1638 if (iget->GetType() == DataType::Type::kReference) {
1639 // Use the same dex_cache that we used for field lookup as the hint_dex_cache.
1640 Handle<mirror::DexCache> dex_cache =
1641 graph_->GetHandleCache()->NewHandle(referrer->GetDexCache());
1642 ReferenceTypePropagation rtp(graph_,
1643 outer_compilation_unit_.GetClassLoader(),
1644 dex_cache,
1645 /* is_first_run= */ false);
1646 rtp.Visit(iget);
1647 }
1648 return iget;
1649 }
1650
CreateInstanceFieldSet(uint32_t field_index,ArtMethod * referrer,HInstruction * obj,HInstruction * value,bool * is_final)1651 HInstanceFieldSet* HInliner::CreateInstanceFieldSet(uint32_t field_index,
1652 ArtMethod* referrer,
1653 HInstruction* obj,
1654 HInstruction* value,
1655 bool* is_final)
1656 REQUIRES_SHARED(Locks::mutator_lock_) {
1657 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
1658 ArtField* resolved_field =
1659 class_linker->LookupResolvedField(field_index, referrer, /* is_static= */ false);
1660 DCHECK(resolved_field != nullptr);
1661 if (is_final != nullptr) {
1662 // This information is needed only for constructors.
1663 DCHECK(referrer->IsConstructor());
1664 *is_final = resolved_field->IsFinal();
1665 }
1666 HInstanceFieldSet* iput = new (graph_->GetAllocator()) HInstanceFieldSet(
1667 obj,
1668 value,
1669 resolved_field,
1670 DataType::FromShorty(resolved_field->GetTypeDescriptor()[0]),
1671 resolved_field->GetOffset(),
1672 resolved_field->IsVolatile(),
1673 field_index,
1674 resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
1675 *referrer->GetDexFile(),
1676 // Read barrier generates a runtime call in slow path and we need a valid
1677 // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
1678 /* dex_pc= */ 0);
1679 return iput;
1680 }
1681
1682 template <typename T>
NewHandleIfDifferent(ObjPtr<T> object,Handle<T> hint,HGraph * graph)1683 static inline Handle<T> NewHandleIfDifferent(ObjPtr<T> object, Handle<T> hint, HGraph* graph)
1684 REQUIRES_SHARED(Locks::mutator_lock_) {
1685 return (object != hint.Get()) ? graph->GetHandleCache()->NewHandle(object) : hint;
1686 }
1687
CanEncodeInlinedMethodInStackMap(const DexFile & caller_dex_file,ArtMethod * callee)1688 static bool CanEncodeInlinedMethodInStackMap(const DexFile& caller_dex_file, ArtMethod* callee)
1689 REQUIRES_SHARED(Locks::mutator_lock_) {
1690 if (!Runtime::Current()->IsAotCompiler()) {
1691 // JIT can always encode methods in stack maps.
1692 return true;
1693 }
1694 if (IsSameDexFile(caller_dex_file, *callee->GetDexFile())) {
1695 return true;
1696 }
1697 // TODO(ngeoffray): Support more AOT cases for inlining:
1698 // - methods in multidex
1699 // - methods in boot image for on-device non-PIC compilation.
1700 return false;
1701 }
1702
1703 // Substitutes parameters in the callee graph with their values from the caller.
SubstituteArguments(HGraph * callee_graph,HInvoke * invoke_instruction,ReferenceTypeInfo receiver_type,const DexCompilationUnit & dex_compilation_unit)1704 void HInliner::SubstituteArguments(HGraph* callee_graph,
1705 HInvoke* invoke_instruction,
1706 ReferenceTypeInfo receiver_type,
1707 const DexCompilationUnit& dex_compilation_unit) {
1708 ArtMethod* const resolved_method = callee_graph->GetArtMethod();
1709 size_t parameter_index = 0;
1710 bool run_rtp = false;
1711 for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions());
1712 !instructions.Done();
1713 instructions.Advance()) {
1714 HInstruction* current = instructions.Current();
1715 if (current->IsParameterValue()) {
1716 HInstruction* argument = invoke_instruction->InputAt(parameter_index);
1717 if (argument->IsNullConstant()) {
1718 current->ReplaceWith(callee_graph->GetNullConstant());
1719 } else if (argument->IsIntConstant()) {
1720 current->ReplaceWith(callee_graph->GetIntConstant(argument->AsIntConstant()->GetValue()));
1721 } else if (argument->IsLongConstant()) {
1722 current->ReplaceWith(callee_graph->GetLongConstant(argument->AsLongConstant()->GetValue()));
1723 } else if (argument->IsFloatConstant()) {
1724 current->ReplaceWith(
1725 callee_graph->GetFloatConstant(argument->AsFloatConstant()->GetValue()));
1726 } else if (argument->IsDoubleConstant()) {
1727 current->ReplaceWith(
1728 callee_graph->GetDoubleConstant(argument->AsDoubleConstant()->GetValue()));
1729 } else if (argument->GetType() == DataType::Type::kReference) {
1730 if (!resolved_method->IsStatic() && parameter_index == 0 && receiver_type.IsValid()) {
1731 run_rtp = true;
1732 current->SetReferenceTypeInfo(receiver_type);
1733 } else {
1734 current->SetReferenceTypeInfo(argument->GetReferenceTypeInfo());
1735 }
1736 current->AsParameterValue()->SetCanBeNull(argument->CanBeNull());
1737 }
1738 ++parameter_index;
1739 }
1740 }
1741
1742 // We have replaced formal arguments with actual arguments. If actual types
1743 // are more specific than the declared ones, run RTP again on the inner graph.
1744 if (run_rtp || ArgumentTypesMoreSpecific(invoke_instruction, resolved_method)) {
1745 ReferenceTypePropagation(callee_graph,
1746 outer_compilation_unit_.GetClassLoader(),
1747 dex_compilation_unit.GetDexCache(),
1748 /* is_first_run= */ false).Run();
1749 }
1750 }
1751
1752 // Returns whether we can inline the callee_graph into the target_block.
1753 //
1754 // This performs a combination of semantics checks, compiler support checks, and
1755 // resource limit checks.
1756 //
1757 // If this function returns true, it will also set out_number_of_instructions to
1758 // the number of instructions in the inlined body.
CanInlineBody(const HGraph * callee_graph,const HBasicBlock * target_block,size_t * out_number_of_instructions) const1759 bool HInliner::CanInlineBody(const HGraph* callee_graph,
1760 const HBasicBlock* target_block,
1761 size_t* out_number_of_instructions) const {
1762 ArtMethod* const resolved_method = callee_graph->GetArtMethod();
1763
1764 HBasicBlock* exit_block = callee_graph->GetExitBlock();
1765 if (exit_block == nullptr) {
1766 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
1767 << "Method " << resolved_method->PrettyMethod()
1768 << " could not be inlined because it has an infinite loop";
1769 return false;
1770 }
1771
1772 bool has_one_return = false;
1773 for (HBasicBlock* predecessor : exit_block->GetPredecessors()) {
1774 if (predecessor->GetLastInstruction()->IsThrow()) {
1775 if (target_block->IsTryBlock()) {
1776 // TODO(ngeoffray): Support adding HTryBoundary in Hgraph::InlineInto.
1777 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatch)
1778 << "Method " << resolved_method->PrettyMethod()
1779 << " could not be inlined because one branch always throws and"
1780 << " caller is in a try/catch block";
1781 return false;
1782 } else if (graph_->GetExitBlock() == nullptr) {
1783 // TODO(ngeoffray): Support adding HExit in the caller graph.
1784 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
1785 << "Method " << resolved_method->PrettyMethod()
1786 << " could not be inlined because one branch always throws and"
1787 << " caller does not have an exit block";
1788 return false;
1789 } else if (graph_->HasIrreducibleLoops()) {
1790 // TODO(ngeoffray): Support re-computing loop information to graphs with
1791 // irreducible loops?
1792 VLOG(compiler) << "Method " << resolved_method->PrettyMethod()
1793 << " could not be inlined because one branch always throws and"
1794 << " caller has irreducible loops";
1795 return false;
1796 }
1797 } else {
1798 has_one_return = true;
1799 }
1800 }
1801
1802 if (!has_one_return) {
1803 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedAlwaysThrows)
1804 << "Method " << resolved_method->PrettyMethod()
1805 << " could not be inlined because it always throws";
1806 return false;
1807 }
1808
1809 size_t number_of_instructions = 0;
1810 // Skip the entry block, it does not contain instructions that prevent inlining.
1811 for (HBasicBlock* block : callee_graph->GetReversePostOrderSkipEntryBlock()) {
1812 if (block->IsLoopHeader()) {
1813 if (block->GetLoopInformation()->IsIrreducible()) {
1814 // Don't inline methods with irreducible loops, they could prevent some
1815 // optimizations to run.
1816 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedIrreducibleLoop)
1817 << "Method " << resolved_method->PrettyMethod()
1818 << " could not be inlined because it contains an irreducible loop";
1819 return false;
1820 }
1821 if (!block->GetLoopInformation()->HasExitEdge()) {
1822 // Don't inline methods with loops without exit, since they cause the
1823 // loop information to be computed incorrectly when updating after
1824 // inlining.
1825 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedLoopWithoutExit)
1826 << "Method " << resolved_method->PrettyMethod()
1827 << " could not be inlined because it contains a loop with no exit";
1828 return false;
1829 }
1830 }
1831
1832 for (HInstructionIterator instr_it(block->GetInstructions());
1833 !instr_it.Done();
1834 instr_it.Advance()) {
1835 if (++number_of_instructions > inlining_budget_) {
1836 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInstructionBudget)
1837 << "Method " << resolved_method->PrettyMethod()
1838 << " is not inlined because the outer method has reached"
1839 << " its instruction budget limit.";
1840 return false;
1841 }
1842 HInstruction* current = instr_it.Current();
1843 if (current->NeedsEnvironment() &&
1844 (total_number_of_dex_registers_ > kMaximumNumberOfCumulatedDexRegisters)) {
1845 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedEnvironmentBudget)
1846 << "Method " << resolved_method->PrettyMethod()
1847 << " is not inlined because its caller has reached"
1848 << " its environment budget limit.";
1849 return false;
1850 }
1851
1852 if (current->NeedsEnvironment() &&
1853 !CanEncodeInlinedMethodInStackMap(*caller_compilation_unit_.GetDexFile(),
1854 resolved_method)) {
1855 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedStackMaps)
1856 << "Method " << resolved_method->PrettyMethod()
1857 << " could not be inlined because " << current->DebugName()
1858 << " needs an environment, is in a different dex file"
1859 << ", and cannot be encoded in the stack maps.";
1860 return false;
1861 }
1862
1863 if (current->IsUnresolvedStaticFieldGet() ||
1864 current->IsUnresolvedInstanceFieldGet() ||
1865 current->IsUnresolvedStaticFieldSet() ||
1866 current->IsUnresolvedInstanceFieldSet()) {
1867 // Entrypoint for unresolved fields does not handle inlined frames.
1868 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedUnresolvedEntrypoint)
1869 << "Method " << resolved_method->PrettyMethod()
1870 << " could not be inlined because it is using an unresolved"
1871 << " entrypoint";
1872 return false;
1873 }
1874 }
1875 }
1876
1877 *out_number_of_instructions = number_of_instructions;
1878 return true;
1879 }
1880
TryBuildAndInlineHelper(HInvoke * invoke_instruction,ArtMethod * resolved_method,ReferenceTypeInfo receiver_type,HInstruction ** return_replacement)1881 bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
1882 ArtMethod* resolved_method,
1883 ReferenceTypeInfo receiver_type,
1884 HInstruction** return_replacement) {
1885 DCHECK(!(resolved_method->IsStatic() && receiver_type.IsValid()));
1886 const dex::CodeItem* code_item = resolved_method->GetCodeItem();
1887 const DexFile& callee_dex_file = *resolved_method->GetDexFile();
1888 uint32_t method_index = resolved_method->GetDexMethodIndex();
1889 CodeItemDebugInfoAccessor code_item_accessor(resolved_method->DexInstructionDebugInfo());
1890 ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
1891 Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(),
1892 caller_compilation_unit_.GetDexCache(),
1893 graph_);
1894 Handle<mirror::ClassLoader> class_loader =
1895 NewHandleIfDifferent(resolved_method->GetDeclaringClass()->GetClassLoader(),
1896 caller_compilation_unit_.GetClassLoader(),
1897 graph_);
1898
1899 Handle<mirror::Class> compiling_class =
1900 graph_->GetHandleCache()->NewHandle(resolved_method->GetDeclaringClass());
1901 DexCompilationUnit dex_compilation_unit(
1902 class_loader,
1903 class_linker,
1904 callee_dex_file,
1905 code_item,
1906 resolved_method->GetDeclaringClass()->GetDexClassDefIndex(),
1907 method_index,
1908 resolved_method->GetAccessFlags(),
1909 /* verified_method= */ nullptr,
1910 dex_cache,
1911 compiling_class);
1912
1913 InvokeType invoke_type = invoke_instruction->GetInvokeType();
1914 if (invoke_type == kInterface) {
1915 // We have statically resolved the dispatch. To please the class linker
1916 // at runtime, we change this call as if it was a virtual call.
1917 invoke_type = kVirtual;
1918 }
1919
1920 bool caller_dead_reference_safe = graph_->IsDeadReferenceSafe();
1921 const dex::ClassDef& callee_class = resolved_method->GetClassDef();
1922 // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
1923 // is currently rarely true.
1924 bool callee_dead_reference_safe =
1925 annotations::HasDeadReferenceSafeAnnotation(callee_dex_file, callee_class)
1926 && !annotations::MethodContainsRSensitiveAccess(callee_dex_file, callee_class, method_index);
1927
1928 const int32_t caller_instruction_counter = graph_->GetCurrentInstructionId();
1929 HGraph* callee_graph = new (graph_->GetAllocator()) HGraph(
1930 graph_->GetAllocator(),
1931 graph_->GetArenaStack(),
1932 graph_->GetHandleCache()->GetHandles(),
1933 callee_dex_file,
1934 method_index,
1935 codegen_->GetCompilerOptions().GetInstructionSet(),
1936 invoke_type,
1937 callee_dead_reference_safe,
1938 graph_->IsDebuggable(),
1939 graph_->GetCompilationKind(),
1940 /* start_instruction_id= */ caller_instruction_counter);
1941 callee_graph->SetArtMethod(resolved_method);
1942
1943 // When they are needed, allocate `inline_stats_` on the Arena instead
1944 // of on the stack, as Clang might produce a stack frame too large
1945 // for this function, that would not fit the requirements of the
1946 // `-Wframe-larger-than` option.
1947 if (stats_ != nullptr) {
1948 // Reuse one object for all inline attempts from this caller to keep Arena memory usage low.
1949 if (inline_stats_ == nullptr) {
1950 void* storage = graph_->GetAllocator()->Alloc<OptimizingCompilerStats>(kArenaAllocMisc);
1951 inline_stats_ = new (storage) OptimizingCompilerStats;
1952 } else {
1953 inline_stats_->Reset();
1954 }
1955 }
1956 HGraphBuilder builder(callee_graph,
1957 code_item_accessor,
1958 &dex_compilation_unit,
1959 &outer_compilation_unit_,
1960 codegen_,
1961 inline_stats_);
1962
1963 if (builder.BuildGraph() != kAnalysisSuccess) {
1964 LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCannotBuild)
1965 << "Method " << callee_dex_file.PrettyMethod(method_index)
1966 << " could not be built, so cannot be inlined";
1967 return false;
1968 }
1969
1970 SubstituteArguments(callee_graph, invoke_instruction, receiver_type, dex_compilation_unit);
1971
1972 RunOptimizations(callee_graph, code_item, dex_compilation_unit);
1973
1974 size_t number_of_instructions = 0;
1975 if (!CanInlineBody(callee_graph, invoke_instruction->GetBlock(), &number_of_instructions)) {
1976 return false;
1977 }
1978
1979 DCHECK_EQ(caller_instruction_counter, graph_->GetCurrentInstructionId())
1980 << "No instructions can be added to the outer graph while inner graph is being built";
1981
1982 // Inline the callee graph inside the caller graph.
1983 const int32_t callee_instruction_counter = callee_graph->GetCurrentInstructionId();
1984 graph_->SetCurrentInstructionId(callee_instruction_counter);
1985 *return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
1986 // Update our budget for other inlining attempts in `caller_graph`.
1987 total_number_of_instructions_ += number_of_instructions;
1988 UpdateInliningBudget();
1989
1990 DCHECK_EQ(callee_instruction_counter, callee_graph->GetCurrentInstructionId())
1991 << "No instructions can be added to the inner graph during inlining into the outer graph";
1992
1993 if (stats_ != nullptr) {
1994 DCHECK(inline_stats_ != nullptr);
1995 inline_stats_->AddTo(stats_);
1996 }
1997
1998 if (caller_dead_reference_safe && !callee_dead_reference_safe) {
1999 // Caller was dead reference safe, but is not anymore, since we inlined dead
2000 // reference unsafe code. Prior transformations remain valid, since they did not
2001 // affect the inlined code.
2002 graph_->MarkDeadReferenceUnsafe();
2003 }
2004
2005 return true;
2006 }
2007
RunOptimizations(HGraph * callee_graph,const dex::CodeItem * code_item,const DexCompilationUnit & dex_compilation_unit)2008 void HInliner::RunOptimizations(HGraph* callee_graph,
2009 const dex::CodeItem* code_item,
2010 const DexCompilationUnit& dex_compilation_unit) {
2011 // Note: if the outermost_graph_ is being compiled OSR, we should not run any
2012 // optimization that could lead to a HDeoptimize. The following optimizations do not.
2013 HDeadCodeElimination dce(callee_graph, inline_stats_, "dead_code_elimination$inliner");
2014 HConstantFolding fold(callee_graph, "constant_folding$inliner");
2015 InstructionSimplifier simplify(callee_graph, codegen_, inline_stats_);
2016
2017 HOptimization* optimizations[] = {
2018 &simplify,
2019 &fold,
2020 &dce,
2021 };
2022
2023 for (size_t i = 0; i < arraysize(optimizations); ++i) {
2024 HOptimization* optimization = optimizations[i];
2025 optimization->Run();
2026 }
2027
2028 // Bail early for pathological cases on the environment (for example recursive calls,
2029 // or too large environment).
2030 if (total_number_of_dex_registers_ > kMaximumNumberOfCumulatedDexRegisters) {
2031 LOG_NOTE() << "Calls in " << callee_graph->GetArtMethod()->PrettyMethod()
2032 << " will not be inlined because the outer method has reached"
2033 << " its environment budget limit.";
2034 return;
2035 }
2036
2037 // Bail early if we know we already are over the limit.
2038 size_t number_of_instructions = CountNumberOfInstructions(callee_graph);
2039 if (number_of_instructions > inlining_budget_) {
2040 LOG_NOTE() << "Calls in " << callee_graph->GetArtMethod()->PrettyMethod()
2041 << " will not be inlined because the outer method has reached"
2042 << " its instruction budget limit. " << number_of_instructions;
2043 return;
2044 }
2045
2046 CodeItemDataAccessor accessor(callee_graph->GetDexFile(), code_item);
2047 HInliner inliner(callee_graph,
2048 outermost_graph_,
2049 codegen_,
2050 outer_compilation_unit_,
2051 dex_compilation_unit,
2052 inline_stats_,
2053 total_number_of_dex_registers_ + accessor.RegistersSize(),
2054 total_number_of_instructions_ + number_of_instructions,
2055 this,
2056 depth_ + 1);
2057 inliner.Run();
2058 }
2059
IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,bool declared_is_exact,bool declared_can_be_null,HInstruction * actual_obj)2060 static bool IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,
2061 bool declared_is_exact,
2062 bool declared_can_be_null,
2063 HInstruction* actual_obj)
2064 REQUIRES_SHARED(Locks::mutator_lock_) {
2065 if (declared_can_be_null && !actual_obj->CanBeNull()) {
2066 return true;
2067 }
2068
2069 ReferenceTypeInfo actual_rti = actual_obj->GetReferenceTypeInfo();
2070 ObjPtr<mirror::Class> actual_class = actual_rti.GetTypeHandle().Get();
2071 return (actual_rti.IsExact() && !declared_is_exact) ||
2072 (declared_class != actual_class && declared_class->IsAssignableFrom(actual_class));
2073 }
2074
IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,bool declared_can_be_null,HInstruction * actual_obj)2075 static bool IsReferenceTypeRefinement(ObjPtr<mirror::Class> declared_class,
2076 bool declared_can_be_null,
2077 HInstruction* actual_obj)
2078 REQUIRES_SHARED(Locks::mutator_lock_) {
2079 bool admissible = ReferenceTypePropagation::IsAdmissible(declared_class);
2080 return IsReferenceTypeRefinement(
2081 admissible ? declared_class : GetClassRoot<mirror::Class>(),
2082 /*declared_is_exact=*/ admissible && declared_class->CannotBeAssignedFromOtherTypes(),
2083 declared_can_be_null,
2084 actual_obj);
2085 }
2086
ArgumentTypesMoreSpecific(HInvoke * invoke_instruction,ArtMethod * resolved_method)2087 bool HInliner::ArgumentTypesMoreSpecific(HInvoke* invoke_instruction, ArtMethod* resolved_method) {
2088 // If this is an instance call, test whether the type of the `this` argument
2089 // is more specific than the class which declares the method.
2090 if (!resolved_method->IsStatic()) {
2091 if (IsReferenceTypeRefinement(resolved_method->GetDeclaringClass(),
2092 /*declared_can_be_null=*/ false,
2093 invoke_instruction->InputAt(0u))) {
2094 return true;
2095 }
2096 }
2097
2098 // Iterate over the list of parameter types and test whether any of the
2099 // actual inputs has a more specific reference type than the type declared in
2100 // the signature.
2101 const dex::TypeList* param_list = resolved_method->GetParameterTypeList();
2102 for (size_t param_idx = 0,
2103 input_idx = resolved_method->IsStatic() ? 0 : 1,
2104 e = (param_list == nullptr ? 0 : param_list->Size());
2105 param_idx < e;
2106 ++param_idx, ++input_idx) {
2107 HInstruction* input = invoke_instruction->InputAt(input_idx);
2108 if (input->GetType() == DataType::Type::kReference) {
2109 ObjPtr<mirror::Class> param_cls = resolved_method->LookupResolvedClassFromTypeIndex(
2110 param_list->GetTypeItem(param_idx).type_idx_);
2111 if (IsReferenceTypeRefinement(param_cls, /*declared_can_be_null=*/ true, input)) {
2112 return true;
2113 }
2114 }
2115 }
2116
2117 return false;
2118 }
2119
ReturnTypeMoreSpecific(HInstruction * return_replacement,HInvoke * invoke_instruction)2120 bool HInliner::ReturnTypeMoreSpecific(HInstruction* return_replacement,
2121 HInvoke* invoke_instruction) {
2122 // Check the integrity of reference types and run another type propagation if needed.
2123 if (return_replacement != nullptr) {
2124 if (return_replacement->GetType() == DataType::Type::kReference) {
2125 // Test if the return type is a refinement of the declared return type.
2126 ReferenceTypeInfo invoke_rti = invoke_instruction->GetReferenceTypeInfo();
2127 if (IsReferenceTypeRefinement(invoke_rti.GetTypeHandle().Get(),
2128 invoke_rti.IsExact(),
2129 /*declared_can_be_null=*/ true,
2130 return_replacement)) {
2131 return true;
2132 } else if (return_replacement->IsInstanceFieldGet()) {
2133 HInstanceFieldGet* field_get = return_replacement->AsInstanceFieldGet();
2134 if (field_get->GetFieldInfo().GetField() ==
2135 GetClassRoot<mirror::Object>()->GetInstanceField(0)) {
2136 return true;
2137 }
2138 }
2139 } else if (return_replacement->IsInstanceOf()) {
2140 // Inlining InstanceOf into an If may put a tighter bound on reference types.
2141 return true;
2142 }
2143 }
2144
2145 return false;
2146 }
2147
FixUpReturnReferenceType(ArtMethod * resolved_method,HInstruction * return_replacement)2148 void HInliner::FixUpReturnReferenceType(ArtMethod* resolved_method,
2149 HInstruction* return_replacement) {
2150 if (return_replacement != nullptr) {
2151 if (return_replacement->GetType() == DataType::Type::kReference) {
2152 if (!return_replacement->GetReferenceTypeInfo().IsValid()) {
2153 // Make sure that we have a valid type for the return. We may get an invalid one when
2154 // we inline invokes with multiple branches and create a Phi for the result.
2155 // TODO: we could be more precise by merging the phi inputs but that requires
2156 // some functionality from the reference type propagation.
2157 DCHECK(return_replacement->IsPhi());
2158 ObjPtr<mirror::Class> cls = resolved_method->LookupResolvedReturnType();
2159 ReferenceTypeInfo rti = ReferenceTypePropagation::IsAdmissible(cls)
2160 ? ReferenceTypeInfo::Create(graph_->GetHandleCache()->NewHandle(cls))
2161 : graph_->GetInexactObjectRti();
2162 return_replacement->SetReferenceTypeInfo(rti);
2163 }
2164 }
2165 }
2166 }
2167
2168 } // namespace art
2169