am 64d8f18c: Merge "Support inline dex data"

* commit '64d8f18c94b23cb4ff908304aef4d9f3f5a85f39':
  Support inline dex data
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 038957e..49aba4d 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -495,7 +495,7 @@
 
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files,
-                                TimingLogger& timings) {
+                                base::TimingLogger& timings) {
   DCHECK(!Runtime::Current()->IsStarted());
   UniquePtr<ThreadPool> thread_pool(new ThreadPool(thread_count_));
   PreCompile(class_loader, dex_files, *thread_pool.get(), timings);
@@ -528,7 +528,7 @@
   return klass->IsVerified();
 }
 
-void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, TimingLogger& timings) {
+void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings) {
   DCHECK(!Runtime::Current()->IsStarted());
   Thread* self = Thread::Current();
   jobject jclass_loader;
@@ -572,7 +572,7 @@
 }
 
 void CompilerDriver::Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                             ThreadPool& thread_pool, TimingLogger& timings) {
+                             ThreadPool& thread_pool, base::TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -581,7 +581,7 @@
 }
 
 void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                                ThreadPool& thread_pool, TimingLogger& timings) {
+                                ThreadPool& thread_pool, base::TimingLogger& timings) {
   LoadImageClasses(timings);
 
   Resolve(class_loader, dex_files, thread_pool, timings);
@@ -666,12 +666,13 @@
 }
 
 // Make a list of descriptors for classes to include in the image
-void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+void CompilerDriver::LoadImageClasses(base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_) {
   if (image_classes_.get() == NULL) {
     return;
   }
 
+  timings.NewSplit("LoadImageClasses");
   // Make a first class to load all classes explicitly listed in the file
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
@@ -726,7 +727,6 @@
   class_linker->VisitClasses(RecordImageClassesVisitor, image_classes_.get());
 
   CHECK_NE(image_classes_->size(), 0U);
-  timings.AddSplit("LoadImageClasses");
 }
 
 static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::DescriptorSet* image_classes)
@@ -758,11 +758,13 @@
   MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
 }
 
-void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) {
   if (image_classes_.get() == NULL) {
     return;
   }
 
+  timings.NewSplit("UpdateImageClasses");
+
   // Update image_classes_ with classes for objects created by <clinit> methods.
   Thread* self = Thread::Current();
   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
@@ -772,7 +774,6 @@
   heap->FlushAllocStack();
   heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
   self->EndAssertNoThreadSuspension(old_cause);
-  timings.AddSplit("UpdateImageClasses");
 }
 
 void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
@@ -1551,22 +1552,22 @@
 }
 
 void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_file,
-                                    ThreadPool& thread_pool, TimingLogger& timings) {
+                                    ThreadPool& thread_pool, base::TimingLogger& timings) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   // TODO: we could resolve strings here, although the string table is largely filled with class
   //       and method names.
 
+  timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str()));
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
-  timings.AddSplit("Resolve " + dex_file.GetLocation() + " Types");
 
+  timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " MethodsAndFields").c_str()));
   context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
-  timings.AddSplit("Resolve " + dex_file.GetLocation() + " MethodsAndFields");
 }
 
 void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                            ThreadPool& thread_pool, TimingLogger& timings) {
+                            ThreadPool& thread_pool, base::TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -1620,11 +1621,11 @@
 }
 
 void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
-                                   ThreadPool& thread_pool, TimingLogger& timings) {
+                                   ThreadPool& thread_pool, base::TimingLogger& timings) {
+  timings.NewSplit(strdup(("Verify " + dex_file.GetLocation()).c_str()));
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
-  timings.AddSplit("Verify " + dex_file.GetLocation());
 }
 
 static const char* class_initializer_black_list[] = {
@@ -2116,7 +2117,8 @@
 }
 
 void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
-                                       ThreadPool& thread_pool, TimingLogger& timings) {
+                                       ThreadPool& thread_pool, base::TimingLogger& timings) {
+  timings.NewSplit(strdup(("InitializeNoClinit " + dex_file.GetLocation()).c_str()));
 #ifndef NDEBUG
   for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
     const char* descriptor = class_initializer_black_list[i];
@@ -2126,12 +2128,11 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count_);
-  timings.AddSplit("InitializeNoClinit " + dex_file.GetLocation());
 }
 
 void CompilerDriver::InitializeClasses(jobject class_loader,
                                        const std::vector<const DexFile*>& dex_files,
-                                       ThreadPool& thread_pool, TimingLogger& timings) {
+                                       ThreadPool& thread_pool, base::TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -2140,7 +2141,7 @@
 }
 
 void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                       ThreadPool& thread_pool, TimingLogger& timings) {
+                       ThreadPool& thread_pool, base::TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
@@ -2220,10 +2221,10 @@
 }
 
 void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file,
-                                    ThreadPool& thread_pool, TimingLogger& timings) {
+                                    ThreadPool& thread_pool, base::TimingLogger& timings) {
+  timings.NewSplit(strdup(("Compile " + dex_file.GetLocation()).c_str()));
   ParallelCompilationManager context(NULL, class_loader, this, &dex_file, thread_pool);
   context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_);
-  timings.AddSplit("Compile " + dex_file.GetLocation());
 }
 
 void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
@@ -2239,18 +2240,8 @@
     CHECK(compiled_method != NULL);
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
-    // In small mode we only compile image classes.
-    bool dont_compile = (Runtime::Current()->IsSmallMode() &&
-                         ((image_classes_.get() == NULL) || (image_classes_->size() == 0)));
-
-    // Don't compile class initializers, ever.
-    if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
-      dont_compile = true;
-    } else if (code_item->insns_size_in_code_units_ < Runtime::Current()->GetSmallModeMethodDexSizeLimit()) {
-    // Do compile small methods.
-      dont_compile = false;
-    }
-    if (!dont_compile) {
+    bool compile = verifier::MethodVerifier::IsCandidateForCompilation(code_item, access_flags);
+    if (compile) {
       CompilerFn compiler = compiler_;
 #ifdef ART_SEA_IR_MODE
       bool use_sea = Runtime::Current()->IsSeaIRMode();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index f3f72dd..a7a47ed 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -78,11 +78,11 @@
   ~CompilerDriver();
 
   void CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                  TimingLogger& timings)
+                  base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Compile a single Method
-  void CompileOne(const mirror::AbstractMethod* method, TimingLogger& timings)
+  void CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   InstructionSet GetInstructionSet() const {
@@ -284,42 +284,42 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                  ThreadPool& thread_pool, TimingLogger& timings)
+                  ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  void LoadImageClasses(TimingLogger& timings);
+  void LoadImageClasses(base::TimingLogger& timings);
 
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
   // ordering semantics.
   void Resolve(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-               ThreadPool& thread_pool, TimingLogger& timings)
+               ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void ResolveDexFile(jobject class_loader, const DexFile& dex_file,
-                      ThreadPool& thread_pool, TimingLogger& timings)
+                      ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   void Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-              ThreadPool& thread_pool, TimingLogger& timings);
+              ThreadPool& thread_pool, base::TimingLogger& timings);
   void VerifyDexFile(jobject class_loader, const DexFile& dex_file,
-                     ThreadPool& thread_pool, TimingLogger& timings)
+                     ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   void InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-                         ThreadPool& thread_pool, TimingLogger& timings)
+                         ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void InitializeClasses(jobject class_loader, const DexFile& dex_file,
-                         ThreadPool& thread_pool, TimingLogger& timings)
+                         ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
 
-  void UpdateImageClasses(TimingLogger& timings);
+  void UpdateImageClasses(base::TimingLogger& timings);
   static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
-               ThreadPool& thread_pool, TimingLogger& timings);
+               ThreadPool& thread_pool, base::TimingLogger& timings);
   void CompileDexFile(jobject class_loader, const DexFile& dex_file,
-                      ThreadPool& thread_pool, TimingLogger& timings)
+                      ThreadPool& thread_pool, base::TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
                      InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx,
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 78cacaf..8ee9cf6 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -36,7 +36,8 @@
 class CompilerDriverTest : public CommonTest {
  protected:
   void CompileAll(jobject class_loader) LOCKS_EXCLUDED(Locks::mutator_lock_) {
-    TimingLogger timings("CompilerDriverTest::CompileAll", false);
+    base::TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
+    timings.StartSplit("CompileAll");
     compiler_driver_->CompileAll(class_loader,
                                  Runtime::Current()->GetCompileTimeClassPath(class_loader),
                                  timings);
diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc
index 8fc1cf8..ebc767c 100644
--- a/compiler/sea_ir/frontend.cc
+++ b/compiler/sea_ir/frontend.cc
@@ -40,7 +40,7 @@
   // NOTE: Instead of keeping the convention from the Dalvik frontend.cc
   //       and silencing the cpplint.py warning, I just corrected the formatting.
   VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
-  sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph();
+  sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph(dex_file);
   sg->CompileMethod(code_item, class_def_idx, method_idx, dex_file);
   sg->DumpSea("/tmp/temp.dot");
   CHECK(0 && "No SEA compiled function exists yet.");
diff --git a/compiler/sea_ir/instruction_nodes.h b/compiler/sea_ir/instruction_nodes.h
index 5c9cfe1..103c16f 100644
--- a/compiler/sea_ir/instruction_nodes.h
+++ b/compiler/sea_ir/instruction_nodes.h
@@ -50,7 +50,7 @@
   // Returns the set of register numbers that are used by the instruction.
   virtual std::vector<int> GetUses();
   // Appends to @result the .dot string representation of the instruction.
-  virtual void ToDot(std::string& result) const;
+  virtual void ToDot(std::string& result, const art::DexFile& dex_file) const;
   // Mark the current instruction as a downward exposed definition.
   void MarkAsDEDef();
   // Rename the use of @reg_no to refer to the instruction @definition,
@@ -126,7 +126,7 @@
     return value_;
   }
 
-  void ToDot(std::string& result) const {
+  void ToDot(std::string& result, const art::DexFile& dex_file) const {
     std::ostringstream sstream;
     sstream << GetConstValue();
     const std::string value_as_string(sstream.str());
@@ -140,11 +140,9 @@
     for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin();
         def_it != definition_edges_.end(); def_it++) {
       if (NULL != def_it->second) {
-        result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\"";
-        std::stringstream ss;
-        ss << def_it->first;
-        result.append(ss.str());
-        result += "\"] ;  // ssa edge\n";
+        result += def_it->second->StringId() + " -> " + StringId() +"[color=gray,label=\"";
+        result += art::StringPrintf("vR = %d", def_it->first);
+        result += "\"] ; // ssa edge\n";
       }
     }
   }
diff --git a/compiler/sea_ir/sea.cc b/compiler/sea_ir/sea.cc
index 3488afd..17ee2dd 100644
--- a/compiler/sea_ir/sea.cc
+++ b/compiler/sea_ir/sea.cc
@@ -27,7 +27,6 @@
 
 namespace sea_ir {
 
-SeaGraph SeaGraph::graph_;
 int SeaNode::current_max_node_id_ = 0;
 
 void IRVisitor::Traverse(Region* region) {
@@ -51,16 +50,16 @@
   }
 }
 
-SeaGraph* SeaGraph::GetCurrentGraph() {
-  return &sea_ir::SeaGraph::graph_;
+SeaGraph* SeaGraph::GetCurrentGraph(const art::DexFile& dex_file) {
+  return new SeaGraph(dex_file);
 }
 
 void SeaGraph::DumpSea(std::string filename) const {
   LOG(INFO) << "Starting to write SEA string to file.";
   std::string result;
-  result += "digraph seaOfNodes {\n";
+  result += "digraph seaOfNodes {\ncompound=true\n";
   for (std::vector<Region*>::const_iterator cit = regions_.begin(); cit != regions_.end(); cit++) {
-    (*cit)->ToDot(result);
+    (*cit)->ToDot(result, dex_file_);
   }
   result += "}\n";
   art::File* file = art::OS::OpenFile(filename.c_str(), true, true);
@@ -490,53 +489,44 @@
   return NULL;
 }
 
-void Region::ToDot(std::string& result) const {
-  result += "\n// Region: \n" + StringId() + " [label=\"region " + StringId() + "(rpo=";
+void Region::ToDot(std::string& result, const art::DexFile& dex_file) const {
+  result += "\n// Region: \nsubgraph " + StringId() + " { label=\"region " + StringId() + "(rpo=";
   result += art::StringPrintf("%d", rpo_number_);
   if (NULL != GetIDominator()) {
     result += " dom=" + GetIDominator()->StringId();
   }
-  result += ")\"];\n";
+  result += ")\";\n";
+
+  for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin();
+        cit != phi_instructions_.end(); cit++) {
+    result += (*cit)->StringId() +";\n";
+  }
+
+  for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin();
+        cit != instructions_.end(); cit++) {
+      result += (*cit)->StringId() +";\n";
+    }
+
+  result += "} // End Region.\n";
 
   // Save phi-nodes.
   for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin();
       cit != phi_instructions_.end(); cit++) {
-    (*cit)->ToDot(result);
-    result += StringId() + " -> " + (*cit)->StringId() + ";  // phi-function \n";
+    (*cit)->ToDot(result, dex_file);
   }
 
   // Save instruction nodes.
   for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin();
       cit != instructions_.end(); cit++) {
-    (*cit)->ToDot(result);
-    result += StringId() + " -> " + (*cit)->StringId() + ";  // region -> instruction \n";
+    (*cit)->ToDot(result, dex_file);
   }
 
   for (std::vector<Region*>::const_iterator cit = successors_.begin(); cit != successors_.end();
       cit++) {
     DCHECK(NULL != *cit) << "Null successor found for SeaNode" << GetLastChild()->StringId() << ".";
-    result += GetLastChild()->StringId() + " -> " + (*cit)->StringId() + ";\n\n";
+    result += GetLastChild()->StringId() + " -> " + (*cit)->GetLastChild()->StringId() +
+         "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + StringId() + "];\n\n";
   }
