optimizing_compiler.cc revision 26a25ef62a13f409f941aa39825a51b4d6f0f047
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 <stdint.h>
21
22#include "builder.h"
23#include "code_generator.h"
24#include "compiler.h"
25#include "driver/compiler_driver.h"
26#include "driver/dex_compilation_unit.h"
27#include "graph_visualizer.h"
28#include "gvn.h"
29#include "instruction_simplifier.h"
30#include "nodes.h"
31#include "prepare_for_register_allocation.h"
32#include "register_allocator.h"
33#include "ssa_phi_elimination.h"
34#include "ssa_liveness_analysis.h"
35#include "utils/arena_allocator.h"
36
37namespace art {
38
39/**
40 * Used by the code generator, to allocate the code in a vector.
41 */
42class CodeVectorAllocator FINAL : public CodeAllocator {
43 public:
44  CodeVectorAllocator() {}
45
46  virtual uint8_t* Allocate(size_t size) {
47    size_ = size;
48    memory_.resize(size);
49    return &memory_[0];
50  }
51
52  size_t GetSize() const { return size_; }
53  const std::vector<uint8_t>& GetMemory() const { return memory_; }
54
55 private:
56  std::vector<uint8_t> memory_;
57  size_t size_;
58
59  DISALLOW_COPY_AND_ASSIGN(CodeVectorAllocator);
60};
61
62/**
63 * If set to true, generates a file suitable for the c1visualizer tool and IRHydra.
64 */
65static bool kIsVisualizerEnabled = false;
66
67/**
68 * Filter to apply to the visualizer. Methods whose name contain that filter will
69 * be in the file.
70 */
71static const char* kStringFilter = "";
72
73class OptimizingCompiler FINAL : public Compiler {
74 public:
75  explicit OptimizingCompiler(CompilerDriver* driver);
76  ~OptimizingCompiler();
77
78  bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const
79      OVERRIDE;
80
81  CompiledMethod* Compile(const DexFile::CodeItem* code_item,
82                          uint32_t access_flags,
83                          InvokeType invoke_type,
84                          uint16_t class_def_idx,
85                          uint32_t method_idx,
86                          jobject class_loader,
87                          const DexFile& dex_file) const OVERRIDE;
88
89  CompiledMethod* TryCompile(const DexFile::CodeItem* code_item,
90                             uint32_t access_flags,
91                             InvokeType invoke_type,
92                             uint16_t class_def_idx,
93                             uint32_t method_idx,
94                             jobject class_loader,
95                             const DexFile& dex_file) const;
96
97  // For the following methods we will use the fallback. This is a delegation pattern.
98  CompiledMethod* JniCompile(uint32_t access_flags,
99                             uint32_t method_idx,
100                             const DexFile& dex_file) const OVERRIDE;
101
102  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const OVERRIDE
103      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
104
105  bool WriteElf(art::File* file,
106                OatWriter* oat_writer,
107                const std::vector<const art::DexFile*>& dex_files,
108                const std::string& android_root,
109                bool is_host) const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
110
111  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE;
112
113  void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE;
114
115  void Init() const OVERRIDE;
116
117  void UnInit() const OVERRIDE;
118
119 private:
120  // Whether we should run any optimization or register allocation. If false, will
121  // just run the code generation after the graph was built.
122  const bool run_optimizations_;
123  mutable AtomicInteger total_compiled_methods_;
124  mutable AtomicInteger unoptimized_compiled_methods_;
125  mutable AtomicInteger optimized_compiled_methods_;
126
127  std::unique_ptr<std::ostream> visualizer_output_;
128
129  // Delegate to another compiler in case the optimizing compiler cannot compile a method.
130  // Currently the fallback is the quick compiler.
131  std::unique_ptr<Compiler> delegate_;
132
133  DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler);
134};
135
136static const int kMaximumCompilationTimeBeforeWarning = 100; /* ms */
137
138OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver)
139    : Compiler(driver, kMaximumCompilationTimeBeforeWarning),
140      run_optimizations_(
141          driver->GetCompilerOptions().GetCompilerFilter() != CompilerOptions::kTime),
142      total_compiled_methods_(0),
143      unoptimized_compiled_methods_(0),
144      optimized_compiled_methods_(0),
145      delegate_(Create(driver, Compiler::Kind::kQuick)) {
146  if (kIsVisualizerEnabled) {
147    visualizer_output_.reset(new std::ofstream("art.cfg"));
148  }
149}
150
151void OptimizingCompiler::Init() const {
152  delegate_->Init();
153}
154
155void OptimizingCompiler::UnInit() const {
156  delegate_->UnInit();
157}
158
159OptimizingCompiler::~OptimizingCompiler() {
160  if (total_compiled_methods_ == 0) {
161    LOG(INFO) << "Did not compile any method.";
162  } else {
163    size_t unoptimized_percent = (unoptimized_compiled_methods_ * 100 / total_compiled_methods_);
164    size_t optimized_percent = (optimized_compiled_methods_ * 100 / total_compiled_methods_);
165    LOG(INFO) << "Compiled " << total_compiled_methods_ << " methods: "
166              << unoptimized_percent << "% (" << unoptimized_compiled_methods_ << ") unoptimized, "
167              << optimized_percent << "% (" << optimized_compiled_methods_ << ") optimized.";
168  }
169}
170
171bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file,
172                                          CompilationUnit* cu) const {
173  return delegate_->CanCompileMethod(method_idx, dex_file, cu);
174}
175
176CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags,
177                                               uint32_t method_idx,
178                                               const DexFile& dex_file) const {
179  return delegate_->JniCompile(access_flags, method_idx, dex_file);
180}
181
182uintptr_t OptimizingCompiler::GetEntryPointOf(mirror::ArtMethod* method) const {
183  return delegate_->GetEntryPointOf(method);
184}
185
186bool OptimizingCompiler::WriteElf(art::File* file, OatWriter* oat_writer,
187                                  const std::vector<const art::DexFile*>& dex_files,
188                                  const std::string& android_root, bool is_host) const {
189  return delegate_->WriteElf(file, oat_writer, dex_files, android_root, is_host);
190}
191
192Backend* OptimizingCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
193  return delegate_->GetCodeGenerator(cu, compilation_unit);
194}
195
196void OptimizingCompiler::InitCompilationUnit(CompilationUnit& cu) const {
197  delegate_->InitCompilationUnit(cu);
198}
199
200CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
201                                               uint32_t access_flags,
202                                               InvokeType invoke_type,
203                                               uint16_t class_def_idx,
204                                               uint32_t method_idx,
205                                               jobject class_loader,
206                                               const DexFile& dex_file) const {
207  total_compiled_methods_++;
208  InstructionSet instruction_set = GetCompilerDriver()->GetInstructionSet();
209  // Always use the thumb2 assembler: some runtime functionality (like implicit stack
210  // overflow checks) assume thumb2.
211  if (instruction_set == kArm) {
212    instruction_set = kThumb2;
213  }
214
215  // Do not attempt to compile on architectures we do not support.
216  if (instruction_set != kX86 && instruction_set != kX86_64 && instruction_set != kThumb2) {
217    return nullptr;
218  }
219
220  DexCompilationUnit dex_compilation_unit(
221    nullptr, class_loader, art::Runtime::Current()->GetClassLinker(), dex_file, code_item,
222    class_def_idx, method_idx, access_flags,
223    GetCompilerDriver()->GetVerifiedMethod(&dex_file, method_idx));
224
225  // For testing purposes, we put a special marker on method names that should be compiled
226  // with this compiler. This makes sure we're not regressing.
227  bool shouldCompile = dex_compilation_unit.GetSymbol().find("00024opt_00024") != std::string::npos;
228  bool shouldOptimize =
229      dex_compilation_unit.GetSymbol().find("00024reg_00024") != std::string::npos;
230
231  ArenaPool pool;
232  ArenaAllocator arena(&pool);
233  HGraphBuilder builder(&arena, &dex_compilation_unit, &dex_file, GetCompilerDriver());
234
235  HGraph* graph = builder.BuildGraph(*code_item);
236  if (graph == nullptr) {
237    if (shouldCompile) {
238      LOG(FATAL) << "Could not build graph in optimizing compiler";
239    }
240    return nullptr;
241  }
242
243  CodeGenerator* codegen = CodeGenerator::Create(&arena, graph, instruction_set);
244  if (codegen == nullptr) {
245    if (shouldCompile) {
246      LOG(FATAL) << "Could not find code generator for optimizing compiler";
247    }
248    return nullptr;
249  }
250
251  HGraphVisualizer visualizer(
252      visualizer_output_.get(), graph, kStringFilter, *codegen, dex_compilation_unit);
253  visualizer.DumpGraph("builder");
254
255  CodeVectorAllocator allocator;
256
257  if (run_optimizations_ && RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
258    optimized_compiled_methods_++;
259    graph->BuildDominatorTree();
260    graph->TransformToSSA();
261    visualizer.DumpGraph("ssa");
262    graph->FindNaturalLoops();
263
264    SsaRedundantPhiElimination(graph).Run();
265    SsaDeadPhiElimination(graph).Run();
266    InstructionSimplifier(graph).Run();
267    GlobalValueNumberer(graph->GetArena(), graph).Run();
268    visualizer.DumpGraph(kGVNPassName);
269    PrepareForRegisterAllocation(graph).Run();
270
271    SsaLivenessAnalysis liveness(*graph, codegen);
272    liveness.Analyze();
273    visualizer.DumpGraph(kLivenessPassName);
274
275    RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
276    register_allocator.AllocateRegisters();
277
278    visualizer.DumpGraph(kRegisterAllocatorPassName);
279    codegen->CompileOptimized(&allocator);
280
281    std::vector<uint8_t> mapping_table;
282    SrcMap src_mapping_table;
283    codegen->BuildMappingTable(&mapping_table,
284            GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
285                 &src_mapping_table : nullptr);
286
287    std::vector<uint8_t> stack_map;
288    codegen->BuildStackMaps(&stack_map);
289
290    return new CompiledMethod(GetCompilerDriver(),
291                              instruction_set,
292                              allocator.GetMemory(),
293                              codegen->GetFrameSize(),
294                              codegen->GetCoreSpillMask(),
295                              0, /* FPR spill mask, unused */
296                              mapping_table,
297                              stack_map);
298  } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
299    LOG(FATAL) << "Could not allocate registers in optimizing compiler";
300    return nullptr;
301  } else {
302    unoptimized_compiled_methods_++;
303    codegen->CompileBaseline(&allocator);
304
305    // Run these phases to get some test coverage.
306    graph->BuildDominatorTree();
307    graph->TransformToSSA();
308    visualizer.DumpGraph("ssa");
309    graph->FindNaturalLoops();
310    SsaRedundantPhiElimination(graph).Run();
311    SsaDeadPhiElimination(graph).Run();
312    GlobalValueNumberer(graph->GetArena(), graph).Run();
313    SsaLivenessAnalysis liveness(*graph, codegen);
314    liveness.Analyze();
315    visualizer.DumpGraph(kLivenessPassName);
316
317    std::vector<uint8_t> mapping_table;
318    SrcMap src_mapping_table;
319    codegen->BuildMappingTable(&mapping_table,
320            GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
321                 &src_mapping_table : nullptr);
322    std::vector<uint8_t> vmap_table;
323    codegen->BuildVMapTable(&vmap_table);
324    std::vector<uint8_t> gc_map;
325    codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
326
327    return new CompiledMethod(GetCompilerDriver(),
328                              instruction_set,
329                              allocator.GetMemory(),
330                              codegen->GetFrameSize(),
331                              codegen->GetCoreSpillMask(),
332                              0, /* FPR spill mask, unused */
333                              &src_mapping_table,
334                              mapping_table,
335                              vmap_table,
336                              gc_map,
337                              nullptr);
338  }
339}
340
341CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
342                                            uint32_t access_flags,
343                                            InvokeType invoke_type,
344                                            uint16_t class_def_idx,
345                                            uint32_t method_idx,
346                                            jobject class_loader,
347                                            const DexFile& dex_file) const {
348  CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
349                                      method_idx, class_loader, dex_file);
350  if (method != nullptr) {
351    return method;
352  }
353
354  return delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx,
355                            class_loader, dex_file);
356}
357
358Compiler* CreateOptimizingCompiler(CompilerDriver* driver) {
359  return new OptimizingCompiler(driver);
360}
361
362}  // namespace art
363