Merge "Create HGraph outside Builder, print timings"
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index c509606..20a1b03 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -259,13 +259,14 @@
   return false;
 }
 
-HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item, int start_instruction_id) {
+bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
+  DCHECK(graph_->GetBlocks().IsEmpty());
+
   const uint16_t* code_ptr = code_item.insns_;
   const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
   code_start_ = code_ptr;
 
   // Setup the graph with the entry block and exit block.
-  graph_ = new (arena_) HGraph(arena_, start_instruction_id);
   entry_block_ = new (arena_) HBasicBlock(graph_, 0);
   graph_->AddBlock(entry_block_);
   exit_block_ = new (arena_) HBasicBlock(graph_, kNoDexPc);
@@ -289,7 +290,7 @@
   // Note that the compiler driver is null when unit testing.
   if ((compiler_driver_ != nullptr)
       && SkipCompilation(number_of_dex_instructions, number_of_blocks, number_of_branches)) {
-    return nullptr;
+    return false;
   }
 
   // Also create blocks for catch handlers.
@@ -319,7 +320,7 @@
     MaybeUpdateCurrentBlock(dex_pc);
     const Instruction& instruction = *Instruction::At(code_ptr);
     if (!AnalyzeDexInstruction(instruction, dex_pc)) {
-      return nullptr;
+      return false;
     }
     dex_pc += instruction.SizeInCodeUnits();
     code_ptr += instruction.SizeInCodeUnits();
@@ -331,7 +332,8 @@
   // Add the suspend check to the entry block.
   entry_block_->AddInstruction(new (arena_) HSuspendCheck(0));
   entry_block_->AddInstruction(new (arena_) HGoto());
-  return graph_;
+
+  return true;
 }
 
 void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 8ee27a1..c510136 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -34,19 +34,19 @@
 
 class HGraphBuilder : public ValueObject {
  public:
-  HGraphBuilder(ArenaAllocator* arena,
+  HGraphBuilder(HGraph* graph,
                 DexCompilationUnit* dex_compilation_unit,
                 const DexCompilationUnit* const outer_compilation_unit,
                 const DexFile* dex_file,
                 CompilerDriver* driver,
                 OptimizingCompilerStats* compiler_stats)
-      : arena_(arena),
-        branch_targets_(arena, 0),
-        locals_(arena, 0),
+      : arena_(graph->GetArena()),
+        branch_targets_(graph->GetArena(), 0),
+        locals_(graph->GetArena(), 0),
         entry_block_(nullptr),
         exit_block_(nullptr),
         current_block_(nullptr),
-        graph_(nullptr),
+        graph_(graph),
         constant0_(nullptr),
         constant1_(nullptr),
         dex_file_(dex_file),
@@ -59,14 +59,14 @@
         compilation_stats_(compiler_stats) {}
 
   // Only for unit testing.
-  HGraphBuilder(ArenaAllocator* arena, Primitive::Type return_type = Primitive::kPrimInt)
-      : arena_(arena),
-        branch_targets_(arena, 0),
-        locals_(arena, 0),
+  HGraphBuilder(HGraph* graph, Primitive::Type return_type = Primitive::kPrimInt)
+      : arena_(graph->GetArena()),
+        branch_targets_(graph->GetArena(), 0),
+        locals_(graph->GetArena(), 0),
         entry_block_(nullptr),
         exit_block_(nullptr),
         current_block_(nullptr),
-        graph_(nullptr),
+        graph_(graph),
         constant0_(nullptr),
         constant1_(nullptr),
         dex_file_(nullptr),
@@ -78,7 +78,7 @@
         latest_result_(nullptr),
         compilation_stats_(nullptr) {}
 
-  HGraph* BuildGraph(const DexFile::CodeItem& code, int start_instruction_id = 0);
+  bool BuildGraph(const DexFile::CodeItem& code);
 
  private:
   // Analyzes the dex instruction and adds HInstruction to the graph
@@ -249,7 +249,7 @@
   HBasicBlock* entry_block_;
   HBasicBlock* exit_block_;
   HBasicBlock* current_block_;
-  HGraph* graph_;
+  HGraph* const graph_;
 
   HIntConstant* constant0_;
   HIntConstant* constant1_;
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index dfa4748..e0e0b4c 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -180,10 +180,11 @@
 static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) {
   ArenaPool pool;
   ArenaAllocator arena(&pool);
-  HGraphBuilder builder(&arena);
+  HGraph* graph = new (&arena) HGraph(&arena);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
   // Remove suspend checks, they cannot be executed in this context.
   RemoveSuspendChecks(graph);
   RunCodeBaseline(graph, has_result, expected);
@@ -192,10 +193,11 @@
 static void TestCodeLong(const uint16_t* data, bool has_result, int64_t expected) {
   ArenaPool pool;
   ArenaAllocator arena(&pool);
-  HGraphBuilder builder(&arena, Primitive::kPrimLong);
+  HGraph* graph = new (&arena) HGraph(&arena);
+  HGraphBuilder builder(graph, Primitive::kPrimLong);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
   // Remove suspend checks, they cannot be executed in this context.
   RemoveSuspendChecks(graph);
   RunCodeBaseline(graph, has_result, expected);
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index 3062e37..b246c6f 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -27,10 +27,11 @@
 static void TestCode(const uint16_t* data, const int* blocks, size_t blocks_length) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
   graph->BuildDominatorTree();
   ASSERT_EQ(graph->GetBlocks().Size(), blocks_length);
   for (size_t i = 0, e = blocks_length; i < e; ++i) {
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index 82fe03c..e05d9b3 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -28,9 +28,10 @@
 namespace art {
 
 static HGraph* TestCode(const uint16_t* data, ArenaAllocator* allocator) {
-  HGraphBuilder builder(allocator);
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
+  builder.BuildGraph(*item);
   graph->BuildDominatorTree();
   graph->AnalyzeNaturalLoops();
   return graph;
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 22a3d12..9383d31 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -194,7 +194,9 @@
       }
       output_ << "]";
     }
-    if (pass_name_ == kLivenessPassName && instruction->GetLifetimePosition() != kNoLifetime) {
+    if (pass_name_ == kLivenessPassName
+        && is_after_pass_
+        && instruction->GetLifetimePosition() != kNoLifetime) {
       output_ << " (liveness: " << instruction->GetLifetimePosition();
       if (instruction->HasLiveInterval()) {
         output_ << " ";
@@ -202,7 +204,7 @@
         interval.Dump(output_);
       }
       output_ << ")";
-    } else if (pass_name_ == kRegisterAllocatorPassName) {
+    } else if (pass_name_ == kRegisterAllocatorPassName && is_after_pass_) {
       LocationSummary* locations = instruction->GetLocations();
       if (locations != nullptr) {
         output_ << " ( ";
@@ -310,18 +312,13 @@
 
 HGraphVisualizer::HGraphVisualizer(std::ostream* output,
                                    HGraph* graph,
-                                   const char* string_filter,
                                    const CodeGenerator& codegen,
                                    const char* method_name)
-  : output_(output), graph_(graph), codegen_(codegen), is_enabled_(false) {
+  : output_(output), graph_(graph), codegen_(codegen) {
   if (output == nullptr) {
     return;
   }
-  if (strstr(method_name, string_filter) == nullptr) {
-    return;
-  }
 
-  is_enabled_ = true;
   HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
   printer.StartTag("compilation");
   printer.PrintProperty("name", method_name);
@@ -331,7 +328,8 @@
 }
 
 void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
-  if (is_enabled_) {
+  DCHECK(output_ != nullptr);
+  if (!graph_->GetBlocks().IsEmpty()) {
     HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
     printer.Run();
   }
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 8d6fe04..bc553ae 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -35,7 +35,6 @@
  public:
   HGraphVisualizer(std::ostream* output,
                    HGraph* graph,
-                   const char* string_filter,
                    const CodeGenerator& codegen,
                    const char* method_name);
 
@@ -46,10 +45,6 @@
   HGraph* const graph_;
   const CodeGenerator& codegen_;
 
-  // Is true when `output_` is not null, and the compiled method's name
-  // contains the string_filter given in the constructor.
-  bool is_enabled_;
-
   DISALLOW_COPY_AND_ASSIGN(HGraphVisualizer);
 };
 
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 41e5164..32f6972 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -124,16 +124,18 @@
     resolved_method->GetAccessFlags(),
     nullptr);
 
+  HGraph* callee_graph =
+      new (graph_->GetArena()) HGraph(graph_->GetArena(), graph_->GetCurrentInstructionId());
+
   OptimizingCompilerStats inline_stats;
-  HGraphBuilder builder(graph_->GetArena(),
+  HGraphBuilder builder(callee_graph,
                         &dex_compilation_unit,
                         &outer_compilation_unit_,
                         &outer_dex_file,
                         compiler_driver_,
                         &inline_stats);
-  HGraph* callee_graph = builder.BuildGraph(*code_item, graph_->GetCurrentInstructionId());
 
-  if (callee_graph == nullptr) {
+  if (!builder.BuildGraph(*code_item)) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file)
                    << " could not be built, so cannot be inlined";
     return false;
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index 2ab9b57..eb27965 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -38,10 +38,11 @@
 static void TestCode(const uint16_t* data, const int* expected_order, size_t number_of_blocks) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
 
   graph->TryBuildingSsa();
 
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 92742f9..0558b85 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -31,9 +31,10 @@
 namespace art {
 
 static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) {
-  HGraphBuilder builder(allocator);
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
+  builder.BuildGraph(*item);
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
   RemoveSuspendChecks(graph);
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index f2d49ac..c9be570 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -45,10 +45,11 @@
 static void TestCode(const uint16_t* data, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
   graph->TryBuildingSsa();
   // `Inline` conditions into ifs.
   PrepareForRegisterAllocation(graph).Run();
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 9315d89..d9e082a 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -21,6 +21,8 @@
 
 namespace art {
 
+static const char* kBuilderPassName = "builder";
+static const char* kSsaBuilderPassName = "ssa_builder";
 static const char* kLivenessPassName = "liveness";
 static const char* kRegisterAllocatorPassName = "register";
 static const char* kLoopInvariantCodeMotionPassName = "licm";
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 50d7924..38f7daa 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -19,6 +19,8 @@
 #include <fstream>
 #include <stdint.h>
 
+#include "base/dumpable.h"
+#include "base/timing_logger.h"
 #include "bounds_check_elimination.h"
 #include "builder.h"
 #include "code_generator.h"
@@ -78,6 +80,70 @@
  */
 static const char* kStringFilter = "";
 
+class PassInfoPrinter : public ValueObject {
+ public:
+  PassInfoPrinter(HGraph* graph,
+                  const char* method_name,
+                  const CodeGenerator& codegen,
+                  std::ostream* visualizer_output,
+                  bool timing_logger_enabled,
+                  bool visualizer_enabled)
+      : method_name_(method_name),
+        timing_logger_enabled_(timing_logger_enabled),
+        timing_logger_running_(false),
+        timing_logger_(method_name, true, true),
+        visualizer_enabled_(visualizer_enabled),
+        visualizer_(visualizer_output, graph, codegen, method_name_) {
+    if (strstr(method_name, kStringFilter) == nullptr) {
+      timing_logger_enabled_ = visualizer_enabled_ = false;
+    }
+  }
+
+  void BeforePass(const char* pass_name) {
+    // Dump graph first, then start timer.
+    if (visualizer_enabled_) {
+      visualizer_.DumpGraph(pass_name, /* is_after_pass */ false);
+    }
+    if (timing_logger_enabled_) {
+      DCHECK(!timing_logger_running_);
+      timing_logger_running_ = true;
+      timing_logger_.StartTiming(pass_name);
+    }
+  }
+
+  void AfterPass(const char* pass_name) {
+    // Pause timer first, then dump graph.
+    if (timing_logger_enabled_) {
+      DCHECK(timing_logger_running_);
+      timing_logger_.EndTiming();
+      timing_logger_running_ = false;
+    }
+    if (visualizer_enabled_) {
+      visualizer_.DumpGraph(pass_name, /* is_after_pass */ true);
+    }
+  }
+
+  ~PassInfoPrinter() {
+    if (timing_logger_enabled_) {
+      DCHECK(!timing_logger_running_);
+      LOG(INFO) << "TIMINGS " << method_name_;
+      LOG(INFO) << Dumpable<TimingLogger>(timing_logger_);
+    }
+  }
+
+ private:
+  const char* method_name_;
+
+  bool timing_logger_enabled_;
+  bool timing_logger_running_;
+  TimingLogger timing_logger_;
+
+  bool visualizer_enabled_;
+  HGraphVisualizer visualizer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PassInfoPrinter);
+};
+
 class OptimizingCompiler FINAL : public Compiler {
  public:
   explicit OptimizingCompiler(CompilerDriver* driver);
@@ -123,7 +189,7 @@
                                    CodeGenerator* codegen,
                                    CompilerDriver* driver,
                                    const DexCompilationUnit& dex_compilation_unit,
-                                   const HGraphVisualizer& visualizer) const;
+                                   PassInfoPrinter* pass_info) const;
 
   // Just compile without doing optimizations.
   CompiledMethod* CompileBaseline(CodeGenerator* codegen,
@@ -200,12 +266,12 @@
 
 static void RunOptimizations(HOptimization* optimizations[],
                              size_t length,
-                             const HGraphVisualizer& visualizer) {
+                             PassInfoPrinter* pass_info) {
   for (size_t i = 0; i < length; ++i) {
     HOptimization* optimization = optimizations[i];
-    visualizer.DumpGraph(optimization->GetPassName(), /*is_after=*/false);
+    pass_info->BeforePass(optimization->GetPassName());
     optimization->Run();
-    visualizer.DumpGraph(optimization->GetPassName(), /*is_after=*/true);
+    pass_info->AfterPass(optimization->GetPassName());
     optimization->Check();
   }
 }
@@ -214,7 +280,7 @@
                              CompilerDriver* driver,
                              OptimizingCompilerStats* stats,
                              const DexCompilationUnit& dex_compilation_unit,
-                             const HGraphVisualizer& visualizer) {
+                             PassInfoPrinter* pass_info) {
   SsaRedundantPhiElimination redundant_phi(graph);
   SsaDeadPhiElimination dead_phi(graph);
   HDeadCodeElimination dce(graph);
@@ -250,7 +316,7 @@
     &simplify2
   };
 
-  RunOptimizations(optimizations, arraysize(optimizations), visualizer);
+  RunOptimizations(optimizations, arraysize(optimizations), pass_info);
 }
 
 // The stack map we generate must be 4-byte aligned on ARM. Since existing
@@ -269,18 +335,20 @@
                                                      CodeGenerator* codegen,
                                                      CompilerDriver* compiler_driver,
                                                      const DexCompilationUnit& dex_compilation_unit,
-                                                     const HGraphVisualizer& visualizer) const {
+                                                     PassInfoPrinter* pass_info) const {
   RunOptimizations(
-      graph, compiler_driver, &compilation_stats_, dex_compilation_unit, visualizer);
+      graph, compiler_driver, &compilation_stats_, dex_compilation_unit, pass_info);
 
+  pass_info->BeforePass(kLivenessPassName);
   PrepareForRegisterAllocation(graph).Run();
   SsaLivenessAnalysis liveness(*graph, codegen);
   liveness.Analyze();
-  visualizer.DumpGraph(kLivenessPassName);
+  pass_info->AfterPass(kLivenessPassName);
 
+  pass_info->BeforePass(kRegisterAllocatorPassName);
   RegisterAllocator register_allocator(graph->GetArena(), codegen, liveness);
   register_allocator.AllocateRegisters();
-  visualizer.DumpGraph(kRegisterAllocatorPassName);
+  pass_info->AfterPass(kRegisterAllocatorPassName);
 
   CodeVectorAllocator allocator;
   codegen->CompileOptimized(&allocator);
@@ -339,6 +407,7 @@
                                             jobject class_loader,
                                             const DexFile& dex_file) const {
   UNUSED(invoke_type);
+  std::string method_name = PrettyMethod(method_idx, dex_file);
   compilation_stats_.RecordStat(MethodCompilationStat::kAttemptCompilation);
   CompilerDriver* compiler_driver = GetCompilerDriver();
   InstructionSet instruction_set = compiler_driver->GetInstructionSet();
@@ -364,29 +433,15 @@
     class_def_idx, method_idx, access_flags,
     compiler_driver->GetVerifiedMethod(&dex_file, method_idx));
 
-  std::string method_name = PrettyMethod(method_idx, dex_file);
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  HGraph* graph = new (&arena) HGraph(&arena);
 
   // For testing purposes, we put a special marker on method names that should be compiled
   // with this compiler. This makes sure we're not regressing.
   bool shouldCompile = method_name.find("$opt$") != std::string::npos;
   bool shouldOptimize = method_name.find("$opt$reg$") != std::string::npos;
 
-  ArenaPool pool;
-  ArenaAllocator arena(&pool);
-  HGraphBuilder builder(&arena,
-                        &dex_compilation_unit,
-                        &dex_compilation_unit,
-                        &dex_file,
-                        compiler_driver,
-                        &compilation_stats_);
-
-  VLOG(compiler) << "Building " << PrettyMethod(method_idx, dex_file);
-  HGraph* graph = builder.BuildGraph(*code_item);
-  if (graph == nullptr) {
-    CHECK(!shouldCompile) << "Could not build graph in optimizing compiler";
-    return nullptr;
-  }
-
   std::unique_ptr<CodeGenerator> codegen(
       CodeGenerator::Create(graph,
                             instruction_set,
@@ -398,29 +453,53 @@
     return nullptr;
   }
 
-  HGraphVisualizer visualizer(
-      visualizer_output_.get(), graph, kStringFilter, *codegen.get(), method_name.c_str());
-  visualizer.DumpGraph("builder");
+  PassInfoPrinter pass_info(graph,
+                            method_name.c_str(),
+                            *codegen.get(),
+                            visualizer_output_.get(),
+                            GetCompilerDriver()->GetDumpPasses(),
+                            !GetCompilerDriver()->GetDumpCfgFileName().empty());
+
+  HGraphBuilder builder(graph,
+                        &dex_compilation_unit,
+                        &dex_compilation_unit,
+                        &dex_file,
+                        compiler_driver,
+                        &compilation_stats_);
+
+  VLOG(compiler) << "Building " << method_name;
+
+  pass_info.BeforePass(kBuilderPassName);
+  if (!builder.BuildGraph(*code_item)) {
+    CHECK(!shouldCompile) << "Could not build graph in optimizing compiler";
+    return nullptr;
+  }
+  pass_info.AfterPass(kBuilderPassName);
 
   bool can_optimize = CanOptimize(*code_item);
   bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set);
-  CompiledMethod* result = nullptr;
   if (run_optimizations_ && can_optimize && can_allocate_registers) {
-    VLOG(compiler) << "Optimizing " << PrettyMethod(method_idx, dex_file);
+    VLOG(compiler) << "Optimizing " << method_name;
+
+    pass_info.BeforePass(kSsaBuilderPassName);
     if (!graph->TryBuildingSsa()) {
-      LOG(INFO) << "Skipping compilation of "
-                << PrettyMethod(method_idx, dex_file)
-                << ": it contains a non natural loop";
       // We could not transform the graph to SSA, bailout.
+      LOG(INFO) << "Skipping compilation of " << method_name << ": it contains a non natural loop";
       compilation_stats_.RecordStat(MethodCompilationStat::kNotCompiledCannotBuildSSA);
-    } else {
-      result = CompileOptimized(graph, codegen.get(), compiler_driver, dex_compilation_unit, visualizer);
+      return nullptr;
     }
+    pass_info.AfterPass(kSsaBuilderPassName);
+
+    return CompileOptimized(graph,
+                            codegen.get(),
+                            compiler_driver,
+                            dex_compilation_unit,
+                            &pass_info);
   } else if (shouldOptimize && RegisterAllocator::Supports(instruction_set)) {
     LOG(FATAL) << "Could not allocate registers in optimizing compiler";
     UNREACHABLE();
   } else {
-    VLOG(compiler) << "Compile baseline " << PrettyMethod(method_idx, dex_file);
+    VLOG(compiler) << "Compile baseline " << method_name;
 
     if (!run_optimizations_) {
       compilation_stats_.RecordStat(MethodCompilationStat::kNotOptimizedDisabled);
@@ -430,9 +509,8 @@
       compilation_stats_.RecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator);
     }
 
-    result = CompileBaseline(codegen.get(), compiler_driver, dex_compilation_unit);
+    return CompileBaseline(codegen.get(), compiler_driver, dex_compilation_unit);
   }
-  return result;
 }
 
 Compiler* CreateOptimizingCompiler(CompilerDriver* driver) {
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 29d47e1..6b23692 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -76,11 +76,12 @@
 inline HGraph* CreateCFG(ArenaAllocator* allocator,
                          const uint16_t* data,
                          Primitive::Type return_type = Primitive::kPrimInt) {
-  HGraphBuilder builder(allocator, return_type);
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HGraphBuilder builder(graph, return_type);
   const DexFile::CodeItem* item =
     reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  return graph;
+  bool graph_built = builder.BuildGraph(*item);
+  return graph_built ? graph : nullptr;
 }
 
 // Naive string diff data type.
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index a231a72..9cf8235 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -30,10 +30,11 @@
 static void TestCode(const uint16_t* data, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
   StringPrettyPrinter printer(graph);
   printer.VisitInsertionOrder();
   ASSERT_STREQ(expected, printer.str().c_str());
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 0e49bf2..0cc00c0 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -37,9 +37,10 @@
 static bool Check(const uint16_t* data) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
+  builder.BuildGraph(*item);
   graph->TryBuildingSsa();
   x86::CodeGeneratorX86 codegen(graph, CompilerOptions());
   SsaLivenessAnalysis liveness(*graph, &codegen);
@@ -249,9 +250,10 @@
 }
 
 static HGraph* BuildSSAGraph(const uint16_t* data, ArenaAllocator* allocator) {
-  HGraphBuilder builder(allocator);
+  HGraph* graph = new (allocator) HGraph(allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
+  builder.BuildGraph(*item);
   graph->TryBuildingSsa();
   return graph;
 }
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 6b6bf05..7e90b37 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -78,10 +78,11 @@
 static void TestCode(const uint16_t* data, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
 
   graph->BuildDominatorTree();
   // Suspend checks implementation may change in the future, and this test relies
diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc
index 2e48ee8..a5a0eb2 100644
--- a/compiler/optimizing/suspend_check_test.cc
+++ b/compiler/optimizing/suspend_check_test.cc
@@ -30,10 +30,11 @@
 static void TestCode(const uint16_t* data) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraphBuilder builder(&allocator);
+  HGraph* graph = new (&allocator) HGraph(&allocator);
+  HGraphBuilder builder(graph);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  HGraph* graph = builder.BuildGraph(*item);
-  ASSERT_NE(graph, nullptr);
+  bool graph_built = builder.BuildGraph(*item);
+  ASSERT_TRUE(graph_built);
 
   HBasicBlock* first_block = graph->GetEntryBlock()->GetSuccessors().Get(0);
   HInstruction* first_instruction = first_block->GetFirstInstruction();