-  // Save reaching definitions.
-  for (std::map<int, std::set<sea_ir::InstructionNode*>* >::const_iterator cit =
-      reaching_defs_.begin();
-      cit != reaching_defs_.end(); cit++) {
-    for (std::set<sea_ir::InstructionNode*>::const_iterator
-        reaching_set_it = (*cit).second->begin();
-        reaching_set_it != (*cit).second->end();
-        reaching_set_it++) {
-      result += (*reaching_set_it)->StringId() +
-         " -> " + StringId() +
-         " [style=dotted];  // Reaching def.\n";
-    }
-  }
-  // Save dominance frontier.
-  for (std::set<Region*>::const_iterator cit = df_.begin(); cit != df_.end(); cit++) {
-    result += StringId() +
-        " -> " + (*cit)->StringId() +
-        " [color=gray];  // Dominance frontier.\n";
-  }
-  result += "// End Region.\n";
 }
 
 void Region::ComputeDownExposedDefs() {
@@ -698,9 +688,9 @@
   return sea_instructions;
 }
 
-void InstructionNode::ToDot(std::string& result) const {
+void InstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const {
   result += "// Instruction ("+StringId()+"): \n" + StringId() +
-      " [label=\"" + instruction_->DumpString(NULL) + "\"";
+      " [label=\"" + instruction_->DumpString(&dex_file) + "\"";
   if (de_def_) {
     result += "style=bold";
   }
@@ -709,9 +699,9 @@
   for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin();
       def_it != definition_edges_.end(); def_it++) {
     if (NULL != def_it->second) {
-      result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\"";
-      result += art::StringPrintf("%d", def_it->first);
-      result += "\"] ;  // ssa edge\n";
+      result += def_it->second->StringId() + " -> " + StringId() +"[color=gray,label=\"";
+      result += art::StringPrintf("vR = %d", def_it->first);
+      result += "\"] ; // ssa edge\n";
     }
   }
 }
@@ -756,7 +746,7 @@
   return uses;
 }
 
-void PhiInstructionNode::ToDot(std::string& result) const {
+void PhiInstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const {
   result += "// PhiInstruction: \n" + StringId() +
       " [label=\"" + "PHI(";
   result += art::StringPrintf("%d", register_no_);
@@ -768,7 +758,7 @@
     std::vector<InstructionNode*>* defs_from_pred = *pred_it;
     for (std::vector<InstructionNode* >::const_iterator def_it = defs_from_pred->begin();
         def_it != defs_from_pred->end(); def_it++) {
-        result += (*def_it)->StringId() + " -> " + StringId() +"[color=red,label=\"vR = ";
+        result += (*def_it)->StringId() + " -> " + StringId() +"[color=gray,label=\"vR = ";
         result += art::StringPrintf("%d", GetRegisterNumber());
         result += "\"] ;  // phi-ssa edge\n";
     }
diff --git a/compiler/sea_ir/sea.h b/compiler/sea_ir/sea.h
index 25ab1fe..c64703a 100644
--- a/compiler/sea_ir/sea.h
+++ b/compiler/sea_ir/sea.h
@@ -49,7 +49,7 @@
   explicit SignatureNode(unsigned int parameter_register):InstructionNode(NULL),
     parameter_register_(parameter_register) { }
 
-  void ToDot(std::string& result) const {
+  void ToDot(std::string& result, const art::DexFile& dex_file) const {
     result += StringId() +" [label=\"signature:";
     result += art::StringPrintf("r%d", GetResultRegister());
     result += "\"] // signature node\n";
@@ -77,7 +77,7 @@
   explicit PhiInstructionNode(int register_no):
     InstructionNode(NULL), register_no_(register_no), definition_edges_() {}
   // Appends to @result the .dot string representation of the instruction.
-  void ToDot(std::string& result) const;
+  void ToDot(std::string& result, const art::DexFile& dex_file) const;
   // Returns the register on which this phi-function is used.
   int GetRegisterNumber() const {
     return register_no_;
@@ -125,7 +125,9 @@
  public:
   explicit Region():
     SeaNode(), successors_(), predecessors_(), reaching_defs_size_(0),
-    rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {}
+    rpo_number_(NOT_VISITED), idom_(NULL), idominated_set_(), df_(), phi_set_() {
+    string_id_ = "cluster_" + string_id_;
+  }
   // Adds @instruction as an instruction node child in the current region.
   void AddChild(sea_ir::InstructionNode* instruction);
   // Returns the last instruction node child of the current region.
@@ -138,7 +140,7 @@
   // Appends to @result a dot language formatted string representing the node and
   //    (by convention) outgoing edges, so that the composition of theToDot() of all nodes
   //    builds a complete dot graph (without prolog and epilog though).
-  virtual void ToDot(std::string& result) const;
+  virtual void ToDot(std::string& result, const art::DexFile& dex_file) const;
   // Computes Downward Exposed Definitions for the current node.
   void ComputeDownExposedDefs();
   const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const;
@@ -242,7 +244,7 @@
 // and acts as starting point for visitors (ex: during code generation).
 class SeaGraph: IVisitable {
  public:
-  static SeaGraph* GetCurrentGraph();
+  static SeaGraph* GetCurrentGraph(const art::DexFile&);
 
   void CompileMethod(const art::DexFile::CodeItem* code_item,
       uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file);
@@ -264,7 +266,8 @@
   uint32_t method_idx_;
 
  private:
-  SeaGraph(): class_def_idx_(0), method_idx_(0), regions_(), parameters_() {
+  explicit SeaGraph(const art::DexFile& df):
+    class_def_idx_(0), method_idx_(0), regions_(), parameters_(), dex_file_(df) {
   }
   // Registers @childReg as a region belonging to the SeaGraph instance.
   void AddRegion(Region* childReg);
@@ -319,6 +322,7 @@
   static SeaGraph graph_;
   std::vector<Region*> regions_;
   std::vector<SignatureNode*> parameters_;
+  const art::DexFile& dex_file_;
 };
 }  // namespace sea_ir
 #endif  // ART_COMPILER_SEA_IR_SEA_H_
diff --git a/compiler/sea_ir/sea_node.h b/compiler/sea_ir/sea_node.h
index 5d28f8a..c13e5d6 100644
--- a/compiler/sea_ir/sea_node.h
+++ b/compiler/sea_ir/sea_node.h
@@ -30,7 +30,7 @@
 };
 
 // This abstract class provides the essential services that
-// we want each SEA IR element should have.
+// we want each SEA IR element to have.
 // At the moment, these are:
 // - an id and corresponding string representation.
 // - a .dot graph language representation for .dot output.
@@ -42,6 +42,7 @@
   explicit SeaNode():id_(GetNewId()), string_id_() {
     string_id_ = art::StringPrintf("%d", id_);
   }
+
   // Adds CFG predecessors and successors to each block.
   void AddSuccessor(Region* successor);
   void AddPredecessor(Region* predecesor);
@@ -58,7 +59,7 @@
   // Appends to @result a dot language formatted string representing the node and
   //    (by convention) outgoing edges, so that the composition of theToDot() of all nodes
   //    builds a complete dot graph, but without prolog ("digraph {") and epilog ("}").
-  virtual void ToDot(std::string& result) const = 0;
+  virtual void ToDot(std::string& result, const art::DexFile& dex_file) const = 0;
 
   virtual ~SeaNode() { }
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index f79ddb1..c8c4347 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -230,7 +230,7 @@
                                       bool image,
                                       UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
                                       bool dump_stats,
-                                      TimingLogger& timings)
+                                      base::TimingLogger& timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // SirtRef and ClassLoader creation needs to come after Runtime::Create
     jobject class_loader = NULL;
@@ -263,11 +263,11 @@
 
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
-    timings.AddSplit("dex2oat Setup");
     driver->CompileAll(class_loader, dex_files, timings);
 
     Thread::Current()->TransitionFromSuspendedToRunnable();
 
+    timings.NewSplit("dex2oat OatWriter");
     std::string image_file_location;
     uint32_t image_file_location_oat_checksum = 0;
     uint32_t image_file_location_oat_data_begin = 0;
@@ -287,13 +287,11 @@
                          image_file_location_oat_data_begin,
                          image_file_location,
                          driver.get());
-    timings.AddSplit("dex2oat OatWriter");
 
     if (!driver->WriteElf(android_root, is_host, dex_files, oat_writer, oat_file)) {
       LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
       return NULL;
     }
-    timings.AddSplit("dex2oat ElfWriter");
 
     return driver.release();
   }
@@ -563,7 +561,7 @@
 const unsigned int WatchDog::kWatchDogTimeoutSeconds;
 
 static int dex2oat(int argc, char** argv) {
-  TimingLogger timings("compiler", false);
+  base::TimingLogger timings("compiler", false, false);
 
   InitLogging(argv);
 
@@ -928,6 +926,7 @@
     }
   }
 
+  timings.StartSplit("dex2oat Setup");
   UniquePtr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
                                                                   host_prefix.get(),
                                                                   android_root,
@@ -998,13 +997,13 @@
   // Elf32_Phdr.p_vaddr values by the desired base address.
   //
   if (image) {
+    timings.NewSplit("dex2oat ImageWriter");
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
     bool image_creation_success = dex2oat->CreateImageFile(image_filename,
                                                            image_base,
                                                            oat_unstripped,
                                                            oat_location,
                                                            *compiler.get());
-    timings.AddSplit("dex2oat ImageWriter");
     Thread::Current()->TransitionFromSuspendedToRunnable();
     if (!image_creation_success) {
       return EXIT_FAILURE;
@@ -1014,7 +1013,7 @@
 
   if (is_host) {
     if (dump_timings && timings.GetTotalNs() > MsToNs(1000)) {
-      LOG(INFO) << Dumpable<TimingLogger>(timings);
+      LOG(INFO) << Dumpable<base::TimingLogger>(timings);
     }
     return EXIT_SUCCESS;
   }
@@ -1022,6 +1021,7 @@
   // If we don't want to strip in place, copy from unstripped location to stripped location.
   // We need to strip after image creation because FixupElf needs to use .strtab.
   if (oat_unstripped != oat_stripped) {
+    timings.NewSplit("dex2oat OatFile copy");
     oat_file.reset();
     UniquePtr<File> in(OS::OpenFile(oat_unstripped.c_str(), false));
     UniquePtr<File> out(OS::OpenFile(oat_stripped.c_str(), true));
@@ -1036,23 +1036,25 @@
       CHECK(write_ok);
     }
     oat_file.reset(out.release());
-    timings.AddSplit("dex2oat OatFile copy");
     LOG(INFO) << "Oat file copied successfully (stripped): " << oat_stripped;
   }
 
 #if ART_USE_PORTABLE_COMPILER  // We currently only generate symbols on Portable
+  timings.NewSplit("dex2oat ElfStripper");
   // Strip unneeded sections for target
   off_t seek_actual = lseek(oat_file->Fd(), 0, SEEK_SET);
   CHECK_EQ(0, seek_actual);
   ElfStripper::Strip(oat_file.get());
-  timings.AddSplit("dex2oat ElfStripper");
+
 
   // We wrote the oat file successfully, and want to keep it.
   LOG(INFO) << "Oat file written successfully (stripped): " << oat_location;
 #endif  // ART_USE_PORTABLE_COMPILER
 
+  timings.EndSplit();
+
   if (dump_timings && timings.GetTotalNs() > MsToNs(1000)) {
-    LOG(INFO) << Dumpable<TimingLogger>(timings);
+    LOG(INFO) << Dumpable<base::TimingLogger>(timings);
   }
   return EXIT_SUCCESS;
 }
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index dea52a6..b924798 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -53,7 +53,7 @@
 class ScopedContentionRecorder;
 class Thread;
 
