xref: /aosp_15_r20/art/compiler/optimizing/optimizing_compiler.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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 "optimizing_compiler.h"
18 
19 #include <fstream>
20 #include <memory>
21 #include <sstream>
22 
23 #include <stdint.h>
24 
25 #include "art_method-inl.h"
26 #include "base/arena_allocator.h"
27 #include "base/arena_containers.h"
28 #include "base/dumpable.h"
29 #include "base/logging.h"
30 #include "base/macros.h"
31 #include "base/mutex.h"
32 #include "base/scoped_arena_allocator.h"
33 #include "base/systrace.h"
34 #include "base/timing_logger.h"
35 #include "builder.h"
36 #include "code_generator.h"
37 #include "compiler.h"
38 #include "debug/elf_debug_writer.h"
39 #include "debug/method_debug_info.h"
40 #include "dex/dex_file_types.h"
41 #include "driver/compiled_code_storage.h"
42 #include "driver/compiler_options.h"
43 #include "driver/dex_compilation_unit.h"
44 #include "graph_checker.h"
45 #include "graph_visualizer.h"
46 #include "inliner.h"
47 #include "jit/debugger_interface.h"
48 #include "jit/jit.h"
49 #include "jit/jit_code_cache.h"
50 #include "jit/jit_logger.h"
51 #include "jni/quick/jni_compiler.h"
52 #include "linker/linker_patch.h"
53 #include "nodes.h"
54 #include "oat/oat_quick_method_header.h"
55 #include "optimizing/write_barrier_elimination.h"
56 #include "prepare_for_register_allocation.h"
57 #include "profiling_info_builder.h"
58 #include "reference_type_propagation.h"
59 #include "register_allocator_linear_scan.h"
60 #include "select_generator.h"
61 #include "ssa_builder.h"
62 #include "ssa_liveness_analysis.h"
63 #include "ssa_phi_elimination.h"
64 #include "stack_map_stream.h"
65 #include "utils/assembler.h"
66 
67 namespace art HIDDEN {
68 
69 static constexpr size_t kArenaAllocatorMemoryReportThreshold = 8 * MB;
70 
71 static constexpr const char* kPassNameSeparator = "$";
72 
73 /**
74  * Filter to apply to the visualizer. Methods whose name contain that filter will
75  * be dumped.
76  */
77 static constexpr const char kStringFilter[] = "";
78 
79 class PassScope;
80 
81 class PassObserver : public ValueObject {
82  public:
PassObserver(HGraph * graph,CodeGenerator * codegen,std::ostream * visualizer_output,const CompilerOptions & compiler_options)83   PassObserver(HGraph* graph,
84                CodeGenerator* codegen,
85                std::ostream* visualizer_output,
86                const CompilerOptions& compiler_options)
87       : graph_(graph),
88         last_seen_graph_size_(0),
89         cached_method_name_(),
90         timing_logger_enabled_(compiler_options.GetDumpPassTimings()),
91         timing_logger_(timing_logger_enabled_ ? GetMethodName() : "", true, true),
92         disasm_info_(graph->GetAllocator()),
93         visualizer_oss_(),
94         visualizer_output_(visualizer_output),
95         visualizer_enabled_(!compiler_options.GetDumpCfgFileName().empty()),
96         visualizer_(&visualizer_oss_, graph, codegen),
97         codegen_(codegen),
98         graph_in_bad_state_(false) {
99     if (timing_logger_enabled_ || visualizer_enabled_) {
100       if (!IsVerboseMethod(compiler_options, GetMethodName())) {
101         timing_logger_enabled_ = visualizer_enabled_ = false;
102       }
103       if (visualizer_enabled_) {
104         visualizer_.PrintHeader(GetMethodName());
105         codegen->SetDisassemblyInformation(&disasm_info_);
106       }
107     }
108   }
109 
~PassObserver()110   ~PassObserver() {
111     if (timing_logger_enabled_) {
112       LOG(INFO) << "TIMINGS " << GetMethodName();
113       LOG(INFO) << Dumpable<TimingLogger>(timing_logger_);
114     }
115     if (visualizer_enabled_) {
116       FlushVisualizer();
117     }
118     DCHECK(visualizer_oss_.str().empty());
119   }
120 
DumpDisassembly()121   void DumpDisassembly() {
122     if (visualizer_enabled_) {
123       visualizer_.DumpGraphWithDisassembly();
124       FlushVisualizer();
125     }
126   }
127 
SetGraphInBadState()128   void SetGraphInBadState() { graph_in_bad_state_ = true; }
129 
GetMethodName()130   const char* GetMethodName() {
131     // PrettyMethod() is expensive, so we delay calling it until we actually have to.
132     if (cached_method_name_.empty()) {
133       cached_method_name_ = graph_->GetDexFile().PrettyMethod(graph_->GetMethodIdx());
134     }
135     return cached_method_name_.c_str();
136   }
137 
138  private:
StartPass(const char * pass_name)139   void StartPass(const char* pass_name) {
140     VLOG(compiler) << "Starting pass: " << pass_name;
141     // Dump graph first, then start timer.
142     if (visualizer_enabled_) {
143       visualizer_.DumpGraph(pass_name, /* is_after_pass= */ false, graph_in_bad_state_);
144       FlushVisualizer();
145     }
146     if (timing_logger_enabled_) {
147       timing_logger_.StartTiming(pass_name);
148     }
149   }
150 
FlushVisualizer()151   void FlushVisualizer() {
152     *visualizer_output_ << visualizer_oss_.str();
153     visualizer_output_->flush();
154     visualizer_oss_.str("");
155     visualizer_oss_.clear();
156   }
157 
EndPass(const char * pass_name,bool pass_change)158   void EndPass(const char* pass_name, bool pass_change) {
159     // Pause timer first, then dump graph.
160     if (timing_logger_enabled_) {
161       timing_logger_.EndTiming();
162     }
163     if (visualizer_enabled_) {
164       visualizer_.DumpGraph(pass_name, /* is_after_pass= */ true, graph_in_bad_state_);
165       FlushVisualizer();
166     }
167 
168     // Validate the HGraph if running in debug mode.
169     if (kIsDebugBuild) {
170       if (!graph_in_bad_state_) {
171         GraphChecker checker(graph_, codegen_);
172         last_seen_graph_size_ = checker.Run(pass_change, last_seen_graph_size_);
173         if (!checker.IsValid()) {
174           std::ostringstream stream;
175           graph_->Dump(stream, codegen_);
176           LOG(FATAL_WITHOUT_ABORT) << "Error after " << pass_name << "(" << graph_->PrettyMethod()
177                                    << "): " << stream.str();
178           LOG(FATAL) << "(" << pass_name <<  "): " << Dumpable<GraphChecker>(checker);
179         }
180       }
181     }
182   }
183 
IsVerboseMethod(const CompilerOptions & compiler_options,const char * method_name)184   static bool IsVerboseMethod(const CompilerOptions& compiler_options, const char* method_name) {
185     // Test an exact match to --verbose-methods. If verbose-methods is set, this overrides an
186     // empty kStringFilter matching all methods.
187     if (compiler_options.HasVerboseMethods()) {
188       return compiler_options.IsVerboseMethod(method_name);
189     }
190 
191     // Test the kStringFilter sub-string. constexpr helper variable to silence unreachable-code
192     // warning when the string is empty.
193     constexpr bool kStringFilterEmpty = arraysize(kStringFilter) <= 1;
194     if (kStringFilterEmpty || strstr(method_name, kStringFilter) != nullptr) {
195       return true;
196     }
197 
198     return false;
199   }
200 
201   HGraph* const graph_;
202   size_t last_seen_graph_size_;
203 
204   std::string cached_method_name_;
205 
206   bool timing_logger_enabled_;
207   TimingLogger timing_logger_;
208 
209   DisassemblyInformation disasm_info_;
210 
211   std::ostringstream visualizer_oss_;
212   std::ostream* visualizer_output_;
213   bool visualizer_enabled_;
214   HGraphVisualizer visualizer_;
215   CodeGenerator* codegen_;
216 
217   // Flag to be set by the compiler if the pass failed and the graph is not
218   // expected to validate.
219   bool graph_in_bad_state_;
220 
221   friend PassScope;
222 
223   DISALLOW_COPY_AND_ASSIGN(PassObserver);
224 };
225 
226 class PassScope : public ValueObject {
227  public:
PassScope(const char * pass_name,PassObserver * pass_observer)228   PassScope(const char *pass_name, PassObserver* pass_observer)
229       : pass_name_(pass_name),
230         pass_change_(true),  // assume change
231         pass_observer_(pass_observer) {
232     pass_observer_->StartPass(pass_name_);
233   }
234 
SetPassNotChanged()235   void SetPassNotChanged() {
236     pass_change_ = false;
237   }
238 
~PassScope()239   ~PassScope() {
240     pass_observer_->EndPass(pass_name_, pass_change_);
241   }
242 
243  private:
244   const char* const pass_name_;
245   bool pass_change_;
246   PassObserver* const pass_observer_;
247 };
248 
249 class OptimizingCompiler final : public Compiler {
250  public:
251   explicit OptimizingCompiler(const CompilerOptions& compiler_options,
252                               CompiledCodeStorage* storage);
253   ~OptimizingCompiler() override;
254 
255   bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file) const override;
256 
257   CompiledMethod* Compile(const dex::CodeItem* code_item,
258                           uint32_t access_flags,
259                           uint16_t class_def_idx,
260                           uint32_t method_idx,
261                           Handle<mirror::ClassLoader> class_loader,
262                           const DexFile& dex_file,
263                           Handle<mirror::DexCache> dex_cache) const override;
264 
265   CompiledMethod* JniCompile(uint32_t access_flags,
266                              uint32_t method_idx,
267                              const DexFile& dex_file,
268                              Handle<mirror::DexCache> dex_cache) const override;
269 
GetEntryPointOf(ArtMethod * method) const270   uintptr_t GetEntryPointOf(ArtMethod* method) const override
271       REQUIRES_SHARED(Locks::mutator_lock_) {
272     return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize(
273         InstructionSetPointerSize(GetCompilerOptions().GetInstructionSet())));
274   }
275 
276   bool JitCompile(Thread* self,
277                   jit::JitCodeCache* code_cache,
278                   jit::JitMemoryRegion* region,
279                   ArtMethod* method,
280                   CompilationKind compilation_kind,
281                   jit::JitLogger* jit_logger)
282       override
283       REQUIRES_SHARED(Locks::mutator_lock_);
284 
285  private:
RunOptimizations(HGraph * graph,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,PassObserver * pass_observer,const OptimizationDef definitions[],size_t length) const286   bool RunOptimizations(HGraph* graph,
287                         CodeGenerator* codegen,
288                         const DexCompilationUnit& dex_compilation_unit,
289                         PassObserver* pass_observer,
290                         const OptimizationDef definitions[],
291                         size_t length) const {
292     // Convert definitions to optimization passes.
293     ArenaVector<HOptimization*> optimizations = ConstructOptimizations(
294         definitions,
295         length,
296         graph->GetAllocator(),
297         graph,
298         compilation_stats_.get(),
299         codegen,
300         dex_compilation_unit);
301     DCHECK_EQ(length, optimizations.size());
302     // Run the optimization passes one by one. Any "depends_on" pass refers back to
303     // the most recent occurrence of that pass, skipped or executed.
304     std::bitset<static_cast<size_t>(OptimizationPass::kLast) + 1u> pass_changes;
305     pass_changes[static_cast<size_t>(OptimizationPass::kNone)] = true;
306     bool change = false;
307     for (size_t i = 0; i < length; ++i) {
308       if (pass_changes[static_cast<size_t>(definitions[i].depends_on)]) {
309         // Execute the pass and record whether it changed anything.
310         PassScope scope(optimizations[i]->GetPassName(), pass_observer);
311         bool pass_change = optimizations[i]->Run();
312         pass_changes[static_cast<size_t>(definitions[i].pass)] = pass_change;
313         if (pass_change) {
314           change = true;
315         } else {
316           scope.SetPassNotChanged();
317         }
318       } else {
319         // Skip the pass and record that nothing changed.
320         pass_changes[static_cast<size_t>(definitions[i].pass)] = false;
321       }
322     }
323     return change;
324   }
325 
RunOptimizations(HGraph * graph,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,PassObserver * pass_observer,const OptimizationDef (& definitions)[length]) const326   template <size_t length> bool RunOptimizations(
327       HGraph* graph,
328       CodeGenerator* codegen,
329       const DexCompilationUnit& dex_compilation_unit,
330       PassObserver* pass_observer,
331       const OptimizationDef (&definitions)[length]) const {
332     return RunOptimizations(
333         graph, codegen, dex_compilation_unit, pass_observer, definitions, length);
334   }
335 
336   void RunOptimizations(HGraph* graph,
337                         CodeGenerator* codegen,
338                         const DexCompilationUnit& dex_compilation_unit,
339                         PassObserver* pass_observer) const;
340 
341   // Create a 'CompiledMethod' for an optimized graph.
342   CompiledMethod* Emit(ArenaAllocator* allocator,
343                        CodeGenerator* codegen,
344                        bool is_intrinsic,
345                        const dex::CodeItem* item) const;
346 
347   // Try compiling a method and return the code generator used for
348   // compiling it.
349   // This method:
350   // 1) Builds the graph. Returns null if it failed to build it.
351   // 2) Transforms the graph to SSA. Returns null if it failed.
352   // 3) Runs optimizations on the graph, including register allocator.
353   CodeGenerator* TryCompile(ArenaAllocator* allocator,
354                             ArenaStack* arena_stack,
355                             const DexCompilationUnit& dex_compilation_unit,
356                             ArtMethod* method,
357                             CompilationKind compilation_kind,
358                             VariableSizedHandleScope* handles) const;
359 
360   CodeGenerator* TryCompileIntrinsic(ArenaAllocator* allocator,
361                                      ArenaStack* arena_stack,
362                                      const DexCompilationUnit& dex_compilation_unit,
363                                      ArtMethod* method,
364                                      VariableSizedHandleScope* handles) const;
365 
366   bool RunArchOptimizations(HGraph* graph,
367                             CodeGenerator* codegen,
368                             const DexCompilationUnit& dex_compilation_unit,
369                             PassObserver* pass_observer) const;
370 
371   bool RunRequiredPasses(HGraph* graph,
372                          CodeGenerator* codegen,
373                          const DexCompilationUnit& dex_compilation_unit,
374                          PassObserver* pass_observer) const;
375 
376   std::vector<uint8_t> GenerateJitDebugInfo(const debug::MethodDebugInfo& method_debug_info);
377 
378   // This must be called before any other function that dumps data to the cfg
379   void DumpInstructionSetFeaturesToCfg() const;
380 
381   std::unique_ptr<OptimizingCompilerStats> compilation_stats_;
382 
383   std::unique_ptr<std::ostream> visualizer_output_;
384 
385   DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
386 };
387 
388 static const int kMaximumCompilationTimeBeforeWarning = 100; /* ms */
389 
OptimizingCompiler(const CompilerOptions & compiler_options,CompiledCodeStorage * storage)390 OptimizingCompiler::OptimizingCompiler(const CompilerOptions& compiler_options,
391                                        CompiledCodeStorage* storage)
392     : Compiler(compiler_options, storage, kMaximumCompilationTimeBeforeWarning) {
393   // Enable C1visualizer output.
394   const std::string& cfg_file_name = compiler_options.GetDumpCfgFileName();
395   if (!cfg_file_name.empty()) {
396     std::ios_base::openmode cfg_file_mode =
397         compiler_options.GetDumpCfgAppend() ? std::ofstream::app : std::ofstream::out;
398     visualizer_output_.reset(new std::ofstream(cfg_file_name, cfg_file_mode));
399     DumpInstructionSetFeaturesToCfg();
400   }
401   if (compiler_options.GetDumpStats()) {
402     compilation_stats_.reset(new OptimizingCompilerStats());
403   }
404 }
405 
~OptimizingCompiler()406 OptimizingCompiler::~OptimizingCompiler() {
407   if (compilation_stats_.get() != nullptr) {
408     compilation_stats_->Log();
409   }
410 }
411 
DumpInstructionSetFeaturesToCfg() const412 void OptimizingCompiler::DumpInstructionSetFeaturesToCfg() const {
413   const CompilerOptions& compiler_options = GetCompilerOptions();
414   const InstructionSetFeatures* features = compiler_options.GetInstructionSetFeatures();
415   std::string isa_string =
416       std::string("isa:") + GetInstructionSetString(features->GetInstructionSet());
417   std::string features_string = "isa_features:" + features->GetFeatureString();
418   std::string read_barrier_type = "none";
419   if (compiler_options.EmitReadBarrier()) {
420     if (art::kUseBakerReadBarrier)
421       read_barrier_type = "baker";
422     else if (art::kUseTableLookupReadBarrier)
423       read_barrier_type = "tablelookup";
424   }
425   std::string read_barrier_string = ART_FORMAT("read_barrier_type:{}", read_barrier_type);
426   // It is assumed that visualizer_output_ is empty when calling this function, hence the fake
427   // compilation block containing the ISA features will be printed at the beginning of the .cfg
428   // file.
429   *visualizer_output_ << HGraphVisualizer::InsertMetaDataAsCompilationBlock(
430       isa_string + ' ' + features_string + ' ' + read_barrier_string);
431 }
432 
CanCompileMethod(uint32_t method_idx,const DexFile & dex_file) const433 bool OptimizingCompiler::CanCompileMethod([[maybe_unused]] uint32_t method_idx,
434                                           [[maybe_unused]] const DexFile& dex_file) const {
435   return true;
436 }
437 
IsInstructionSetSupported(InstructionSet instruction_set)438 static bool IsInstructionSetSupported(InstructionSet instruction_set) {
439   return instruction_set == InstructionSet::kArm ||
440          instruction_set == InstructionSet::kArm64 ||
441          instruction_set == InstructionSet::kThumb2 ||
442          instruction_set == InstructionSet::kRiscv64 ||
443          instruction_set == InstructionSet::kX86 ||
444          instruction_set == InstructionSet::kX86_64;
445 }
446 
RunRequiredPasses(HGraph * graph,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,PassObserver * pass_observer) const447 bool OptimizingCompiler::RunRequiredPasses(HGraph* graph,
448                                            CodeGenerator* codegen,
449                                            const DexCompilationUnit& dex_compilation_unit,
450                                            PassObserver* pass_observer) const {
451   switch (codegen->GetCompilerOptions().GetInstructionSet()) {
452 #if defined(ART_ENABLE_CODEGEN_arm)
453     case InstructionSet::kThumb2:
454     case InstructionSet::kArm: {
455       OptimizationDef arm_optimizations[] = {
456           OptDef(OptimizationPass::kCriticalNativeAbiFixupArm),
457       };
458       return RunOptimizations(graph,
459                               codegen,
460                               dex_compilation_unit,
461                               pass_observer,
462                               arm_optimizations);
463     }
464 #endif
465 #if defined(ART_ENABLE_CODEGEN_riscv64)
466     case InstructionSet::kRiscv64: {
467       OptimizationDef riscv64_optimizations[] = {
468           OptDef(OptimizationPass::kCriticalNativeAbiFixupRiscv64),
469       };
470       return RunOptimizations(graph,
471                               codegen,
472                               dex_compilation_unit,
473                               pass_observer,
474                               riscv64_optimizations);
475     }
476 #endif
477 #ifdef ART_ENABLE_CODEGEN_x86
478     case InstructionSet::kX86: {
479       OptimizationDef x86_optimizations[] = {
480           OptDef(OptimizationPass::kPcRelativeFixupsX86),
481       };
482       return RunOptimizations(graph,
483                               codegen,
484                               dex_compilation_unit,
485                               pass_observer,
486                               x86_optimizations);
487     }
488 #endif
489     default:
490       UNUSED(graph);
491       UNUSED(codegen);
492       UNUSED(dex_compilation_unit);
493       UNUSED(pass_observer);
494       return false;
495   }
496 }
497 
RunArchOptimizations(HGraph * graph,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,PassObserver * pass_observer) const498 bool OptimizingCompiler::RunArchOptimizations(HGraph* graph,
499                                               CodeGenerator* codegen,
500                                               const DexCompilationUnit& dex_compilation_unit,
501                                               PassObserver* pass_observer) const {
502   switch (codegen->GetCompilerOptions().GetInstructionSet()) {
503 #if defined(ART_ENABLE_CODEGEN_arm)
504     case InstructionSet::kThumb2:
505     case InstructionSet::kArm: {
506       OptimizationDef arm_optimizations[] = {
507           OptDef(OptimizationPass::kInstructionSimplifierArm),
508           OptDef(OptimizationPass::kSideEffectsAnalysis),
509           OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"),
510           OptDef(OptimizationPass::kCriticalNativeAbiFixupArm),
511           OptDef(OptimizationPass::kScheduling)
512       };
513       return RunOptimizations(graph,
514                               codegen,
515                               dex_compilation_unit,
516                               pass_observer,
517                               arm_optimizations);
518     }
519 #endif
520 #ifdef ART_ENABLE_CODEGEN_arm64
521     case InstructionSet::kArm64: {
522       OptimizationDef arm64_optimizations[] = {
523           OptDef(OptimizationPass::kInstructionSimplifierArm64),
524           OptDef(OptimizationPass::kSideEffectsAnalysis),
525           OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"),
526           OptDef(OptimizationPass::kScheduling)
527       };
528       return RunOptimizations(graph,
529                               codegen,
530                               dex_compilation_unit,
531                               pass_observer,
532                               arm64_optimizations);
533     }
534 #endif
535 #if defined(ART_ENABLE_CODEGEN_riscv64)
536     case InstructionSet::kRiscv64: {
537       OptimizationDef riscv64_optimizations[] = {
538           OptDef(OptimizationPass::kInstructionSimplifierRiscv64),
539           OptDef(OptimizationPass::kSideEffectsAnalysis),
540           OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"),
541           OptDef(OptimizationPass::kCriticalNativeAbiFixupRiscv64)
542       };
543       return RunOptimizations(graph,
544                               codegen,
545                               dex_compilation_unit,
546                               pass_observer,
547                               riscv64_optimizations);
548     }
549 #endif
550 #ifdef ART_ENABLE_CODEGEN_x86
551     case InstructionSet::kX86: {
552       OptimizationDef x86_optimizations[] = {
553           OptDef(OptimizationPass::kInstructionSimplifierX86),
554           OptDef(OptimizationPass::kSideEffectsAnalysis),
555           OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"),
556           OptDef(OptimizationPass::kPcRelativeFixupsX86),
557           OptDef(OptimizationPass::kX86MemoryOperandGeneration)
558       };
559       return RunOptimizations(graph,
560                               codegen,
561                               dex_compilation_unit,
562                               pass_observer,
563                               x86_optimizations);
564     }
565 #endif
566 #ifdef ART_ENABLE_CODEGEN_x86_64
567     case InstructionSet::kX86_64: {
568       OptimizationDef x86_64_optimizations[] = {
569           OptDef(OptimizationPass::kInstructionSimplifierX86_64),
570           OptDef(OptimizationPass::kSideEffectsAnalysis),
571           OptDef(OptimizationPass::kGlobalValueNumbering, "GVN$after_arch"),
572           OptDef(OptimizationPass::kX86MemoryOperandGeneration)
573       };
574       return RunOptimizations(graph,
575                               codegen,
576                               dex_compilation_unit,
577                               pass_observer,
578                               x86_64_optimizations);
579     }
580 #endif
581     default:
582       UNUSED(graph);
583       UNUSED(dex_compilation_unit);
584       UNUSED(pass_observer);
585       return false;
586   }
587 }
588 
589 NO_INLINE  // Avoid increasing caller's frame size by large stack-allocated objects.
AllocateRegisters(HGraph * graph,CodeGenerator * codegen,PassObserver * pass_observer,OptimizingCompilerStats * stats)590 static void AllocateRegisters(HGraph* graph,
591                               CodeGenerator* codegen,
592                               PassObserver* pass_observer,
593                               OptimizingCompilerStats* stats) {
594   {
595     PassScope scope(PrepareForRegisterAllocation::kPrepareForRegisterAllocationPassName,
596                     pass_observer);
597     PrepareForRegisterAllocation(graph, codegen->GetCompilerOptions(), stats).Run();
598   }
599   // Use local allocator shared by SSA liveness analysis and register allocator.
600   // (Register allocator creates new objects in the liveness data.)
601   ScopedArenaAllocator local_allocator(graph->GetArenaStack());
602   SsaLivenessAnalysis liveness(graph, codegen, &local_allocator);
603   {
604     PassScope scope(SsaLivenessAnalysis::kLivenessPassName, pass_observer);
605     liveness.Analyze();
606   }
607   {
608     PassScope scope(RegisterAllocator::kRegisterAllocatorPassName, pass_observer);
609     std::unique_ptr<RegisterAllocator> register_allocator =
610         RegisterAllocator::Create(&local_allocator, codegen, liveness);
611     register_allocator->AllocateRegisters();
612   }
613 }
614 
615 // Strip pass name suffix to get optimization name.
ConvertPassNameToOptimizationName(const std::string & pass_name)616 static std::string ConvertPassNameToOptimizationName(const std::string& pass_name) {
617   size_t pos = pass_name.find(kPassNameSeparator);
618   return pos == std::string::npos ? pass_name : pass_name.substr(0, pos);
619 }
620 
RunOptimizations(HGraph * graph,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,PassObserver * pass_observer) const621 void OptimizingCompiler::RunOptimizations(HGraph* graph,
622                                           CodeGenerator* codegen,
623                                           const DexCompilationUnit& dex_compilation_unit,
624                                           PassObserver* pass_observer) const {
625   const std::vector<std::string>* pass_names = GetCompilerOptions().GetPassesToRun();
626   if (pass_names != nullptr) {
627     // If passes were defined on command-line, build the optimization
628     // passes and run these instead of the built-in optimizations.
629     // TODO: a way to define depends_on via command-line?
630     const size_t length = pass_names->size();
631     std::vector<OptimizationDef> optimizations;
632     for (const std::string& pass_name : *pass_names) {
633       std::string opt_name = ConvertPassNameToOptimizationName(pass_name);
634       optimizations.push_back(OptDef(OptimizationPassByName(opt_name), pass_name.c_str()));
635     }
636     RunOptimizations(graph,
637                      codegen,
638                      dex_compilation_unit,
639                      pass_observer,
640                      optimizations.data(),
641                      length);
642     return;
643   }
644 
645   OptimizationDef optimizations[] = {
646       // Initial optimizations.
647       OptDef(OptimizationPass::kConstantFolding),
648       OptDef(OptimizationPass::kInstructionSimplifier),
649       OptDef(OptimizationPass::kDeadCodeElimination,
650              "dead_code_elimination$initial"),
651       // Inlining.
652       OptDef(OptimizationPass::kInliner),
653       // Simplification (if inlining occurred, or if we analyzed the invoke as "always throwing").
654       OptDef(OptimizationPass::kConstantFolding,
655              "constant_folding$after_inlining",
656              OptimizationPass::kInliner),
657       OptDef(OptimizationPass::kInstructionSimplifier,
658              "instruction_simplifier$after_inlining",
659              OptimizationPass::kInliner),
660       OptDef(OptimizationPass::kDeadCodeElimination,
661              "dead_code_elimination$after_inlining",
662              OptimizationPass::kInliner),
663       // GVN.
664       OptDef(OptimizationPass::kSideEffectsAnalysis,
665              "side_effects$before_gvn"),
666       OptDef(OptimizationPass::kGlobalValueNumbering),
667       OptDef(OptimizationPass::kReferenceTypePropagation,
668              "reference_type_propagation$after_gvn",
669              OptimizationPass::kGlobalValueNumbering),
670       // Simplification (TODO: only if GVN occurred).
671       OptDef(OptimizationPass::kSelectGenerator),
672       OptDef(OptimizationPass::kConstantFolding,
673              "constant_folding$after_gvn"),
674       OptDef(OptimizationPass::kInstructionSimplifier,
675              "instruction_simplifier$after_gvn"),
676       OptDef(OptimizationPass::kDeadCodeElimination,
677              "dead_code_elimination$after_gvn"),
678       // High-level optimizations.
679       OptDef(OptimizationPass::kSideEffectsAnalysis,
680              "side_effects$before_licm"),
681       OptDef(OptimizationPass::kInvariantCodeMotion),
682       OptDef(OptimizationPass::kInductionVarAnalysis),
683       OptDef(OptimizationPass::kBoundsCheckElimination),
684       OptDef(OptimizationPass::kLoopOptimization),
685       // Simplification.
686       OptDef(OptimizationPass::kConstantFolding,
687              "constant_folding$after_loop_opt"),
688       OptDef(OptimizationPass::kAggressiveInstructionSimplifier,
689              "instruction_simplifier$after_loop_opt"),
690       OptDef(OptimizationPass::kDeadCodeElimination,
691              "dead_code_elimination$after_loop_opt"),
692       // Other high-level optimizations.
693       OptDef(OptimizationPass::kLoadStoreElimination),
694       OptDef(OptimizationPass::kCHAGuardOptimization),
695       OptDef(OptimizationPass::kCodeSinking),
696       // Simplification.
697       OptDef(OptimizationPass::kConstantFolding,
698              "constant_folding$before_codegen"),
699       // The codegen has a few assumptions that only the instruction simplifier
700       // can satisfy. For example, the code generator does not expect to see a
701       // HTypeConversion from a type to the same type.
702       OptDef(OptimizationPass::kAggressiveInstructionSimplifier,
703              "instruction_simplifier$before_codegen"),
704       // Simplification may result in dead code that should be removed prior to
705       // code generation.
706       OptDef(OptimizationPass::kDeadCodeElimination,
707              "dead_code_elimination$before_codegen"),
708       // Eliminate constructor fences after code sinking to avoid
709       // complicated sinking logic to split a fence with many inputs.
710       OptDef(OptimizationPass::kConstructorFenceRedundancyElimination)
711   };
712   RunOptimizations(graph,
713                    codegen,
714                    dex_compilation_unit,
715                    pass_observer,
716                    optimizations);
717 
718   RunArchOptimizations(graph, codegen, dex_compilation_unit, pass_observer);
719 }
720 
EmitAndSortLinkerPatches(CodeGenerator * codegen)721 static ArenaVector<linker::LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) {
722   ArenaVector<linker::LinkerPatch> linker_patches(codegen->GetGraph()->GetAllocator()->Adapter());
723   codegen->EmitLinkerPatches(&linker_patches);
724 
725   // Sort patches by literal offset. Required for .oat_patches encoding.
726   std::sort(linker_patches.begin(), linker_patches.end(),
727             [](const linker::LinkerPatch& lhs, const linker::LinkerPatch& rhs) {
728     return lhs.LiteralOffset() < rhs.LiteralOffset();
729   });
730 
731   return linker_patches;
732 }
733 
Emit(ArenaAllocator * allocator,CodeGenerator * codegen,bool is_intrinsic,const dex::CodeItem * code_item_for_osr_check) const734 CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* allocator,
735                                          CodeGenerator* codegen,
736                                          bool is_intrinsic,
737                                          const dex::CodeItem* code_item_for_osr_check) const {
738   ArenaVector<linker::LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);
739   ScopedArenaVector<uint8_t> stack_map = codegen->BuildStackMaps(code_item_for_osr_check);
740 
741   CompiledCodeStorage* storage = GetCompiledCodeStorage();
742   CompiledMethod* compiled_method = storage->CreateCompiledMethod(
743       codegen->GetInstructionSet(),
744       codegen->GetCode(),
745       ArrayRef<const uint8_t>(stack_map),
746       ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
747       ArrayRef<const linker::LinkerPatch>(linker_patches),
748       is_intrinsic);
749 
750   for (const linker::LinkerPatch& patch : linker_patches) {
751     if (codegen->NeedsThunkCode(patch) && storage->GetThunkCode(patch).empty()) {
752       ArenaVector<uint8_t> code(allocator->Adapter());
753       std::string debug_name;
754       codegen->EmitThunkCode(patch, &code, &debug_name);
755       storage->SetThunkCode(patch, ArrayRef<const uint8_t>(code), debug_name);
756     }
757   }
758 
759   return compiled_method;
760 }
761 
TryCompile(ArenaAllocator * allocator,ArenaStack * arena_stack,const DexCompilationUnit & dex_compilation_unit,ArtMethod * method,CompilationKind compilation_kind,VariableSizedHandleScope * handles) const762 CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator,
763                                               ArenaStack* arena_stack,
764                                               const DexCompilationUnit& dex_compilation_unit,
765                                               ArtMethod* method,
766                                               CompilationKind compilation_kind,
767                                               VariableSizedHandleScope* handles) const {
768   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptBytecodeCompilation);
769   const CompilerOptions& compiler_options = GetCompilerOptions();
770   InstructionSet instruction_set = compiler_options.GetInstructionSet();
771   const DexFile& dex_file = *dex_compilation_unit.GetDexFile();
772   uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex();
773   const dex::CodeItem* code_item = dex_compilation_unit.GetCodeItem();
774 
775   // Always use the Thumb-2 assembler: some runtime functionality
776   // (like implicit stack overflow checks) assume Thumb-2.
777   DCHECK_NE(instruction_set, InstructionSet::kArm);
778 
779   // Do not attempt to compile on architectures we do not support.
780   if (!IsInstructionSetSupported(instruction_set)) {
781     MaybeRecordStat(compilation_stats_.get(),
782                     MethodCompilationStat::kNotCompiledUnsupportedIsa);
783     return nullptr;
784   }
785 
786   if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) {
787     SCOPED_TRACE << "Not compiling because of pathological case";
788     MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledPathological);
789     return nullptr;
790   }
791 
792   // Implementation of the space filter: do not compile a code item whose size in
793   // code units is bigger than 128.
794   static constexpr size_t kSpaceFilterOptimizingThreshold = 128;
795   if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace)
796       && (CodeItemInstructionAccessor(dex_file, code_item).InsnsSizeInCodeUnits() >
797           kSpaceFilterOptimizingThreshold)) {
798     SCOPED_TRACE << "Not compiling because of space filter";
799     MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledSpaceFilter);
800     return nullptr;
801   }
802 
803   CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item, method_idx);
804 
805   bool dead_reference_safe;
806   // For AOT compilation, we may not get a method, for example if its class is erroneous,
807   // possibly due to an unavailable superclass.  JIT should always have a method.
808   DCHECK(Runtime::Current()->IsAotCompiler() || method != nullptr);
809   if (method != nullptr) {
810     const dex::ClassDef* containing_class;
811     {
812       ScopedObjectAccess soa(Thread::Current());
813       containing_class = &method->GetClassDef();
814     }
815     // MethodContainsRSensitiveAccess is currently slow, but HasDeadReferenceSafeAnnotation()
816     // is currently rarely true.
817     dead_reference_safe =
818         annotations::HasDeadReferenceSafeAnnotation(dex_file, *containing_class)
819         && !annotations::MethodContainsRSensitiveAccess(dex_file, *containing_class, method_idx);
820   } else {
821     // If we could not resolve the class, conservatively assume it's dead-reference unsafe.
822     dead_reference_safe = false;
823   }
824 
825   HGraph* graph = new (allocator) HGraph(
826       allocator,
827       arena_stack,
828       handles,
829       dex_file,
830       method_idx,
831       compiler_options.GetInstructionSet(),
832       kInvalidInvokeType,
833       dead_reference_safe,
834       compiler_options.GetDebuggable(),
835       compilation_kind);
836 
837   if (method != nullptr) {
838     graph->SetArtMethod(method);
839   }
840 
841   jit::Jit* jit = Runtime::Current()->GetJit();
842   if (jit != nullptr) {
843     ProfilingInfo* info = jit->GetCodeCache()->GetProfilingInfo(method, Thread::Current());
844     graph->SetProfilingInfo(info);
845   }
846 
847   std::unique_ptr<CodeGenerator> codegen(
848       CodeGenerator::Create(graph,
849                             compiler_options,
850                             compilation_stats_.get()));
851   if (codegen.get() == nullptr) {
852     MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledNoCodegen);
853     return nullptr;
854   }
855   codegen->GetAssembler()->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo());
856 
857   PassObserver pass_observer(graph,
858                              codegen.get(),
859                              visualizer_output_.get(),
860                              compiler_options);
861 
862   {
863     VLOG(compiler) << "Building " << pass_observer.GetMethodName();
864     PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
865     HGraphBuilder builder(graph,
866                           code_item_accessor,
867                           &dex_compilation_unit,
868                           &dex_compilation_unit,
869                           codegen.get(),
870                           compilation_stats_.get());
871     GraphAnalysisResult result = builder.BuildGraph();
872     if (result != kAnalysisSuccess) {
873       // Don't try recompiling this method again.
874       if (method != nullptr) {
875         ScopedObjectAccess soa(Thread::Current());
876         method->SetDontCompile();
877       }
878       SCOPED_TRACE << "Not compiling because of " << result;
879       switch (result) {
880         case kAnalysisSkipped: {
881           MaybeRecordStat(compilation_stats_.get(),
882                           MethodCompilationStat::kNotCompiledSkipped);
883           break;
884         }
885         case kAnalysisInvalidBytecode: {
886           MaybeRecordStat(compilation_stats_.get(),
887                           MethodCompilationStat::kNotCompiledInvalidBytecode);
888           break;
889         }
890         case kAnalysisFailThrowCatchLoop: {
891           MaybeRecordStat(compilation_stats_.get(),
892                           MethodCompilationStat::kNotCompiledThrowCatchLoop);
893           break;
894         }
895         case kAnalysisFailAmbiguousArrayOp: {
896           MaybeRecordStat(compilation_stats_.get(),
897                           MethodCompilationStat::kNotCompiledAmbiguousArrayOp);
898           break;
899         }
900         case kAnalysisFailIrreducibleLoopAndStringInit: {
901           MaybeRecordStat(compilation_stats_.get(),
902                           MethodCompilationStat::kNotCompiledIrreducibleLoopAndStringInit);
903           break;
904         }
905         case kAnalysisFailPhiEquivalentInOsr: {
906           MaybeRecordStat(compilation_stats_.get(),
907                           MethodCompilationStat::kNotCompiledPhiEquivalentInOsr);
908           break;
909         }
910         case kAnalysisSuccess:
911           LOG(FATAL) << "Unreachable";
912           UNREACHABLE();
913       }
914       pass_observer.SetGraphInBadState();
915       return nullptr;
916     }
917   }
918 
919   if (compilation_kind == CompilationKind::kBaseline && compiler_options.ProfileBranches()) {
920     graph->SetUsefulOptimizing();
921     // Branch profiling currently doesn't support running optimizations.
922     RunRequiredPasses(graph, codegen.get(), dex_compilation_unit, &pass_observer);
923   } else {
924     RunOptimizations(graph, codegen.get(), dex_compilation_unit, &pass_observer);
925     PassScope scope(WriteBarrierElimination::kWBEPassName, &pass_observer);
926     WriteBarrierElimination(graph, compilation_stats_.get()).Run();
927   }
928 
929   // If we are compiling baseline and we haven't created a profiling info for
930   // this method already, do it now.
931   if (jit != nullptr &&
932       compilation_kind == CompilationKind::kBaseline &&
933       graph->IsUsefulOptimizing() &&
934       graph->GetProfilingInfo() == nullptr) {
935     ProfilingInfoBuilder(
936         graph, codegen->GetCompilerOptions(), codegen.get(), compilation_stats_.get()).Run();
937     // We expect a profiling info to be created and attached to the graph.
938     // However, we may have run out of memory trying to create it, so in this
939     // case just abort the compilation.
940     if (graph->GetProfilingInfo() == nullptr) {
941       SCOPED_TRACE << "Not compiling because of out of memory";
942       MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit);
943       return nullptr;
944     }
945   }
946 
947   AllocateRegisters(graph,
948                     codegen.get(),
949                     &pass_observer,
950                     compilation_stats_.get());
951 
952   if (UNLIKELY(codegen->GetFrameSize() > codegen->GetMaximumFrameSize())) {
953     SCOPED_TRACE << "Not compiling because of stack frame too large";
954     LOG(WARNING) << "Stack frame size is " << codegen->GetFrameSize()
955                  << " which is larger than the maximum of " << codegen->GetMaximumFrameSize()
956                  << " bytes. Method: " << graph->PrettyMethod();
957     MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledFrameTooBig);
958     return nullptr;
959   }
960 
961   codegen->Compile();
962   pass_observer.DumpDisassembly();
963 
964   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiledBytecode);
965   return codegen.release();
966 }
967 
TryCompileIntrinsic(ArenaAllocator * allocator,ArenaStack * arena_stack,const DexCompilationUnit & dex_compilation_unit,ArtMethod * method,VariableSizedHandleScope * handles) const968 CodeGenerator* OptimizingCompiler::TryCompileIntrinsic(
969     ArenaAllocator* allocator,
970     ArenaStack* arena_stack,
971     const DexCompilationUnit& dex_compilation_unit,
972     ArtMethod* method,
973     VariableSizedHandleScope* handles) const {
974   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kAttemptIntrinsicCompilation);
975   const CompilerOptions& compiler_options = GetCompilerOptions();
976   InstructionSet instruction_set = compiler_options.GetInstructionSet();
977   const DexFile& dex_file = *dex_compilation_unit.GetDexFile();
978   uint32_t method_idx = dex_compilation_unit.GetDexMethodIndex();
979 
980   // Always use the Thumb-2 assembler: some runtime functionality
981   // (like implicit stack overflow checks) assume Thumb-2.
982   DCHECK_NE(instruction_set, InstructionSet::kArm);
983 
984   // Do not attempt to compile on architectures we do not support.
985   if (!IsInstructionSetSupported(instruction_set)) {
986     return nullptr;
987   }
988 
989   HGraph* graph = new (allocator) HGraph(
990       allocator,
991       arena_stack,
992       handles,
993       dex_file,
994       method_idx,
995       compiler_options.GetInstructionSet(),
996       kInvalidInvokeType,
997       /* dead_reference_safe= */ true,  // Intrinsics don't affect dead reference safety.
998       compiler_options.GetDebuggable(),
999       CompilationKind::kOptimized);
1000 
1001   DCHECK(Runtime::Current()->IsAotCompiler());
1002   DCHECK(method != nullptr);
1003   graph->SetArtMethod(method);
1004 
1005   std::unique_ptr<CodeGenerator> codegen(
1006       CodeGenerator::Create(graph,
1007                             compiler_options,
1008                             compilation_stats_.get()));
1009   if (codegen.get() == nullptr) {
1010     return nullptr;
1011   }
1012   codegen->GetAssembler()->cfi().SetEnabled(compiler_options.GenerateAnyDebugInfo());
1013 
1014   PassObserver pass_observer(graph,
1015                              codegen.get(),
1016                              visualizer_output_.get(),
1017                              compiler_options);
1018 
1019   {
1020     VLOG(compiler) << "Building intrinsic graph " << pass_observer.GetMethodName();
1021     PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
1022     HGraphBuilder builder(graph,
1023                           CodeItemDebugInfoAccessor(),  // Null code item.
1024                           &dex_compilation_unit,
1025                           &dex_compilation_unit,
1026                           codegen.get(),
1027                           compilation_stats_.get());
1028     builder.BuildIntrinsicGraph(method);
1029   }
1030 
1031   OptimizationDef optimizations[] = {
1032       // The codegen has a few assumptions that only the instruction simplifier
1033       // can satisfy.
1034       OptDef(OptimizationPass::kInstructionSimplifier),
1035   };
1036   RunOptimizations(graph,
1037                    codegen.get(),
1038                    dex_compilation_unit,
1039                    &pass_observer,
1040                    optimizations);
1041 
1042   RunArchOptimizations(graph, codegen.get(), dex_compilation_unit, &pass_observer);
1043   {
1044     PassScope scope(WriteBarrierElimination::kWBEPassName, &pass_observer);
1045     WriteBarrierElimination(graph, compilation_stats_.get()).Run();
1046   }
1047 
1048   AllocateRegisters(graph,
1049                     codegen.get(),
1050                     &pass_observer,
1051                     compilation_stats_.get());
1052   if (!codegen->IsLeafMethod()) {
1053     VLOG(compiler) << "Intrinsic method is not leaf: " << method->GetIntrinsic()
1054         << " " << graph->PrettyMethod();
1055     return nullptr;
1056   }
1057 
1058   CHECK_LE(codegen->GetFrameSize(), codegen->GetMaximumFrameSize());
1059   codegen->Compile();
1060   pass_observer.DumpDisassembly();
1061 
1062   VLOG(compiler) << "Compiled intrinsic: " << method->GetIntrinsic()
1063       << " " << graph->PrettyMethod();
1064   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiledIntrinsic);
1065   return codegen.release();
1066 }
1067 
Compile(const dex::CodeItem * code_item,uint32_t access_flags,uint16_t class_def_idx,uint32_t method_idx,Handle<mirror::ClassLoader> jclass_loader,const DexFile & dex_file,Handle<mirror::DexCache> dex_cache) const1068 CompiledMethod* OptimizingCompiler::Compile(const dex::CodeItem* code_item,
1069                                             uint32_t access_flags,
1070                                             uint16_t class_def_idx,
1071                                             uint32_t method_idx,
1072                                             Handle<mirror::ClassLoader> jclass_loader,
1073                                             const DexFile& dex_file,
1074                                             Handle<mirror::DexCache> dex_cache) const {
1075   const CompilerOptions& compiler_options = GetCompilerOptions();
1076   DCHECK(compiler_options.IsAotCompiler());
1077   CompiledMethod* compiled_method = nullptr;
1078   Runtime* runtime = Runtime::Current();
1079   DCHECK(runtime->IsAotCompiler());
1080   ArenaAllocator allocator(runtime->GetArenaPool());
1081   ArenaStack arena_stack(runtime->GetArenaPool());
1082   std::unique_ptr<CodeGenerator> codegen;
1083   bool compiled_intrinsic = false;
1084   {
1085     ScopedObjectAccess soa(Thread::Current());
1086     ArtMethod* method =
1087         runtime->GetClassLinker()->ResolveMethodId(method_idx, dex_cache, jclass_loader);
1088     soa.Self()->ClearException();  // Suppress exception if any.
1089     VariableSizedHandleScope handles(soa.Self());
1090     Handle<mirror::Class> compiling_class =
1091         handles.NewHandle(method != nullptr ? method->GetDeclaringClass() : nullptr);
1092     DexCompilationUnit dex_compilation_unit(
1093         jclass_loader,
1094         runtime->GetClassLinker(),
1095         dex_file,
1096         code_item,
1097         class_def_idx,
1098         method_idx,
1099         access_flags,
1100         /*verified_method=*/ nullptr,  // Not needed by the Optimizing compiler.
1101         dex_cache,
1102         compiling_class);
1103     // All signature polymorphic methods are native.
1104     DCHECK(method == nullptr || !method->IsSignaturePolymorphic());
1105     // Go to native so that we don't block GC during compilation.
1106     ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
1107     // Try to compile a fully intrinsified implementation.
1108     if (method != nullptr && UNLIKELY(method->IsIntrinsic())) {
1109       DCHECK(compiler_options.IsBootImage());
1110       codegen.reset(
1111           TryCompileIntrinsic(&allocator,
1112                               &arena_stack,
1113                               dex_compilation_unit,
1114                               method,
1115                               &handles));
1116       if (codegen != nullptr) {
1117         compiled_intrinsic = true;
1118       }
1119     }
1120     if (codegen == nullptr) {
1121       codegen.reset(
1122           TryCompile(&allocator,
1123                      &arena_stack,
1124                      dex_compilation_unit,
1125                      method,
1126                      compiler_options.IsBaseline()
1127                         ? CompilationKind::kBaseline
1128                         : CompilationKind::kOptimized,
1129                      &handles));
1130     }
1131   }
1132   if (codegen.get() != nullptr) {
1133     compiled_method = Emit(&allocator,
1134                            codegen.get(),
1135                            compiled_intrinsic,
1136                            compiled_intrinsic ? nullptr : code_item);
1137 
1138     if (kArenaAllocatorCountAllocations) {
1139       codegen.reset();  // Release codegen's ScopedArenaAllocator for memory accounting.
1140       size_t total_allocated = allocator.BytesAllocated() + arena_stack.PeakBytesAllocated();
1141       if (total_allocated > kArenaAllocatorMemoryReportThreshold) {
1142         MemStats mem_stats(allocator.GetMemStats());
1143         MemStats peak_stats(arena_stack.GetPeakStats());
1144         LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling "
1145                   << dex_file.PrettyMethod(method_idx)
1146                   << "\n" << Dumpable<MemStats>(mem_stats)
1147                   << "\n" << Dumpable<MemStats>(peak_stats);
1148       }
1149     }
1150   }
1151 
1152   if (kIsDebugBuild &&
1153       compiler_options.CompileArtTest() &&
1154       IsInstructionSetSupported(compiler_options.GetInstructionSet())) {
1155     // For testing purposes, we put a special marker on method names
1156     // that should be compiled with this compiler (when the
1157     // instruction set is supported). This makes sure we're not
1158     // regressing.
1159     std::string method_name = dex_file.PrettyMethod(method_idx);
1160     bool shouldCompile = method_name.find("$opt$") != std::string::npos;
1161     DCHECK_IMPLIES(compiled_method == nullptr, !shouldCompile) << "Didn't compile " << method_name;
1162   }
1163 
1164   return compiled_method;
1165 }
1166 
CreateJniStackMap(ScopedArenaAllocator * allocator,const JniCompiledMethod & jni_compiled_method,size_t code_size,bool debuggable)1167 static ScopedArenaVector<uint8_t> CreateJniStackMap(ScopedArenaAllocator* allocator,
1168                                                     const JniCompiledMethod& jni_compiled_method,
1169                                                     size_t code_size,
1170                                                     bool debuggable) {
1171   // StackMapStream is quite large, so allocate it using the ScopedArenaAllocator
1172   // to stay clear of the frame size limit.
1173   std::unique_ptr<StackMapStream> stack_map_stream(
1174       new (allocator) StackMapStream(allocator, jni_compiled_method.GetInstructionSet()));
1175   stack_map_stream->BeginMethod(jni_compiled_method.GetFrameSize(),
1176                                 jni_compiled_method.GetCoreSpillMask(),
1177                                 jni_compiled_method.GetFpSpillMask(),
1178                                 /* num_dex_registers= */ 0,
1179                                 /* baseline= */ false,
1180                                 debuggable);
1181   stack_map_stream->EndMethod(code_size);
1182   return stack_map_stream->Encode();
1183 }
1184 
JniCompile(uint32_t access_flags,uint32_t method_idx,const DexFile & dex_file,Handle<mirror::DexCache> dex_cache) const1185 CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags,
1186                                                uint32_t method_idx,
1187                                                const DexFile& dex_file,
1188                                                Handle<mirror::DexCache> dex_cache) const {
1189   Runtime* runtime = Runtime::Current();
1190   ArenaAllocator allocator(runtime->GetArenaPool());
1191   ArenaStack arena_stack(runtime->GetArenaPool());
1192 
1193   const CompilerOptions& compiler_options = GetCompilerOptions();
1194   if (compiler_options.IsBootImage()) {
1195     ScopedObjectAccess soa(Thread::Current());
1196     ArtMethod* method = runtime->GetClassLinker()->LookupResolvedMethod(
1197         method_idx, dex_cache.Get(), /*class_loader=*/ nullptr);
1198     // Try to compile a fully intrinsified implementation. Do not try to do this for
1199     // signature polymorphic methods as the InstructionBuilder cannot handle them;
1200     // and it would be useless as they always have a slow path for type conversions.
1201     if (method != nullptr && UNLIKELY(method->IsIntrinsic()) && !method->IsSignaturePolymorphic()) {
1202       VariableSizedHandleScope handles(soa.Self());
1203       ScopedNullHandle<mirror::ClassLoader> class_loader;  // null means boot class path loader.
1204       Handle<mirror::Class> compiling_class = handles.NewHandle(method->GetDeclaringClass());
1205       DexCompilationUnit dex_compilation_unit(
1206           class_loader,
1207           runtime->GetClassLinker(),
1208           dex_file,
1209           /*code_item=*/ nullptr,
1210           /*class_def_idx=*/ DexFile::kDexNoIndex16,
1211           method_idx,
1212           access_flags,
1213           /*verified_method=*/ nullptr,
1214           dex_cache,
1215           compiling_class);
1216       // Go to native so that we don't block GC during compilation.
1217       ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
1218       std::unique_ptr<CodeGenerator> codegen(
1219           TryCompileIntrinsic(&allocator,
1220                               &arena_stack,
1221                               dex_compilation_unit,
1222                               method,
1223                               &handles));
1224       if (codegen != nullptr) {
1225         return Emit(&allocator,
1226                     codegen.get(),
1227                     /*is_intrinsic=*/ true,
1228                     /*item=*/ nullptr);
1229       }
1230     }
1231   }
1232 
1233   JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod(
1234       compiler_options, dex_file.GetMethodShortyView(method_idx), access_flags, &allocator);
1235   MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kCompiledNativeStub);
1236 
1237   ScopedArenaAllocator stack_map_allocator(&arena_stack);  // Will hold the stack map.
1238   ScopedArenaVector<uint8_t> stack_map =
1239       CreateJniStackMap(&stack_map_allocator,
1240                         jni_compiled_method,
1241                         jni_compiled_method.GetCode().size(),
1242                         compiler_options.GetDebuggable() && compiler_options.IsJitCompiler());
1243   return GetCompiledCodeStorage()->CreateCompiledMethod(
1244       jni_compiled_method.GetInstructionSet(),
1245       jni_compiled_method.GetCode(),
1246       ArrayRef<const uint8_t>(stack_map),
1247       jni_compiled_method.GetCfi(),
1248       /*patches=*/ ArrayRef<const linker::LinkerPatch>(),
1249       /*is_intrinsic=*/ false);
1250 }
1251 
CreateOptimizingCompiler(const CompilerOptions & compiler_options,CompiledCodeStorage * storage)1252 Compiler* CreateOptimizingCompiler(const CompilerOptions& compiler_options,
1253                                    CompiledCodeStorage* storage) {
1254   return new OptimizingCompiler(compiler_options, storage);
1255 }
1256 
EncodeArtMethodInInlineInfo(ArtMethod * method)1257 bool EncodeArtMethodInInlineInfo([[maybe_unused]] ArtMethod* method) {
1258   // Note: the runtime is null only for unit testing.
1259   return Runtime::Current() == nullptr || !Runtime::Current()->IsAotCompiler();
1260 }
1261 
JitCompile(Thread * self,jit::JitCodeCache * code_cache,jit::JitMemoryRegion * region,ArtMethod * method,CompilationKind compilation_kind,jit::JitLogger * jit_logger)1262 bool OptimizingCompiler::JitCompile(Thread* self,
1263                                     jit::JitCodeCache* code_cache,
1264                                     jit::JitMemoryRegion* region,
1265                                     ArtMethod* method,
1266                                     CompilationKind compilation_kind,
1267                                     jit::JitLogger* jit_logger) {
1268   const CompilerOptions& compiler_options = GetCompilerOptions();
1269   DCHECK(compiler_options.IsJitCompiler());
1270   DCHECK_EQ(compiler_options.IsJitCompilerForSharedCode(), code_cache->IsSharedRegion(*region));
1271   StackHandleScope<3> hs(self);
1272   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
1273       method->GetDeclaringClass()->GetClassLoader()));
1274   Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
1275   DCHECK(method->IsCompilable());
1276 
1277   const DexFile* dex_file = method->GetDexFile();
1278   const uint16_t class_def_idx = method->GetClassDefIndex();
1279   const dex::CodeItem* code_item = method->GetCodeItem();
1280   const uint32_t method_idx = method->GetDexMethodIndex();
1281   const uint32_t access_flags = method->GetAccessFlags();
1282 
1283   Runtime* runtime = Runtime::Current();
1284   ArenaAllocator allocator(runtime->GetJitArenaPool());
1285 
1286   if (UNLIKELY(method->IsNative())) {
1287     // Use GenericJniTrampoline for critical native methods in debuggable runtimes. We don't
1288     // support calling method entry / exit hooks for critical native methods yet.
1289     // TODO(mythria): Add support for calling method entry / exit hooks in JITed stubs for critical
1290     // native methods too.
1291     if (compiler_options.GetDebuggable() && method->IsCriticalNative()) {
1292       DCHECK(compiler_options.IsJitCompiler());
1293       return false;
1294     }
1295     // Java debuggable runtimes should set compiler options to debuggable, so that we either
1296     // generate method entry / exit hooks or skip JITing. For critical native methods we don't
1297     // generate method entry / exit hooks so we shouldn't JIT them in debuggable runtimes.
1298     DCHECK_IMPLIES(method->IsCriticalNative(), !runtime->IsJavaDebuggable());
1299 
1300     JniCompiledMethod jni_compiled_method = ArtQuickJniCompileMethod(
1301         compiler_options, dex_file->GetMethodShortyView(method_idx), access_flags, &allocator);
1302     std::vector<Handle<mirror::Object>> roots;
1303     ArenaSet<ArtMethod*, std::less<ArtMethod*>> cha_single_implementation_list(
1304         allocator.Adapter(kArenaAllocCHA));
1305     ArenaStack arena_stack(runtime->GetJitArenaPool());
1306     // StackMapStream is large and it does not fit into this frame, so we need helper method.
1307     ScopedArenaAllocator stack_map_allocator(&arena_stack);  // Will hold the stack map.
1308     ScopedArenaVector<uint8_t> stack_map =
1309         CreateJniStackMap(&stack_map_allocator,
1310                           jni_compiled_method,
1311                           jni_compiled_method.GetCode().size(),
1312                           compiler_options.GetDebuggable() && compiler_options.IsJitCompiler());
1313 
1314     ArrayRef<const uint8_t> reserved_code;
1315     ArrayRef<const uint8_t> reserved_data;
1316     if (!code_cache->Reserve(self,
1317                              region,
1318                              jni_compiled_method.GetCode().size(),
1319                              stack_map.size(),
1320                              /* number_of_roots= */ 0,
1321                              method,
1322                              /*out*/ &reserved_code,
1323                              /*out*/ &reserved_data)) {
1324       MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit);
1325       return false;
1326     }
1327     const uint8_t* code = reserved_code.data() + OatQuickMethodHeader::InstructionAlignedSize();
1328 
1329     // Add debug info after we know the code location but before we update entry-point.
1330     std::vector<uint8_t> debug_info;
1331     if (compiler_options.GenerateAnyDebugInfo()) {
1332       debug::MethodDebugInfo info = {};
1333       // Simpleperf relies on art_jni_trampoline to detect jni methods.
1334       info.custom_name = "art_jni_trampoline";
1335       info.dex_file = dex_file;
1336       info.class_def_index = class_def_idx;
1337       info.dex_method_index = method_idx;
1338       info.access_flags = access_flags;
1339       info.code_item = code_item;
1340       info.isa = jni_compiled_method.GetInstructionSet();
1341       info.deduped = false;
1342       info.is_native_debuggable = compiler_options.GetNativeDebuggable();
1343       info.is_optimized = true;
1344       info.is_code_address_text_relative = false;
1345       info.code_address = reinterpret_cast<uintptr_t>(code);
1346       info.code_size = jni_compiled_method.GetCode().size();
1347       info.frame_size_in_bytes = jni_compiled_method.GetFrameSize();
1348       info.code_info = nullptr;
1349       info.cfi = jni_compiled_method.GetCfi();
1350       debug_info = GenerateJitDebugInfo(info);
1351     }
1352 
1353     if (!code_cache->Commit(self,
1354                             region,
1355                             method,
1356                             reserved_code,
1357                             jni_compiled_method.GetCode(),
1358                             reserved_data,
1359                             roots,
1360                             ArrayRef<const uint8_t>(stack_map),
1361                             debug_info,
1362                             /* is_full_debug_info= */ compiler_options.GetGenerateDebugInfo(),
1363                             compilation_kind,
1364                             cha_single_implementation_list)) {
1365       code_cache->Free(self, region, reserved_code.data(), reserved_data.data());
1366       return false;
1367     }
1368 
1369     Runtime::Current()->GetJit()->AddMemoryUsage(method, allocator.BytesUsed());
1370     if (jit_logger != nullptr) {
1371       jit_logger->WriteLog(code, jni_compiled_method.GetCode().size(), method);
1372     }
1373     return true;
1374   }
1375 
1376   ArenaStack arena_stack(runtime->GetJitArenaPool());
1377   VariableSizedHandleScope handles(self);
1378 
1379   std::unique_ptr<CodeGenerator> codegen;
1380   {
1381     Handle<mirror::Class> compiling_class = handles.NewHandle(method->GetDeclaringClass());
1382     DexCompilationUnit dex_compilation_unit(
1383         class_loader,
1384         runtime->GetClassLinker(),
1385         *dex_file,
1386         code_item,
1387         class_def_idx,
1388         method_idx,
1389         access_flags,
1390         /*verified_method=*/ nullptr,
1391         dex_cache,
1392         compiling_class);
1393 
1394     // Go to native so that we don't block GC during compilation.
1395     ScopedThreadSuspension sts(self, ThreadState::kNative);
1396     codegen.reset(
1397         TryCompile(&allocator,
1398                    &arena_stack,
1399                    dex_compilation_unit,
1400                    method,
1401                    compilation_kind,
1402                    &handles));
1403     if (codegen.get() == nullptr) {
1404       return false;
1405     }
1406   }
1407 
1408   ScopedArenaVector<uint8_t> stack_map = codegen->BuildStackMaps(code_item);
1409 
1410   ArrayRef<const uint8_t> reserved_code;
1411   ArrayRef<const uint8_t> reserved_data;
1412   if (!code_cache->Reserve(self,
1413                            region,
1414                            codegen->GetAssembler()->CodeSize(),
1415                            stack_map.size(),
1416                            /*number_of_roots=*/codegen->GetNumberOfJitRoots(),
1417                            method,
1418                            /*out*/ &reserved_code,
1419                            /*out*/ &reserved_data)) {
1420     MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kJitOutOfMemoryForCommit);
1421     return false;
1422   }
1423   const uint8_t* code = reserved_code.data() + OatQuickMethodHeader::InstructionAlignedSize();
1424   const uint8_t* roots_data = reserved_data.data();
1425 
1426   std::vector<Handle<mirror::Object>> roots;
1427   codegen->EmitJitRoots(const_cast<uint8_t*>(codegen->GetAssembler()->CodeBufferBaseAddress()),
1428                         roots_data,
1429                         &roots);
1430   // The root Handle<>s filled by the codegen reference entries in the VariableSizedHandleScope.
1431   DCHECK(std::all_of(roots.begin(),
1432                      roots.end(),
1433                      [&handles](Handle<mirror::Object> root){
1434                        return handles.Contains(root.GetReference());
1435                      }));
1436 
1437   // Add debug info after we know the code location but before we update entry-point.
1438   std::vector<uint8_t> debug_info;
1439   if (compiler_options.GenerateAnyDebugInfo()) {
1440     debug::MethodDebugInfo info = {};
1441     DCHECK(info.custom_name.empty());
1442     info.dex_file = dex_file;
1443     info.class_def_index = class_def_idx;
1444     info.dex_method_index = method_idx;
1445     info.access_flags = access_flags;
1446     info.code_item = code_item;
1447     info.isa = codegen->GetInstructionSet();
1448     info.deduped = false;
1449     info.is_native_debuggable = compiler_options.GetNativeDebuggable();
1450     info.is_optimized = true;
1451     info.is_code_address_text_relative = false;
1452     info.code_address = reinterpret_cast<uintptr_t>(code);
1453     info.code_size = codegen->GetAssembler()->CodeSize(),
1454     info.frame_size_in_bytes = codegen->GetFrameSize();
1455     info.code_info = stack_map.size() == 0 ? nullptr : stack_map.data();
1456     info.cfi = ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data());
1457     debug_info = GenerateJitDebugInfo(info);
1458   }
1459 
1460   if (compilation_kind == CompilationKind::kBaseline &&
1461       !codegen->GetGraph()->IsUsefulOptimizing()) {
1462     compilation_kind = CompilationKind::kOptimized;
1463   }
1464 
1465   if (!code_cache->Commit(self,
1466                           region,
1467                           method,
1468                           reserved_code,
1469                           codegen->GetCode(),
1470                           reserved_data,
1471                           roots,
1472                           ArrayRef<const uint8_t>(stack_map),
1473                           debug_info,
1474                           /* is_full_debug_info= */ compiler_options.GetGenerateDebugInfo(),
1475                           compilation_kind,
1476                           codegen->GetGraph()->GetCHASingleImplementationList())) {
1477     CHECK_EQ(CodeInfo::HasShouldDeoptimizeFlag(stack_map.data()),
1478              codegen->GetGraph()->HasShouldDeoptimizeFlag());
1479     code_cache->Free(self, region, reserved_code.data(), reserved_data.data());
1480     return false;
1481   }
1482 
1483   Runtime::Current()->GetJit()->AddMemoryUsage(method, allocator.BytesUsed());
1484   if (jit_logger != nullptr) {
1485     jit_logger->WriteLog(code, codegen->GetAssembler()->CodeSize(), method);
1486   }
1487 
1488   if (kArenaAllocatorCountAllocations) {
1489     codegen.reset();  // Release codegen's ScopedArenaAllocator for memory accounting.
1490     size_t total_allocated = allocator.BytesAllocated() + arena_stack.PeakBytesAllocated();
1491     if (total_allocated > kArenaAllocatorMemoryReportThreshold) {
1492       MemStats mem_stats(allocator.GetMemStats());
1493       MemStats peak_stats(arena_stack.GetPeakStats());
1494       LOG(INFO) << "Used " << total_allocated << " bytes of arena memory for compiling "
1495                 << dex_file->PrettyMethod(method_idx)
1496                 << "\n" << Dumpable<MemStats>(mem_stats)
1497                 << "\n" << Dumpable<MemStats>(peak_stats);
1498     }
1499   }
1500 
1501   return true;
1502 }
1503 
GenerateJitDebugInfo(const debug::MethodDebugInfo & info)1504 std::vector<uint8_t> OptimizingCompiler::GenerateJitDebugInfo(const debug::MethodDebugInfo& info) {
1505   const CompilerOptions& compiler_options = GetCompilerOptions();
1506   if (compiler_options.GenerateAnyDebugInfo()) {
1507     // If both flags are passed, generate full debug info.
1508     const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo();
1509 
1510     // Create entry for the single method that we just compiled.
1511     InstructionSet isa = compiler_options.GetInstructionSet();
1512     const InstructionSetFeatures* features = compiler_options.GetInstructionSetFeatures();
1513     return debug::MakeElfFileForJIT(isa, features, mini_debug_info, info);
1514   }
1515   return std::vector<uint8_t>();
1516 }
1517 
1518 }  // namespace art
1519