-const bool kDebugLocking = kIsDebugBuild;
+const bool kDebugLocking = true || kIsDebugBuild;
 
 // Base class for all Mutex implementations
 class BaseMutex {
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index bf6fd17..dfb0220 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
+
+#define ATRACE_TAG ATRACE_TAG_DALVIK
+#include <stdio.h>
+#include <cutils/trace.h>
+
 #include "timing_logger.h"
 
 #include "base/logging.h"
@@ -26,49 +31,6 @@
 
 namespace art {
 
-void TimingLogger::Reset() {
-  times_.clear();
-  labels_.clear();
-  AddSplit("");
-}
-
-TimingLogger::TimingLogger(const std::string &name, bool precise)
-    : name_(name),
-      precise_(precise) {
-  AddSplit("");
-}
-
-void TimingLogger::AddSplit(const std::string &label) {
-  times_.push_back(NanoTime());
-  labels_.push_back(label);
-}
-
-uint64_t TimingLogger::GetTotalNs() const {
-  return times_.back() - times_.front();
-}
-
-void TimingLogger::Dump(std::ostream &os) const {
-  uint64_t largest_time = 0;
-  os << name_ << ": begin\n";
-  for (size_t i = 1; i < times_.size(); ++i) {
-    uint64_t delta_time = times_[i] - times_[i - 1];
-    largest_time = std::max(largest_time, delta_time);
-  }
-  // Compute which type of unit we will use for printing the timings.
-  TimeUnit tu = GetAppropriateTimeUnit(largest_time);
-  uint64_t divisor = GetNsToTimeUnitDivisor(tu);
-  for (size_t i = 1; i < times_.size(); ++i) {
-    uint64_t delta_time = times_[i] - times_[i - 1];
-    if (!precise_ && divisor >= 1000) {
-      // Make the fraction 0.
-      delta_time -= delta_time % (divisor / 1000);
-    }
-    os << name_ << ": " << std::setw(8) << FormatDuration(delta_time, tu) << " "
-       << labels_[i] << "\n";
-  }
-  os << name_ << ": end, " << NsToMs(GetTotalNs()) << " ms\n";
-}
-
 CumulativeLogger::CumulativeLogger(const std::string& name)
     : name_(name),
       lock_name_("CumulativeLoggerLock" + name),
@@ -112,17 +74,8 @@
   return total;
 }
 
-void CumulativeLogger::AddLogger(const TimingLogger &logger) {
-  MutexLock mu(Thread::Current(), lock_);
-  DCHECK_EQ(logger.times_.size(), logger.labels_.size());
-  for (size_t i = 1; i < logger.times_.size(); ++i) {
-    const uint64_t delta_time = logger.times_[i] - logger.times_[i - 1];
-    const std::string &label = logger.labels_[i];
-    AddPair(label, delta_time);
-  }
-}
 
-void CumulativeLogger::AddNewLogger(const base::NewTimingLogger &logger) {
+void CumulativeLogger::AddLogger(const base::TimingLogger &logger) {
   MutexLock mu(Thread::Current(), lock_);
   const std::vector<std::pair<uint64_t, const char*> >& splits = logger.GetSplits();
   typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
@@ -183,51 +136,55 @@
 
 namespace base {
 
-NewTimingLogger::NewTimingLogger(const char* name, bool precise, bool verbose)
+TimingLogger::TimingLogger(const char* name, bool precise, bool verbose)
     : name_(name), precise_(precise), verbose_(verbose),
       current_split_(NULL), current_split_start_ns_(0) {
 }
 
-void NewTimingLogger::Reset() {
+void TimingLogger::Reset() {
   current_split_ = NULL;
   current_split_start_ns_ = 0;
   splits_.clear();
 }
 
-void NewTimingLogger::StartSplit(const char* new_split_label) {
+void TimingLogger::StartSplit(const char* new_split_label) {
   DCHECK(current_split_ == NULL);
   if (verbose_) {
     LOG(INFO) << "Begin: " << new_split_label;
   }
   current_split_ = new_split_label;
+  ATRACE_BEGIN(current_split_);
   current_split_start_ns_ = NanoTime();
 }
 
 // Ends the current split and starts the one given by the label.
-void NewTimingLogger::NewSplit(const char* new_split_label) {
+void TimingLogger::NewSplit(const char* new_split_label) {
   DCHECK(current_split_ != NULL);
   uint64_t current_time = NanoTime();
   uint64_t split_time = current_time - current_split_start_ns_;
+  ATRACE_END();
   splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
   if (verbose_) {
     LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time) << "\n"
         << "Begin: " << new_split_label;
   }
   current_split_ = new_split_label;
+  ATRACE_BEGIN(current_split_);
   current_split_start_ns_ = current_time;
 }
 
-void NewTimingLogger::EndSplit() {
+void TimingLogger::EndSplit() {
   DCHECK(current_split_ != NULL);
   uint64_t current_time = NanoTime();
   uint64_t split_time = current_time - current_split_start_ns_;
+  ATRACE_END();
   if (verbose_) {
     LOG(INFO) << "End: " << current_split_ << " " << PrettyDuration(split_time);
   }
   splits_.push_back(std::pair<uint64_t, const char*>(split_time, current_split_));
 }
 
-uint64_t NewTimingLogger::GetTotalNs() const {
+uint64_t TimingLogger::GetTotalNs() const {
   uint64_t total_ns = 0;
   typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
   for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
@@ -237,7 +194,7 @@
   return total_ns;
 }
 
-void NewTimingLogger::Dump(std::ostream &os) const {
+void TimingLogger::Dump(std::ostream &os) const {
   uint64_t longest_split = 0;
   uint64_t total_ns = 0;
   typedef std::vector<std::pair<uint64_t, const char*> >::const_iterator It;
diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h
index 0f00a04..0998837 100644
--- a/runtime/base/timing_logger.h
+++ b/runtime/base/timing_logger.h
@@ -26,27 +26,8 @@
 
 namespace art {
 
-class CumulativeLogger;
-
-class TimingLogger {
- public:
-  explicit TimingLogger(const std::string& name, bool precise);
-  void AddSplit(const std::string& label);
-  void Dump(std::ostream& os) const;
-  void Reset();
-  uint64_t GetTotalNs() const;
-
- protected:
-  const std::string name_;
-  const bool precise_;
-  std::vector<uint64_t> times_;
-  std::vector<std::string> labels_;
-
-  friend class CumulativeLogger;
-};
-
 namespace base {
-  class NewTimingLogger;
+  class TimingLogger;
 }  // namespace base
 
 class CumulativeLogger {
@@ -62,8 +43,7 @@
   // Allow the name to be modified, particularly when the cumulative logger is a field within a
   // parent class that is unable to determine the "name" of a sub-class.
   void SetName(const std::string& name);
-  void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_);
-  void AddNewLogger(const base::NewTimingLogger& logger) LOCKS_EXCLUDED(lock_);
+  void AddLogger(const base::TimingLogger& logger) LOCKS_EXCLUDED(lock_);
 
  private:
   void AddPair(const std::string &label, uint64_t delta_time)
@@ -84,16 +64,15 @@
 namespace base {
 
 // A replacement to timing logger that know when a split starts for the purposes of logging.
-// TODO: replace uses of TimingLogger with base::NewTimingLogger.
-class NewTimingLogger {
+class TimingLogger {
  public:
-  explicit NewTimingLogger(const char* name, bool precise, bool verbose);
+  explicit TimingLogger(const char* name, bool precise, bool verbose);
 
   // Clears current splits and labels.
   void Reset();
 
   // Starts a split, a split shouldn't be in progress.
-  void StartSplit(const char* new_split_label);
+  void StartSplit(const char*  new_split_label);
 
   // Ends the current split and starts the one given by the label.
   void NewSplit(const char* new_split_label);
@@ -111,7 +90,7 @@
 
  protected:
   // The name of the timing logger.
-  const std::string name_;
+  const char* name_;
 
   // Do we want to print the exactly recorded split (true) or round down to the time unit being
   // used (false).
@@ -130,7 +109,7 @@
   std::vector<std::pair<uint64_t, const char*> > splits_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(NewTimingLogger);
+  DISALLOW_COPY_AND_ASSIGN(TimingLogger);
 };
 
 }  // namespace base
diff --git a/runtime/common_test.h b/runtime/common_test.h
index 842f959..2c23340 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -473,7 +473,8 @@
 
   void CompileMethod(mirror::AbstractMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK(method != NULL);
-    TimingLogger timings("CommonTest::CompileMethod", false);
+    base::TimingLogger timings("CommonTest::CompileMethod", false, false);
+    timings.StartSplit("CompileOne");
     compiler_driver_->CompileOne(method, timings);
     MakeExecutable(method);
   }
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 6be249c..13b0f1c 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -281,9 +281,7 @@
 
   // Returns the opcode field of the instruction.
   Code Opcode() const {
-    const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
-    int opcode = *insns & 0xFF;
-    return static_cast<Code>(opcode);
+    return static_cast<Code>(Fetch16(0) & 0xFF);
   }
 
   void SetOpcode(Code opcode) {
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index 1684664..0f566c9 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -64,7 +64,7 @@
 
   void RegisterPause(uint64_t nano_length);
 
-  base::NewTimingLogger& GetTimings() {
+  base::TimingLogger& GetTimings() {
     return timings_;
   }
 
@@ -101,7 +101,7 @@
   const bool verbose_;
 
   uint64_t duration_ns_;
-  base::NewTimingLogger timings_;
+  base::TimingLogger timings_;
 
   // Cumulative statistics.
   uint64_t total_time_ns_;
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 5736e38..89c768a 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -1509,7 +1509,7 @@
 
   // Update the cumulative loggers.
   cumulative_timings_.Start();
-  cumulative_timings_.AddNewLogger(timings_);
+  cumulative_timings_.AddLogger(timings_);
   cumulative_timings_.End();
 
   // Clear all of the spaces' mark bitmaps.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 0c1c631..292fd29 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -148,7 +148,7 @@
   CHECK(large_object_space_ != NULL) << "Failed to create large object space";
   AddDiscontinuousSpace(large_object_space_);
 
-  alloc_space_ = space::DlMallocSpace::Create("alloc space",
+  alloc_space_ = space::DlMallocSpace::Create(Runtime::Current()->IsZygote() ? "zygote space" : "alloc space",
                                               initial_size,
                                               growth_limit, capacity,
                                               requested_alloc_space_begin);
@@ -972,7 +972,7 @@
   // Turns the current alloc space into a Zygote space and obtain the new alloc space composed
   // of the remaining available heap memory.
   space::DlMallocSpace* zygote_space = alloc_space_;
-  alloc_space_ = zygote_space->CreateZygoteSpace();
+  alloc_space_ = zygote_space->CreateZygoteSpace("alloc space");
   alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
 
   // Change the GC retention policy of the zygote space to only collect when full.
@@ -1131,7 +1131,7 @@
               << PrettySize(total_memory) << ", " << "paused " << pause_string.str()
               << " total " << PrettyDuration((duration / 1000) * 1000);
     if (VLOG_IS_ON(heap)) {
-      LOG(INFO) << Dumpable<base::NewTimingLogger>(collector->GetTimings());
+      LOG(INFO) << Dumpable<base::TimingLogger>(collector->GetTimings());
     }
   }
 
@@ -1149,7 +1149,7 @@
   return gc_type;
 }
 
-void Heap::UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings,
+void Heap::UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::TimingLogger& timings,
                                  collector::GcType gc_type) {
   if (gc_type == collector::kGcTypeSticky) {
     // Don't need to do anything for mod union table in this case since we are only scanning dirty
@@ -1441,7 +1441,7 @@
   }
 }
 
-void Heap::ProcessCards(base::NewTimingLogger& timings) {
+void Heap::ProcessCards(base::TimingLogger& timings) {
   // Clear cards and keep track of cards cleared in the mod-union table.
   typedef std::vector<space::ContinuousSpace*>::iterator It;
   for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
@@ -1934,5 +1934,27 @@
   } while (!native_bytes_allocated_.compare_and_swap(expected_size, new_size));
 }
 
+int64_t Heap::GetTotalMemory() const {
+  int64_t ret = 0;
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->IsImageSpace()) {
+      // Currently don't include the image space.
+    } else if (space->IsDlMallocSpace()) {
+      // Zygote or alloc space
+      ret += space->AsDlMallocSpace()->GetFootprint();
+    }
+  }
+  typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+  for (It2 it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+    space::DiscontinuousSpace* space = *it;
+    if (space->IsLargeObjectSpace()) {
+      ret += space->AsLargeObjectSpace()->GetBytesAllocated();
+    }
+  }
+  return ret;
+}
+
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 20512b8..7615f98 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -330,11 +330,7 @@
 
   // Implements java.lang.Runtime.totalMemory, returning the amount of memory consumed by an
   // application.
-  int64_t GetTotalMemory() const {
-    // TODO: we use the footprint limit here which is conservative wrt number of pages really used.
-    //       We could implement a more accurate count across all spaces.
-    return max_allowed_footprint_;
-  }
+  int64_t GetTotalMemory() const;
 
   // Implements java.lang.Runtime.freeMemory.
   int64_t GetFreeMemory() const {
@@ -382,7 +378,7 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Update and mark mod union table based on gc type.
-  void UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings,
+  void UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::TimingLogger& timings,
                              collector::GcType gc_type)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -475,7 +471,7 @@
   void SwapStacks();
 
   // Clear cards and update the mod union table.
-  void ProcessCards(base::NewTimingLogger& timings);
+  void ProcessCards(base::TimingLogger& timings);
 
   // All-known continuous spaces, where objects lie within fixed bounds.
   std::vector<space::ContinuousSpace*> continuous_spaces_;
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index ee88eda..de4917f 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -286,7 +286,7 @@
   }
 }
 
-DlMallocSpace* DlMallocSpace::CreateZygoteSpace() {
+DlMallocSpace* DlMallocSpace::CreateZygoteSpace(const char* alloc_space_name) {
   end_ = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(end_), kPageSize));
   DCHECK(IsAligned<accounting::CardTable::kCardSize>(begin_));
   DCHECK(IsAligned<accounting::CardTable::kCardSize>(end_));
@@ -316,20 +316,19 @@
   VLOG(heap) << "Size " << GetMemMap()->Size();
   VLOG(heap) << "GrowthLimit " << PrettySize(growth_limit);
   VLOG(heap) << "Capacity " << PrettySize(capacity);
-  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(GetName(), End(), capacity, PROT_READ | PROT_WRITE));
+  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity, PROT_READ | PROT_WRITE));
   void* mspace = CreateMallocSpace(end_, starting_size, initial_size);
   // Protect memory beyond the initial size.
   byte* end = mem_map->Begin() + starting_size;
   if (capacity - initial_size > 0) {
-    CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), name_.c_str());
+    CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), alloc_space_name);
   }
   DlMallocSpace* alloc_space =
-      new DlMallocSpace(name_, mem_map.release(), mspace, end_, end, growth_limit);
+      new DlMallocSpace(alloc_space_name, mem_map.release(), mspace, end_, end, growth_limit);
   live_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End()));
   CHECK_EQ(live_bitmap_->HeapLimit(), reinterpret_cast<uintptr_t>(End()));
   mark_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End()));
   CHECK_EQ(mark_bitmap_->HeapLimit(), reinterpret_cast<uintptr_t>(End()));
-  name_ += "-zygote-transformed";
   VLOG(heap) << "zygote space creation done";
   return alloc_space;
 }
@@ -449,6 +448,11 @@
   callback(NULL, NULL, 0, arg);  // Indicate end of a space.
 }
 
+size_t DlMallocSpace::GetFootprint() {
+  MutexLock mu(Thread::Current(), lock_);
+  return mspace_footprint(mspace_);
+}
+
 size_t DlMallocSpace::GetFootprintLimit() {
   MutexLock mu(Thread::Current(), lock_);
   return mspace_footprint_limit(mspace_);
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index 8a4314c..c15d0ba 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -73,6 +73,10 @@
   // in use, indicated by num_bytes equaling zero.
   void Walk(WalkCallback callback, void* arg);
 
+  // Returns the number of bytes that the space has currently obtained from the system. This is
+  // greater or equal to the amount of live data in the space.
+  size_t GetFootprint();
+
   // Returns the number of bytes that the heap is allowed to obtain from the system via MoreCore.
   size_t GetFootprintLimit();
 
@@ -113,7 +117,7 @@
   void SwapBitmaps();
 
   // Turn ourself into a zygote space and return a new alloc space which has our unused memory.
-  DlMallocSpace* CreateZygoteSpace();
+  DlMallocSpace* CreateZygoteSpace(const char* alloc_space_name);
 
   uint64_t GetBytesAllocated() const {
     return num_bytes_allocated_;
diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc
index 08ae894..3003140 100644
--- a/runtime/gc/space/space_test.cc
+++ b/runtime/gc/space/space_test.cc
@@ -123,7 +123,7 @@
 
     // Make sure that the zygote space isn't directly at the start of the space.
     space->Alloc(self, 1U * MB);
-    space = space->CreateZygoteSpace();
+    space = space->CreateZygoteSpace("alloc space");
 
     // Make space findable to the heap, will also delete space when runtime is cleaned up
     AddContinuousSpace(space);
diff --git a/runtime/image_test.cc b/runtime/image_test.cc
index 75eead4..22bed2e 100644
--- a/runtime/image_test.cc
+++ b/runtime/image_test.cc
@@ -44,7 +44,8 @@
     {
       jobject class_loader = NULL;
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-      TimingLogger timings("ImageTest::WriteRead", false);
+      base::TimingLogger timings("ImageTest::WriteRead", false, false);
+      timings.StartSplit("CompileAll");
       compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
 
       ScopedObjectAccess soa(Thread::Current());
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 30c7a46..d649d2a 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -1013,28 +1013,29 @@
     return JValue();
   }
   self->VerifyStack();
-  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
-  const uint16_t* const insns = code_item->insns_;
+  instrumentation::Instrumentation* const instrumentation = Runtime::Current()->GetInstrumentation();
 
   // As the 'this' object won't change during the execution of current code, we
   // want to cache it in local variables. Nevertheless, in order to let the
   // garbage collector access it, we store it into sirt references.
   SirtRef<Object> this_object_ref(self, shadow_frame.GetThisObject(code_item->ins_size_));
 
-  const Instruction* inst = Instruction::At(insns + shadow_frame.GetDexPC());
-  if (inst->GetDexPc(insns) == 0) {  // We are entering the method as opposed to deoptimizing..
+  uint32_t dex_pc = shadow_frame.GetDexPC();
+  if (LIKELY(dex_pc == 0)) {  // We are entering the method as opposed to deoptimizing..
     if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
       instrumentation->MethodEnterEvent(self, this_object_ref.get(),
                                         shadow_frame.GetMethod(), 0);
     }
   }
+  const uint16_t* const insns = code_item->insns_;
+  const Instruction* inst = Instruction::At(insns + dex_pc);
   while (true) {
+    dex_pc = inst->GetDexPc(insns);
+    shadow_frame.SetDexPC(dex_pc);
     if (UNLIKELY(self->TestAllFlags())) {
       CheckSuspend(self);
     }
-    const uint32_t dex_pc = inst->GetDexPc(insns);
-    shadow_frame.SetDexPC(dex_pc);
-    if (instrumentation->HasDexPcListeners()) {
+    if (UNLIKELY(instrumentation->HasDexPcListeners())) {
       instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
                                        shadow_frame.GetMethod(), dex_pc);
     }
@@ -1200,8 +1201,8 @@
       }
       case Instruction::CONST_4: {
         PREAMBLE();
-        uint32_t dst = inst->VRegA_11n();
-        int32_t val = inst->VRegB_11n();
+        uint4_t dst = inst->VRegA_11n();
+        int4_t val = inst->VRegB_11n();
         shadow_frame.SetVReg(dst, val);
         if (val == 0) {
           shadow_frame.SetVRegReference(dst, NULL);
@@ -1211,8 +1212,8 @@
       }
       case Instruction::CONST_16: {
         PREAMBLE();
-        uint32_t dst = inst->VRegA_21s();
-        int32_t val = inst->VRegB_21s();
+        uint8_t dst = inst->VRegA_21s();
+        int16_t val = inst->VRegB_21s();
         shadow_frame.SetVReg(dst, val);
         if (val == 0) {
           shadow_frame.SetVRegReference(dst, NULL);
@@ -1222,7 +1223,7 @@
       }
       case Instruction::CONST: {
         PREAMBLE();
-        uint32_t dst = inst->VRegA_31i();
+        uint8_t dst = inst->VRegA_31i();
         int32_t val = inst->VRegB_31i();
         shadow_frame.SetVReg(dst, val);
         if (val == 0) {
@@ -1233,7 +1234,7 @@
       }
       case Instruction::CONST_HIGH16: {
         PREAMBLE();
-        uint32_t dst = inst->VRegA_21h();
+        uint8_t dst = inst->VRegA_21h();
         int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
         shadow_frame.SetVReg(dst, val);
         if (val == 0) {
@@ -2546,7 +2547,7 @@
         break;
       case Instruction::ADD_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) +
                              shadow_frame.GetVReg(inst->VRegB_12x()));
@@ -2555,7 +2556,7 @@
       }
       case Instruction::SUB_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) -
                              shadow_frame.GetVReg(inst->VRegB_12x()));
@@ -2564,7 +2565,7 @@
       }
       case Instruction::MUL_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) *
                              shadow_frame.GetVReg(inst->VRegB_12x()));
@@ -2573,7 +2574,7 @@
       }
       case Instruction::DIV_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
                     shadow_frame.GetVReg(inst->VRegB_12x()));
         inst = inst->Next_1xx();
@@ -2581,7 +2582,7 @@
       }
       case Instruction::REM_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
                        shadow_frame.GetVReg(inst->VRegB_12x()));
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx);
@@ -2589,7 +2590,7 @@
       }
       case Instruction::SHL_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) <<
                              (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x1f));
@@ -2598,7 +2599,7 @@
       }
       case Instruction::SHR_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) >>
                              (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x1f));
@@ -2607,7 +2608,7 @@
       }
       case Instruction::USHR_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              static_cast<uint32_t>(shadow_frame.GetVReg(vregA)) >>
                              (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x1f));
@@ -2616,7 +2617,7 @@
       }
       case Instruction::AND_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) &
                              shadow_frame.GetVReg(inst->VRegB_12x()));
@@ -2625,7 +2626,7 @@
       }
       case Instruction::OR_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) |
                              shadow_frame.GetVReg(inst->VRegB_12x()));
@@ -2634,7 +2635,7 @@
       }
       case Instruction::XOR_INT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVReg(vregA,
                              shadow_frame.GetVReg(vregA) ^
                              shadow_frame.GetVReg(inst->VRegB_12x()));
@@ -2643,7 +2644,7 @@
       }
       case Instruction::ADD_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) +
                                  shadow_frame.GetVRegLong(inst->VRegB_12x()));
@@ -2652,7 +2653,7 @@
       }
       case Instruction::SUB_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) -
                                  shadow_frame.GetVRegLong(inst->VRegB_12x()));
@@ -2661,7 +2662,7 @@
       }
       case Instruction::MUL_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) *
                                  shadow_frame.GetVRegLong(inst->VRegB_12x()));
@@ -2670,7 +2671,7 @@
       }
       case Instruction::DIV_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
                     shadow_frame.GetVRegLong(inst->VRegB_12x()));
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx);
@@ -2678,7 +2679,7 @@
       }
       case Instruction::REM_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
                         shadow_frame.GetVRegLong(inst->VRegB_12x()));
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_1xx);
@@ -2686,7 +2687,7 @@
       }
       case Instruction::AND_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) &
                                  shadow_frame.GetVRegLong(inst->VRegB_12x()));
@@ -2695,7 +2696,7 @@
       }
       case Instruction::OR_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) |
                                  shadow_frame.GetVRegLong(inst->VRegB_12x()));
@@ -2704,7 +2705,7 @@
       }
       case Instruction::XOR_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) ^
                                  shadow_frame.GetVRegLong(inst->VRegB_12x()));
@@ -2713,7 +2714,7 @@
       }
       case Instruction::SHL_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) <<
                                  (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x3f));
@@ -2722,7 +2723,7 @@
       }
       case Instruction::SHR_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  shadow_frame.GetVRegLong(vregA) >>
                                  (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x3f));
@@ -2731,7 +2732,7 @@
       }
       case Instruction::USHR_LONG_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegLong(vregA,
                                  static_cast<uint64_t>(shadow_frame.GetVRegLong(vregA)) >>
                                  (shadow_frame.GetVReg(inst->VRegB_12x()) & 0x3f));
@@ -2740,7 +2741,7 @@
       }
       case Instruction::ADD_FLOAT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegFloat(vregA,
                                   shadow_frame.GetVRegFloat(vregA) +
                                   shadow_frame.GetVRegFloat(inst->VRegB_12x()));
@@ -2749,7 +2750,7 @@
       }
       case Instruction::SUB_FLOAT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegFloat(vregA,
                                   shadow_frame.GetVRegFloat(vregA) -
                                   shadow_frame.GetVRegFloat(inst->VRegB_12x()));
@@ -2758,7 +2759,7 @@
       }
       case Instruction::MUL_FLOAT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegFloat(vregA,
                                   shadow_frame.GetVRegFloat(vregA) *
                                   shadow_frame.GetVRegFloat(inst->VRegB_12x()));
@@ -2767,7 +2768,7 @@
       }
       case Instruction::DIV_FLOAT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegFloat(vregA,
                                   shadow_frame.GetVRegFloat(vregA) /
                                   shadow_frame.GetVRegFloat(inst->VRegB_12x()));
@@ -2776,7 +2777,7 @@
       }
       case Instruction::REM_FLOAT_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegFloat(vregA,
                                   fmodf(shadow_frame.GetVRegFloat(vregA),
                                         shadow_frame.GetVRegFloat(inst->VRegB_12x())));
@@ -2785,7 +2786,7 @@
       }
       case Instruction::ADD_DOUBLE_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegDouble(vregA,
                                    shadow_frame.GetVRegDouble(vregA) +
                                    shadow_frame.GetVRegDouble(inst->VRegB_12x()));
@@ -2794,7 +2795,7 @@
       }
       case Instruction::SUB_DOUBLE_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegDouble(vregA,
                                    shadow_frame.GetVRegDouble(vregA) -
                                    shadow_frame.GetVRegDouble(inst->VRegB_12x()));
@@ -2803,7 +2804,7 @@
       }
       case Instruction::MUL_DOUBLE_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegDouble(vregA,
                                    shadow_frame.GetVRegDouble(vregA) *
                                    shadow_frame.GetVRegDouble(inst->VRegB_12x()));
@@ -2812,7 +2813,7 @@
       }
       case Instruction::DIV_DOUBLE_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegDouble(vregA,
                                    shadow_frame.GetVRegDouble(vregA) /
                                    shadow_frame.GetVRegDouble(inst->VRegB_12x()));
@@ -2821,7 +2822,7 @@
       }
       case Instruction::REM_DOUBLE_2ADDR: {
         PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
+        uint4_t vregA = inst->VRegA_12x();
         shadow_frame.SetVRegDouble(vregA,
                                    fmod(shadow_frame.GetVRegDouble(vregA),
                                         shadow_frame.GetVRegDouble(inst->VRegB_12x())));
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 60624c2..e3ec3bc 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -20,6 +20,9 @@
 #include "class_linker.h"
 #include "common_throws.h"
 #include "debugger.h"
+#include "gc/space/dlmalloc_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
 #include "hprof/hprof.h"
 #include "jni_internal.h"
 #include "mirror/class.h"
@@ -234,6 +237,69 @@
   return count;
 }
 
+// We export the VM internal per-heap-space size/alloc/free metrics
+// for the zygote space, alloc space (application heap), and the large
+// object space for dumpsys meminfo. The other memory region data such
+// as PSS, private/shared dirty/shared data are available via
+// /proc/<pid>/smaps.
+static void VMDebug_getHeapSpaceStats(JNIEnv* env, jclass, jlongArray data) {
+  jlong* arr = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(data, 0));
+  if (arr == NULL || env->GetArrayLength(data) < 9) {
+    return;
+  }
+
+  size_t allocSize = 0;
+  size_t allocUsed = 0;
+  size_t zygoteSize = 0;
+  size_t zygoteUsed = 0;
+  size_t largeObjectsSize = 0;
+  size_t largeObjectsUsed = 0;
+
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  const std::vector<gc::space::ContinuousSpace*>& continuous_spaces = heap->GetContinuousSpaces();
+  const std::vector<gc::space::DiscontinuousSpace*>& discontinuous_spaces = heap->GetDiscontinuousSpaces();
+  typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+  for (It it = continuous_spaces.begin(), end = continuous_spaces.end(); it != end; ++it) {
+    gc::space::ContinuousSpace* space = *it;
+    if (space->IsImageSpace()) {
+      // Currently don't include the image space.
+    } else if (space->IsZygoteSpace()) {
+      gc::space::DlMallocSpace* dlmalloc_space = space->AsDlMallocSpace();
+      zygoteSize += dlmalloc_space->GetFootprint();
+      zygoteUsed += dlmalloc_space->GetBytesAllocated();
+    } else {
+      // This is the alloc space.
+      gc::space::DlMallocSpace* dlmalloc_space = space->AsDlMallocSpace();
+      allocSize += dlmalloc_space->GetFootprint();
+      allocUsed += dlmalloc_space->GetBytesAllocated();
+    }
+  }
+  typedef std::vector<gc::space::DiscontinuousSpace*>::const_iterator It2;
+  for (It2 it = discontinuous_spaces.begin(), end = discontinuous_spaces.end(); it != end; ++it) {
+    gc::space::DiscontinuousSpace* space = *it;
+    if (space->IsLargeObjectSpace()) {
+      largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated();
+      largeObjectsUsed += largeObjectsSize;
+    }
+  }
+
+  size_t allocFree = allocSize - allocUsed;
+  size_t zygoteFree = zygoteSize - zygoteUsed;
+  size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed;
+
+  int j = 0;
+  arr[j++] = allocSize;
+  arr[j++] = allocUsed;
+  arr[j++] = allocFree;
+  arr[j++] = zygoteSize;
+  arr[j++] = zygoteUsed;
+  arr[j++] = zygoteFree;
+  arr[j++] = largeObjectsSize;
+  arr[j++] = largeObjectsUsed;
+  arr[j++] = largeObjectsFree;
+  env->ReleasePrimitiveArrayCritical(data, arr, 0);
+}
+
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
   NATIVE_METHOD(VMDebug, crash, "()V"),
@@ -241,6 +307,7 @@
   NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
   NATIVE_METHOD(VMDebug, dumpReferenceTables, "()V"),
   NATIVE_METHOD(VMDebug, getAllocCount, "(I)I"),
+  NATIVE_METHOD(VMDebug, getHeapSpaceStats, "([J)V"),
   NATIVE_METHOD(VMDebug, getInstructionCount, "([I)V"),
   NATIVE_METHOD(VMDebug, getLoadedClassCount, "()I"),
   NATIVE_METHOD(VMDebug, getVmFeatureList, "()[Ljava/lang/String;"),
diff --git a/runtime/oat_test.cc b/runtime/oat_test.cc
index ebb228e..9fb2638 100644
--- a/runtime/oat_test.cc
+++ b/runtime/oat_test.cc
@@ -77,7 +77,7 @@
   compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, NULL, 2, true));
   jobject class_loader = NULL;
   if (compile) {
-    TimingLogger timings("OatTest::WriteRead", false);
+    base::TimingLogger timings("OatTest::WriteRead", false, false);
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
   }
 
@@ -96,7 +96,7 @@
   ASSERT_TRUE(success);
 
   if (compile) {  // OatWriter strips the code, regenerate to compare
-    TimingLogger timings("CommonTest::WriteRead", false);
+    base::TimingLogger timings("CommonTest::WriteRead", false, false);
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), timings);
   }
   UniquePtr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), NULL, false));
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0c13ad2..35667e7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -134,10 +134,10 @@
   delete java_vm_;
   Thread::Shutdown();
   QuasiAtomic::Shutdown();
+  verifier::MethodVerifier::Shutdown();
   // TODO: acquire a static mutex on Runtime to avoid racing.
   CHECK(instance_ == NULL || instance_ == this);
   instance_ = NULL;
-  verifier::MethodVerifier::Shutdown();
 }
 
 struct AbortState {
diff --git a/runtime/verifier/instruction_flags.cc b/runtime/verifier/instruction_flags.cc
index 358791d..f76c226 100644
--- a/runtime/verifier/instruction_flags.cc
+++ b/runtime/verifier/instruction_flags.cc
@@ -22,16 +22,17 @@
 namespace verifier {
 
 std::string InstructionFlags::ToString() const {
-  char encoding[6];
+  char encoding[7];
   if (!IsOpcode()) {
-    strncpy(encoding, "XXXXX", sizeof(encoding));
+    strncpy(encoding, "XXXXXX", sizeof(encoding));
   } else {
-    strncpy(encoding, "-----", sizeof(encoding));
-    if (IsInTry())        encoding[kInTry] = 'T';
-    if (IsBranchTarget()) encoding[kBranchTarget] = 'B';
+    strncpy(encoding, "------", sizeof(encoding));
+    if (IsVisited())               encoding[kVisited] = 'V';
+    if (IsChanged())               encoding[kChanged] = 'C';
+    if (IsInTry())                 encoding[kInTry] = 'T';
+    if (IsBranchTarget())          encoding[kBranchTarget] = 'B';
     if (IsCompileTimeInfoPoint())  encoding[kCompileTimeInfoPoint] = 'G';
-    if (IsVisited())      encoding[kVisited] = 'V';
-    if (IsChanged())      encoding[kChanged] = 'C';
+    if (IsReturn())                encoding[kReturn] = 'R';
   }
   return encoding;
 }
diff --git a/runtime/verifier/instruction_flags.h b/runtime/verifier/instruction_flags.h
index 9b2e595..e50ba13 100644
--- a/runtime/verifier/instruction_flags.h
+++ b/runtime/verifier/instruction_flags.h
@@ -93,6 +93,21 @@
     return IsVisited() || IsChanged();
   }
 
+  void SetReturn() {
+    flags_ |= 1 << kReturn;
+  }
+  void ClearReturn() {
+    flags_ &= ~(1 << kReturn);
+  }
+  bool IsReturn() const {
+    return (flags_ & (1 << kReturn)) != 0;
+  }
+
+  void SetCompileTimeInfoPointAndReturn() {
+    SetCompileTimeInfoPoint();
+    SetReturn();
+  }
+
   std::string ToString() const;
 
  private:
@@ -108,6 +123,8 @@
     kBranchTarget = 3,
     // Location of interest to the compiler for GC maps and verifier based method sharpening.
     kCompileTimeInfoPoint = 4,
+    // A return instruction.
+    kReturn = 5,
   };
 
   // Size of instruction in code units.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index ac499df..1b8b47e 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -102,7 +102,11 @@
     error += dex_file.GetLocation();
     return kHardFailure;
   }
-  return VerifyClass(&dex_file, kh.GetDexCache(), klass->GetClassLoader(), class_def_idx, error, allow_soft_failures);
+  return VerifyClass(&dex_file,
+                     kh.GetDexCache(),
+                     klass->GetClassLoader(),
+                     class_def_idx, error,
+                     allow_soft_failures);
 }
 
 MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
@@ -142,8 +146,15 @@
       // We couldn't resolve the method, but continue regardless.
       Thread::Current()->ClearException();
     }
-    MethodVerifier::FailureKind result = VerifyMethod(method_idx, dex_file, dex_cache, class_loader,
-        class_def_idx, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), allow_soft_failures);
+    MethodVerifier::FailureKind result = VerifyMethod(method_idx,
+                                                      dex_file,
+                                                      dex_cache,
+                                                      class_loader,
+                                                      class_def_idx,
+                                                      it.GetMethodCodeItem(),
+                                                      method,
+                                                      it.GetMemberAccessFlags(),
+                                                      allow_soft_failures);
     if (result != kNoFailure) {
       if (result == kHardFailure) {
         hard_fail = true;
@@ -177,8 +188,15 @@
       // We couldn't resolve the method, but continue regardless.
       Thread::Current()->ClearException();
     }
-    MethodVerifier::FailureKind result = VerifyMethod(method_idx, dex_file, dex_cache, class_loader,
-        class_def_idx, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), allow_soft_failures);
+    MethodVerifier::FailureKind result = VerifyMethod(method_idx,
+                                                      dex_file,
+                                                      dex_cache,
+                                                      class_loader,
+                                                      class_def_idx,
+                                                      it.GetMethodCodeItem(),
+                                                      method,
+                                                      it.GetMemberAccessFlags(),
+                                                      allow_soft_failures);
     if (result != kNoFailure) {
       if (result == kHardFailure) {
         hard_fail = true;
@@ -282,7 +300,9 @@
       new_instance_count_(0),
       monitor_enter_count_(0),
       can_load_classes_(can_load_classes),
-      allow_soft_failures_(allow_soft_failures) {
+      allow_soft_failures_(allow_soft_failures),
+      has_check_casts_(false),
+      has_virtual_or_interface_invokes_(false) {
 }
 
 void MethodVerifier::FindLocksAtDexPc(mirror::AbstractMethod* m, uint32_t dex_pc,
@@ -470,6 +490,13 @@
       new_instance_count++;
     } else if (opcode == Instruction::MONITOR_ENTER) {
       monitor_enter_count++;
+    } else if (opcode == Instruction::CHECK_CAST) {
+      has_check_casts_ = true;
+    } else if ((inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
+              (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE) ||
+              (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
+              (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE)) {
+      has_virtual_or_interface_invokes_ = true;
     }
     size_t inst_size = inst->SizeInCodeUnits();
     insn_flags_[dex_pc].SetLengthInCodeUnits(inst_size);
@@ -506,7 +533,8 @@
       return false;
     }
     if (!insn_flags_[start].IsOpcode()) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "'try' block starts inside an instruction (" << start << ")";
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+          << "'try' block starts inside an instruction (" << start << ")";
       return false;
     }
     for (uint32_t dex_pc = start; dex_pc < end;
@@ -523,7 +551,8 @@
     for (; iterator.HasNext(); iterator.Next()) {
       uint32_t dex_pc= iterator.GetHandlerAddress();
       if (!insn_flags_[dex_pc].IsOpcode()) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "exception handler starts at bad address (" << dex_pc << ")";
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+            << "exception handler starts at bad address (" << dex_pc << ")";
         return false;
       }
       const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
@@ -570,8 +599,10 @@
     /* Flag instructions that are garbage collection points */
     // All invoke points are marked as "Throw" points already.
     // We are relying on this to also count all the invokes as interesting.
-    if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow() || inst->IsReturn()) {
+    if (inst->IsBranch() || inst->IsSwitch() || inst->IsThrow()) {
       insn_flags_[dex_pc].SetCompileTimeInfoPoint();
+    } else if (inst->IsReturn()) {
+      insn_flags_[dex_pc].SetCompileTimeInfoPointAndReturn();
     }
     dex_pc += inst->SizeInCodeUnits();
     inst = inst->Next();
@@ -737,11 +768,13 @@
   }
   if (bracket_count == 0) {
     /* The given class must be an array type. */
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "can't new-array class '" << descriptor << "' (not an array)";
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+        << "can't new-array class '" << descriptor << "' (not an array)";
     return false;
   } else if (bracket_count > 255) {
     /* It is illegal to create an array of more than 255 dimensions. */
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "can't new-array class '" << descriptor << "' (exceeds limit)";
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+        << "can't new-array class '" << descriptor << "' (exceeds limit)";
     return false;
   }
   return true;
@@ -759,7 +792,8 @@
   if ((int32_t) cur_offset + array_data_offset < 0 ||
       cur_offset + array_data_offset + 2 >= insn_count) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid array data start: at " << cur_offset
-                                      << ", data offset " << array_data_offset << ", count " << insn_count;
+                                      << ", data offset " << array_data_offset
+                                      << ", count " << insn_count;
     return false;
   }
   /* offset to array data table is a relative branch-style offset */
@@ -791,18 +825,22 @@
     return false;
   }
   if (!selfOkay && offset == 0) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch offset of zero not allowed at" << reinterpret_cast<void*>(cur_offset);
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch offset of zero not allowed at"
+                                      << reinterpret_cast<void*>(cur_offset);
     return false;
   }
   // Check for 32-bit overflow. This isn't strictly necessary if we can depend on the runtime
   // to have identical "wrap-around" behavior, but it's unwise to depend on that.
   if (((int64_t) cur_offset + (int64_t) offset) != (int64_t) (cur_offset + offset)) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch target overflow " << reinterpret_cast<void*>(cur_offset) << " +" << offset;
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch target overflow "
+                                      << reinterpret_cast<void*>(cur_offset) << " +" << offset;
     return false;
   }
   const uint32_t insn_count = code_item_->insns_size_in_code_units_;
   int32_t abs_offset = cur_offset + offset;
-  if (abs_offset < 0 || (uint32_t) abs_offset >= insn_count || !insn_flags_[abs_offset].IsOpcode()) {
+  if (abs_offset < 0 ||
+      (uint32_t) abs_offset >= insn_count ||
+      !insn_flags_[abs_offset].IsOpcode()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid branch target " << offset << " (-> "
                                       << reinterpret_cast<void*>(abs_offset) << ") at "
                                       << reinterpret_cast<void*>(cur_offset);
@@ -858,7 +896,8 @@
   int32_t switch_offset = insns[1] | ((int32_t) insns[2]) << 16;
   if ((int32_t) cur_offset + switch_offset < 0 || cur_offset + switch_offset + 2 >= insn_count) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch start: at " << cur_offset
-                                      << ", switch offset " << switch_offset << ", count " << insn_count;
+                                      << ", switch offset " << switch_offset
+                                      << ", count " << insn_count;
     return false;
   }
   /* offset to switch table is a relative branch-style offset */
@@ -885,15 +924,16 @@
   }
   uint32_t table_size = targets_offset + switch_count * 2;
   if (switch_insns[0] != expected_signature) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << StringPrintf("wrong signature for switch table (%x, wanted %x)",
-                                                      switch_insns[0], expected_signature);
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+        << StringPrintf("wrong signature for switch table (%x, wanted %x)",
+                        switch_insns[0], expected_signature);
     return false;
   }
   /* make sure the end of the switch is in range */
   if (cur_offset + switch_offset + table_size > (uint32_t) insn_count) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch end: at " << cur_offset << ", switch offset "
-                                      << switch_offset << ", end "
-                                      << (cur_offset + switch_offset + table_size)
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch end: at " << cur_offset
+                                      << ", switch offset " << switch_offset
+                                      << ", end " << (cur_offset + switch_offset + table_size)
                                       << ", count " << insn_count;
     return false;
   }
@@ -916,10 +956,13 @@
     int32_t offset = (int32_t) switch_insns[targets_offset + targ * 2] |
                      (int32_t) (switch_insns[targets_offset + targ * 2 + 1] << 16);
     int32_t abs_offset = cur_offset + offset;
-    if (abs_offset < 0 || abs_offset >= (int32_t) insn_count || !insn_flags_[abs_offset].IsOpcode()) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch target " << offset << " (-> "
-                                        << reinterpret_cast<void*>(abs_offset) << ") at "
-                                        << reinterpret_cast<void*>(cur_offset) << "[" << targ << "]";
+    if (abs_offset < 0 ||
+        abs_offset >= (int32_t) insn_count ||
+        !insn_flags_[abs_offset].IsOpcode()) {
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch target " << offset
+                                        << " (-> " << reinterpret_cast<void*>(abs_offset) << ") at "
+                                        << reinterpret_cast<void*>(cur_offset)
+                                        << "[" << targ << "]";
       return false;
     }
     insn_flags_[abs_offset].SetBranchTarget();
@@ -949,14 +992,15 @@
   // vA/vC are unsigned 8-bit/16-bit quantities for /range instructions, so there's no risk of
   // integer overflow when adding them here.
   if (vA + vC > registers_size) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index " << vA << "+" << vC << " in range invoke (> "
-                                      << registers_size << ")";
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index " << vA << "+" << vC
+                                      << " in range invoke (> " << registers_size << ")";
     return false;
   }
   return true;
 }
 
-static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap(const std::vector<uint8_t>& gc_map) {
+static const std::vector<uint8_t>* CreateLengthPrefixedDexGcMap(
+    const std::vector<uint8_t>& gc_map) {
   std::vector<uint8_t>* length_prefixed_gc_map = new std::vector<uint8_t>;
   length_prefixed_gc_map->reserve(gc_map.size() + 4);
   length_prefixed_gc_map->push_back((gc_map.size() & 0xff000000) >> 24);
@@ -984,7 +1028,11 @@
                  << " insns_size=" << insns_size << ")";
   }
   /* Create and initialize table holding register status */
-  reg_table_.Init(kTrackCompilerInterestPoints, insn_flags_.get(), insns_size, registers_size, this);
+  reg_table_.Init(kTrackCompilerInterestPoints,
+                  insn_flags_.get(),
+                  insns_size,
+                  registers_size,
+                  this);
 
 
   work_line_.reset(new RegisterLine(registers_size, this));
@@ -1004,27 +1052,37 @@
     return false;
   }
 
-  /* Generate a register map and add it to the method. */
-  UniquePtr<const std::vector<uint8_t> > map(GenerateGcMap());
-  if (map.get() == NULL) {
-    DCHECK_NE(failures_.size(), 0U);
-    return false;  // Not a real failure, but a failure to encode
-  }
-  if (kIsDebugBuild) {
-    VerifyGcMap(*map);
-  }
-  MethodReference ref(dex_file_, dex_method_idx_);
-  const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get()));
-  verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map);
+  // Compute information for compiler.
+  if (Runtime::Current()->IsCompiler()) {
+    MethodReference ref(dex_file_, dex_method_idx_);
+    bool compile = IsCandidateForCompilation(code_item_, method_access_flags_);
+    if (compile) {
+      /* Generate a register map and add it to the method. */
+      UniquePtr<const std::vector<uint8_t> > map(GenerateGcMap());
+      if (map.get() == NULL) {
+        DCHECK_NE(failures_.size(), 0U);
+        return false;  // Not a real failure, but a failure to encode
+      }
+      if (kIsDebugBuild) {
+        VerifyGcMap(*map);
+      }
+      const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get()));
+      verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map);
+    }
 
-  MethodVerifier::MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet();
-  if (method_to_safe_casts != NULL) {
-    SetSafeCastMap(ref, method_to_safe_casts);
-  }
+    if (has_check_casts_) {
+      MethodVerifier::MethodSafeCastSet* method_to_safe_casts = GenerateSafeCastSet();
+      if (method_to_safe_casts != NULL) {
+        SetSafeCastMap(ref, method_to_safe_casts);
+      }
+    }
 
-  MethodVerifier::PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap();
-  if (pc_to_concrete_method != NULL) {
-    SetDevirtMap(ref, pc_to_concrete_method);
+    if (has_virtual_or_interface_invokes_) {
+      MethodVerifier::PcToConcreteMethodMap* pc_to_concrete_method = GenerateDevirtMap();
+      if (pc_to_concrete_method != NULL) {
+        SetDevirtMap(ref, pc_to_concrete_method);
+      }
+    }
   }
   return true;
 }
@@ -1164,13 +1222,15 @@
         break;
       }
       default:
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected signature type char '" << descriptor << "'";
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected signature type char '"
+                                          << descriptor << "'";
         return false;
     }
     cur_arg++;
   }
   if (cur_arg != expected_args) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected " << expected_args << " arguments, found " << cur_arg;
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected " << expected_args
+                                      << " arguments, found " << cur_arg;
     return false;
   }
   const char* descriptor = dex_file_->GetReturnTypeDescriptor(proto_id);
@@ -1304,12 +1364,14 @@
         if (dead_start < 0)
           dead_start = insn_idx;
       } else if (dead_start >= 0) {
-        LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1);
+        LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start)
+                        << "-" << reinterpret_cast<void*>(insn_idx - 1);
         dead_start = -1;
       }
     }
     if (dead_start >= 0) {
-      LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1);
+      LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start)
+                      << "-" << reinterpret_cast<void*>(insn_idx - 1);
     }
     // To dump the state of the verify after a method, do something like:
     // if (PrettyMethod(dex_method_idx_, *dex_file_) ==
@@ -1466,7 +1528,8 @@
         /* check the method signature */
         const RegType& return_type = GetMethodReturnType();
         if (!return_type.IsCategory1Types()) {
-          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected non-category 1 return type " << return_type;
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected non-category 1 return type "
+                                            << return_type;
         } else {
           // Compilers may generate synthetic functions that write byte values into boolean fields.
           // Also, it may use integer values for boolean, byte, short, and character return types.
@@ -1515,10 +1578,14 @@
           // Disallow returning uninitialized values and verify that the reference in vAA is an
           // instance of the "return_type"
           if (reg_type.IsUninitializedTypes()) {
-            Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "returning uninitialized object '" << reg_type << "'";
+            Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "returning uninitialized object '"
+                                              << reg_type << "'";
           } else if (!return_type.IsAssignableFrom(reg_type)) {
-            Fail(reg_type.IsUnresolvedTypes() ? VERIFY_ERROR_BAD_CLASS_SOFT : VERIFY_ERROR_BAD_CLASS_HARD)
-                << "returning '" << reg_type << "', but expected from declaration '" << return_type << "'";
+            Fail(reg_type.IsUnresolvedTypes() ?
+                 VERIFY_ERROR_BAD_CLASS_SOFT :
+                 VERIFY_ERROR_BAD_CLASS_HARD)
+                    << "returning '" << reg_type << "', but expected from declaration '"
+                    << return_type << "'";
           }
         }
       }
@@ -1738,7 +1805,8 @@
     case Instruction::THROW: {
       const RegType& res_type = work_line_->GetRegisterType(inst->VRegA_11x());
       if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
-        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type << " not instanceof Throwable";
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "thrown class " << res_type
+                                          << " not instanceof Throwable";
       }
       break;
     }
@@ -1760,7 +1828,8 @@
       /* array_type can be null if the reg type is Zero */
       if (!array_type.IsZero()) {
         if (!array_type.IsArrayTypes()) {
-          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type " << array_type;
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid fill-array-data with array type "
+                                            << array_type;
         } else {
           const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_);
           DCHECK(!component_type.IsConflict());
@@ -1800,8 +1869,8 @@
         mismatch = !reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes();
       }
       if (mismatch) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to if-eq/if-ne (" << reg_type1 << "," << reg_type2
-                                          << ") must both be references or integral";
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to if-eq/if-ne (" << reg_type1 << ","
+                                          << reg_type2 << ") must both be references or integral";
       }
       break;
     }
@@ -1821,7 +1890,8 @@
     case Instruction::IF_NEZ: {
       const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
       if (!reg_type.IsReferenceTypes() && !reg_type.IsIntegralTypes()) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type << " unexpected as arg to if-eqz/if-nez";
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
+                                          << " unexpected as arg to if-eqz/if-nez";
       }
 
       // Find previous instruction - its existence is a precondition to peephole optimization.
@@ -2143,7 +2213,10 @@
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE: {
         bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
-        mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range, false);
+        mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst,
+                                                                     METHOD_STATIC,
+                                                                     is_range,
+                                                                     false);
         const char* descriptor;
         if (called_method == NULL) {
           uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
@@ -2165,7 +2238,10 @@
     case Instruction::INVOKE_INTERFACE:
     case Instruction::INVOKE_INTERFACE_RANGE: {
       bool is_range =  (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
-      mirror::AbstractMethod* abs_method = VerifyInvocationArgs(inst, METHOD_INTERFACE, is_range, false);
+      mirror::AbstractMethod* abs_method = VerifyInvocationArgs(inst,
+                                                                METHOD_INTERFACE,
+                                                                is_range,
+                                                                false);
       if (abs_method != NULL) {
         mirror::Class* called_interface = abs_method->GetDeclaringClass();
         if (!called_interface->IsInterface() && !called_interface->IsObjectClass()) {
@@ -2329,7 +2405,11 @@
     case Instruction::MUL_FLOAT:
     case Instruction::DIV_FLOAT:
     case Instruction::REM_FLOAT:
-      work_line_->CheckBinaryOp(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
+      work_line_->CheckBinaryOp(inst,
+                                reg_types_.Float(),
+                                reg_types_.Float(),
+                                reg_types_.Float(),
+                                false);
       break;
     case Instruction::ADD_DOUBLE:
     case Instruction::SUB_DOUBLE:
@@ -2347,15 +2427,27 @@
     case Instruction::SHL_INT_2ADDR:
     case Instruction::SHR_INT_2ADDR:
     case Instruction::USHR_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckBinaryOp2addr(inst,
+                                     reg_types_.Integer(),
+                                     reg_types_.Integer(),
+                                     reg_types_.Integer(),
+                                     false);
       break;
     case Instruction::AND_INT_2ADDR:
     case Instruction::OR_INT_2ADDR:
     case Instruction::XOR_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckBinaryOp2addr(inst,
+                                     reg_types_.Integer(),
+                                     reg_types_.Integer(),
+                                     reg_types_.Integer(),
+                                     true);
       break;
     case Instruction::DIV_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(inst, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckBinaryOp2addr(inst,
+                                     reg_types_.Integer(),
+                                     reg_types_.Integer(),
+                                     reg_types_.Integer(),
+                                     false);
       break;
     case Instruction::ADD_LONG_2ADDR:
     case Instruction::SUB_LONG_2ADDR:
@@ -2380,7 +2472,11 @@
     case Instruction::MUL_FLOAT_2ADDR:
     case Instruction::DIV_FLOAT_2ADDR:
     case Instruction::REM_FLOAT_2ADDR:
-      work_line_->CheckBinaryOp2addr(inst, reg_types_.Float(), reg_types_.Float(), reg_types_.Float(), false);
+      work_line_->CheckBinaryOp2addr(inst,
+                                     reg_types_.Float(),
+                                     reg_types_.Float(),
+                                     reg_types_.Float(),
+                                     false);
       break;
     case Instruction::ADD_DOUBLE_2ADDR:
     case Instruction::SUB_DOUBLE_2ADDR:
@@ -2660,6 +2756,20 @@
       // Make workline consistent with fallthrough computed from peephole optimization.
       work_line_->CopyFromLine(fallthrough_line.get());
     }
+    if (insn_flags_[next_insn_idx].IsReturn()) {
+      // For returns we only care about the operand to the return, all other registers are dead.
+      const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx);
+      Instruction::Code opcode = ret_inst->Opcode();
+      if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) {
+        work_line_->MarkAllRegistersAsConflicts();
+      } else {
+        if (opcode == Instruction::RETURN_WIDE) {
+          work_line_->MarkAllRegistersAsConflictsExceptWide(ret_inst->VRegA_11x());
+        } else {
+          work_line_->MarkAllRegistersAsConflictsExcept(ret_inst->VRegA_11x());
+        }
+      }
+    }
     RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
     if (next_line != NULL) {
       // Merge registers into what we have for the next instruction,
@@ -3072,8 +3182,9 @@
   for (size_t param_index = 0; param_index < params_size; param_index++) {
     if (actual_args >= expected_args) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invalid call to '" << PrettyMethod(res_method)
-                << "'. Expected " << expected_args << " arguments, processing argument " << actual_args
-                << " (where longs/doubles count twice).";
+                                        << "'. Expected " << expected_args
+                                         << " arguments, processing argument " << actual_args
+                                        << " (where longs/doubles count twice).";
       return NULL;
     }
     const char* descriptor =
@@ -3226,7 +3337,8 @@
         // The instruction agrees with the type of array, confirm the value to be stored does too
         // Note: we use the instruction type (rather than the component type) for aput-object as
         // incompatible classes will be caught at runtime as an array store exception
-        work_line_->VerifyRegisterType(inst->VRegA_23x(), is_primitive ? component_type : insn_type);
+        work_line_->VerifyRegisterType(inst->VRegA_23x(),
+                                       is_primitive ? component_type : insn_type);
       }
     }
   }
@@ -3245,8 +3357,10 @@
   if (klass_type.IsUnresolvedTypes()) {
     return NULL;  // Can't resolve Class so no more to do here, will do checking at runtime.
   }
-  mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx,
-                                                                       dex_cache_, class_loader_);
+  mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_,
+                                                                               field_idx,
+                                                                               dex_cache_,
+                                                                               class_loader_);
   if (field == NULL) {
     LOG(INFO) << "Unable to resolve static field " << field_idx << " ("
               << dex_file_->GetFieldName(field_id) << ") in "
@@ -3280,8 +3394,10 @@
   if (klass_type.IsUnresolvedTypes()) {
     return NULL;  // Can't resolve Class so no more to do here
   }
-  mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_, field_idx,
-                                                                       dex_cache_, class_loader_);
+  mirror::Field* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(*dex_file_,
+                                                                               field_idx,
+                                                                               dex_cache_,
+                                                                               class_loader_);
   if (field == NULL) {
     LOG(INFO) << "Unable to resolve instance field " << field_idx << " ("
               << dex_file_->GetFieldName(field_id) << ") in "
@@ -3312,8 +3428,8 @@
       // Field accesses through uninitialized references are only allowable for constructors where
       // the field is declared in this class
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "cannot access instance field " << PrettyField(field)
-                                        << " of a not fully initialized object within the context of "
-                                        << PrettyMethod(dex_method_idx_, *dex_file_);
+                                        << " of a not fully initialized object within the context"
+                                        << " of " << PrettyMethod(dex_method_idx_, *dex_file_);
       return NULL;
     } else if (!field_klass.IsAssignableFrom(obj_type)) {
       // Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
@@ -3647,9 +3763,28 @@
      * there's nothing to "merge". Copy the registers over and mark it as changed. (This is the
      * only way a register can transition out of "unknown", so this is not just an optimization.)
      */
-    target_line->CopyFromLine(merge_line);
+    if (!insn_flags_[next_insn].IsReturn()) {
+      target_line->CopyFromLine(merge_line);
+    } else {
+      // For returns we only care about the operand to the return, all other registers are dead.
+      // Initialize them as conflicts so they don't add to GC and deoptimization information.
+      const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
+      Instruction::Code opcode = ret_inst->Opcode();
+      if ((opcode == Instruction::RETURN_VOID) || (opcode == Instruction::RETURN_VOID_BARRIER)) {
+        target_line->MarkAllRegistersAsConflicts();
+      } else {
+        target_line->CopyFromLine(merge_line);
+        if (opcode == Instruction::RETURN_WIDE) {
+          target_line->MarkAllRegistersAsConflictsExceptWide(ret_inst->VRegA_11x());
+        } else {
+          target_line->MarkAllRegistersAsConflictsExcept(ret_inst->VRegA_11x());
+        }
+      }
+    }
   } else {
-    UniquePtr<RegisterLine> copy(gDebugVerify ? new RegisterLine(target_line->NumRegs(), this) : NULL);
+    UniquePtr<RegisterLine> copy(gDebugVerify ?
+                                 new RegisterLine(target_line->NumRegs(), this) :
+                                 NULL);
     if (gDebugVerify) {
       copy->CopyFromLine(target_line);
     }
@@ -3686,7 +3821,8 @@
 const RegType& MethodVerifier::GetDeclaringClass() {
   if (declaring_class_ == NULL) {
     const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
-    const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
+    const char* descriptor
+        = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
     if (mirror_method_ != NULL) {
       mirror::Class* klass = mirror_method_->GetDeclaringClass();
       declaring_class_ = &reg_types_.FromClass(descriptor, klass,
@@ -3919,6 +4055,7 @@
 }
 
 void MethodVerifier::SetDexGcMap(MethodReference ref, const std::vector<uint8_t>& gc_map) {
+  DCHECK(Runtime::Current()->IsCompiler());
   {
     WriterMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
     DexGcMapTable::iterator it = dex_gc_maps_->find(ref);
@@ -3933,6 +4070,7 @@
 
 
 void  MethodVerifier::SetSafeCastMap(MethodReference ref, const MethodSafeCastSet* cast_set) {
+  DCHECK(Runtime::Current()->IsCompiler());
   MutexLock mu(Thread::Current(), *safecast_map_lock_);
   SafeCastMap::iterator it = safecast_map_->find(ref);
   if (it != safecast_map_->end()) {
@@ -3941,10 +4079,11 @@
   }
 
   safecast_map_->Put(ref, cast_set);
-  CHECK(safecast_map_->find(ref) != safecast_map_->end());
+  DCHECK(safecast_map_->find(ref) != safecast_map_->end());
 }
 
 bool MethodVerifier::IsSafeCast(MethodReference ref, uint32_t pc) {
+  DCHECK(Runtime::Current()->IsCompiler());
   MutexLock mu(Thread::Current(), *safecast_map_lock_);
   SafeCastMap::const_iterator it = safecast_map_->find(ref);
   if (it == safecast_map_->end()) {
@@ -3957,6 +4096,7 @@
 }
 
 const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(MethodReference ref) {
+  DCHECK(Runtime::Current()->IsCompiler());
   ReaderMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
   DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
   if (it == dex_gc_maps_->end()) {
@@ -3969,6 +4109,7 @@
 
 void  MethodVerifier::SetDevirtMap(MethodReference ref,
                                    const PcToConcreteMethodMap* devirt_map) {
+  DCHECK(Runtime::Current()->IsCompiler());
   WriterMutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::iterator it = devirt_maps_->find(ref);
   if (it != devirt_maps_->end()) {
@@ -3977,11 +4118,12 @@
   }
 
   devirt_maps_->Put(ref, devirt_map);
-  CHECK(devirt_maps_->find(ref) != devirt_maps_->end());
+  DCHECK(devirt_maps_->find(ref) != devirt_maps_->end());
 }
 
 const MethodReference* MethodVerifier::GetDevirtMap(const MethodReference& ref,
                                                                     uint32_t dex_pc) {
+  DCHECK(Runtime::Current()->IsCompiler());
   ReaderMutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref);
   if (it == devirt_maps_->end()) {
@@ -3989,7 +4131,8 @@
   }
 
   // Look up the PC in the map, get the concrete method to execute and return its reference.
-  MethodVerifier::PcToConcreteMethodMap::const_iterator pc_to_concrete_method = it->second->find(dex_pc);
+  MethodVerifier::PcToConcreteMethodMap::const_iterator pc_to_concrete_method
+      = it->second->find(dex_pc);
   if (pc_to_concrete_method != it->second->end()) {
     return &(pc_to_concrete_method->second);
   } else {
@@ -4041,6 +4184,24 @@
   return result;
 }
 
+bool MethodVerifier::IsCandidateForCompilation(const DexFile::CodeItem* code_item,
+                                               const uint32_t access_flags) {
+  // Don't compile class initializers, ever.
+  if (((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
+    return false;
+  }
+
+  const Runtime* runtime = Runtime::Current();
+  if (runtime->IsSmallMode() && runtime->UseCompileTimeClassPath()) {
+    // In Small mode, we only compile small methods.
+    const uint32_t code_size = code_item->insns_size_in_code_units_;
+    return (code_size < runtime->GetSmallModeMethodDexSizeLimit());
+  } else {
+    // In normal mode, we compile everything.
+    return true;
+  }
+}
+
 ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
 MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;
 
@@ -4054,65 +4215,79 @@
 MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL;
 
 void MethodVerifier::Init() {
-  dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock");
-  Thread* self = Thread::Current();
-  {
-    WriterMutexLock mu(self, *dex_gc_maps_lock_);
-    dex_gc_maps_ = new MethodVerifier::DexGcMapTable;
-  }
+  if (Runtime::Current()->IsCompiler()) {
+    dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock");
+    Thread* self = Thread::Current();
+    {
+      WriterMutexLock mu(self, *dex_gc_maps_lock_);
+      dex_gc_maps_ = new MethodVerifier::DexGcMapTable;
+    }
 
-  safecast_map_lock_ = new Mutex("verifier Cast Elision lock");
-  {
-    MutexLock mu(self, *safecast_map_lock_);
-    safecast_map_ = new MethodVerifier::SafeCastMap();
-  }
+    safecast_map_lock_ = new Mutex("verifier Cast Elision lock");
+    {
+      MutexLock mu(self, *safecast_map_lock_);
+      safecast_map_ = new MethodVerifier::SafeCastMap();
+    }
 
-  devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock");
+    devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock");
 
-  {
-    WriterMutexLock mu(self, *devirt_maps_lock_);
-    devirt_maps_ = new MethodVerifier::DevirtualizationMapTable();
-  }
+    {
+      WriterMutexLock mu(self, *devirt_maps_lock_);
+      devirt_maps_ = new MethodVerifier::DevirtualizationMapTable();
+    }
 
-  rejected_classes_lock_ = new Mutex("verifier rejected classes lock");
-  {
-    MutexLock mu(self, *rejected_classes_lock_);
-    rejected_classes_ = new MethodVerifier::RejectedClassesTable;
+    rejected_classes_lock_ = new Mutex("verifier rejected classes lock");
+    {
+      MutexLock mu(self, *rejected_classes_lock_);
+      rejected_classes_ = new MethodVerifier::RejectedClassesTable;
+    }
   }
   art::verifier::RegTypeCache::Init();
 }
 
 void MethodVerifier::Shutdown() {
-  Thread* self = Thread::Current();
-  {
-    WriterMutexLock mu(self, *dex_gc_maps_lock_);
-    STLDeleteValues(dex_gc_maps_);
-    delete dex_gc_maps_;
-    dex_gc_maps_ = NULL;
-  }
-  delete dex_gc_maps_lock_;
-  dex_gc_maps_lock_ = NULL;
+  if (Runtime::Current()->IsCompiler()) {
+    Thread* self = Thread::Current();
+    {
+      WriterMutexLock mu(self, *dex_gc_maps_lock_);
+      STLDeleteValues(dex_gc_maps_);
+      delete dex_gc_maps_;
+      dex_gc_maps_ = NULL;
+    }
+    delete dex_gc_maps_lock_;
+    dex_gc_maps_lock_ = NULL;
 
-  {
-    WriterMutexLock mu(self, *devirt_maps_lock_);
-    STLDeleteValues(devirt_maps_);
-    delete devirt_maps_;
-    devirt_maps_ = NULL;
-  }
-  delete devirt_maps_lock_;
-  devirt_maps_lock_ = NULL;
+    {
+      MutexLock mu(self, *safecast_map_lock_);
+      STLDeleteValues(safecast_map_);
+      delete safecast_map_;
+      safecast_map_ = NULL;
+    }
+    delete safecast_map_lock_;
+    safecast_map_lock_ = NULL;
 
-  {
-    MutexLock mu(self, *rejected_classes_lock_);
-    delete rejected_classes_;
-    rejected_classes_ = NULL;
+    {
+      WriterMutexLock mu(self, *devirt_maps_lock_);
+      STLDeleteValues(devirt_maps_);
+      delete devirt_maps_;
+      devirt_maps_ = NULL;
+    }
+    delete devirt_maps_lock_;
+    devirt_maps_lock_ = NULL;
+
+    {
+      MutexLock mu(self, *rejected_classes_lock_);
+      delete rejected_classes_;
+      rejected_classes_ = NULL;
+    }
+    delete rejected_classes_lock_;
+    rejected_classes_lock_ = NULL;
   }
-  delete rejected_classes_lock_;
-  rejected_classes_lock_ = NULL;
   verifier::RegTypeCache::ShutDown();
 }
 
 void MethodVerifier::AddRejectedClass(ClassReference ref) {
+  DCHECK(Runtime::Current()->IsCompiler());
   {
     MutexLock mu(Thread::Current(), *rejected_classes_lock_);
     rejected_classes_->insert(ref);
@@ -4121,6 +4296,7 @@
 }
 
 bool MethodVerifier::IsClassRejected(ClassReference ref) {
+  DCHECK(Runtime::Current()->IsCompiler());
   MutexLock mu(Thread::Current(), *rejected_classes_lock_);
   return (rejected_classes_->find(ref) != rejected_classes_->end());
 }
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index e1bcbb1..3f98a00 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -237,6 +237,9 @@
   // Describe VRegs at the given dex pc.
   std::vector<int32_t> DescribeVRegs(uint32_t dex_pc);
 
+  static bool IsCandidateForCompilation(const DexFile::CodeItem* code_item,
+                                        const uint32_t access_flags);
+
  private:
   // Adds the given string to the beginning of the last failure message.
   void PrependToLastFailMessage(std::string);
@@ -654,7 +657,7 @@
         LOCKS_EXCLUDED(devirt_maps_lock_);
   typedef std::set<ClassReference> RejectedClassesTable;
   static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  static RejectedClassesTable* rejected_classes_;
+  static RejectedClassesTable* rejected_classes_ GUARDED_BY(rejected_classes_lock_);
 
   static void AddRejectedClass(ClassReference ref)
       LOCKS_EXCLUDED(rejected_classes_lock_);
@@ -717,6 +720,13 @@
   // Converts soft failures to hard failures when false. Only false when the compiler isn't
   // running and the verifier is called from the class linker.
   const bool allow_soft_failures_;
+
+  // Indicates if the method being verified contains at least one check-cast instruction.
+  bool has_check_casts_;
+
+  // Indicates if the method being verified contains at least one invoke-virtual/range
+  // or invoke-interface/range.
+  bool has_virtual_or_interface_invokes_;
 };
 std::ostream& operator<<(std::ostream& os, const MethodVerifier::FailureKind& rhs);
 
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index d2abaac..7965c06 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -167,7 +167,7 @@
   DCHECK(uninit_type.IsUninitializedTypes());
   const RegType& init_type = verifier_->GetRegTypeCache()->FromUninitialized(uninit_type);
   size_t changed = 0;
-  for (size_t i = 0; i < num_regs_; i++) {
+  for (uint32_t i = 0; i < num_regs_; i++) {
     if (GetRegisterType(i).Equals(uninit_type)) {
       line_[i] = init_type.GetId();
       changed++;
@@ -176,6 +176,31 @@
   DCHECK_GT(changed, 0u);
 }
 
+void RegisterLine::MarkAllRegistersAsConflicts() {
+  uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
+  for (uint32_t i = 0; i < num_regs_; i++) {
+    line_[i] = conflict_type_id;
+  }
+}
+
+void RegisterLine::MarkAllRegistersAsConflictsExcept(uint32_t vsrc) {
+  uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
+  for (uint32_t i = 0; i < num_regs_; i++) {
+    if (i != vsrc) {
+      line_[i] = conflict_type_id;
+    }
+  }
+}
+
+void RegisterLine::MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc) {
+  uint16_t conflict_type_id = verifier_->GetRegTypeCache()->Conflict().GetId();
+  for (uint32_t i = 0; i < num_regs_; i++) {
+    if ((i != vsrc) && (i != (vsrc + 1))) {
+      line_[i] = conflict_type_id;
+    }
+  }
+}
+
 std::string RegisterLine::Dump() const {
   std::string result;
   for (size_t i = 0; i < num_regs_; i++) {
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index cde7b9b..f380877 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -141,6 +141,13 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
+   * Update all registers to be Conflict except vsrc.
+   */
+  void MarkAllRegistersAsConflicts();
+  void MarkAllRegistersAsConflictsExcept(uint32_t vsrc);
+  void MarkAllRegistersAsConflictsExceptWide(uint32_t vsrc);
+
+  /*
    * Check constraints on constructor return. Specifically, make sure that the "this" argument got
    * initialized.
    * The "this" argument to <init> uses code offset kUninitThisArgAddr, which puts it at the start
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/ReferenceMap/stack_walk_refmap_jni.cc
index 10ca563..3b5d80d 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/ReferenceMap/stack_walk_refmap_jni.cc
@@ -103,7 +103,9 @@
       //   0024: move-object v3, v2
       //   0025: goto 0013
       // Detaled dex instructions for ReferenceMap.java are at the end of this function.
-      CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1);  // v8: this, v3: y, v2: y, v1: x
+      // CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1);  // v8: this, v3: y, v2: y, v1: x
+      // We eliminate the non-live registers at a return, so only v3 is live:
+      CHECK_REGS_CONTAIN_REFS(3);  // v3: y
 
       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToFirstNativeSafepointPc(0x18U)));
       CHECK(ref_bitmap);
@@ -188,7 +190,7 @@
 // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
 //      |0010: +invoke-virtual-quick {v8, v7}, [000c] // vtable #000c
 
-// 0:[Conflict],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
+// 0:[Conflict],1:[Conflict],2:[Conflict],3:[Reference: java.lang.Object],4:[Conflict],5:[Conflict],6:[Conflict],7:[Conflict],8:[Conflict],
 //      |0013: return-object v3
 //      |0014: move-exception v0