am 999cd43e: Fix oat-target to use new odex style extensions

* commit '999cd43edadfd408064457c2b46a9f3b6dde4dd3':
  Fix oat-target to use new odex style extensions
diff --git a/build/Android.common.mk b/build/Android.common.mk
index e84667d..a7bf944 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -19,6 +19,9 @@
 $(info Enabling ART_SMALL_MODE because of existence of art/SMALL_ART)
 ART_SMALL_MODE := true
 endif
+ifeq ($(WITH_ART_SMALL_MODE), true)
+ART_SMALL_MODE := true
+endif
 
 ART_USE_PORTABLE_COMPILER := false
 ifneq ($(wildcard art/USE_PORTABLE_COMPILER),)
@@ -49,11 +52,13 @@
 
 ART_C_INCLUDES := \
 	external/gtest/include \
+	external/valgrind/main/include \
 	external/zlib \
 	frameworks/compile/mclinker/include \
 	art/src
 
 art_cflags := \
+	-fno-rtti \
 	-O2 \
 	-ggdb3 \
 	-Wall \
@@ -62,13 +67,6 @@
 	-Wstrict-aliasing=3 \
 	-fstrict-aliasing
 
-# Enable thread-safety for GCC 4.6 but not for GCC 4.7 where this feature was removed.
-# Enable GCC 4.6 builds with 'export TARGET_GCC_VERSION_EXP=4.6'
-ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
-  $(info Enabling thread-safety for GCC $(TARGET_GCC_VERSION))
-  art_cflags += -Wthread-safety
-endif
-
 ifeq ($(ART_SMALL_MODE),true)
   art_cflags += -DART_SMALL_MODE=1
 endif
@@ -108,6 +106,22 @@
   ART_TARGET_CFLAGS += -DANDROID_SMP=0
 endif
 
+# Enable thread-safety for GCC 4.6 on the target but not for GCC 4.7 where this feature was removed.
+ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
+  ART_TARGET_CFLAGS += -Wthread-safety
+else
+  # Warn if not using GCC 4.6 for target builds when not doing a top-level or 'mma' build.
+  ifneq ($(ONE_SHOT_MAKEFILE),)
+    # Enable target GCC 4.6 with: export TARGET_GCC_VERSION_EXP=4.6
+    $(info Using target GCC $(TARGET_GCC_VERSION) disables thread-safety checks.)
+  endif
+endif
+# We build with GCC 4.6 on the host.
+ART_HOST_CFLAGS += -Wthread-safety
+
+# Make host builds easier to debug and profile by not omitting the frame pointer.
+ART_HOST_CFLAGS += -fno-omit-frame-pointer
+
 # To use oprofile_android --callgraph, uncomment this and recompile with "mmm art -B -j16"
 # ART_TARGET_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
 
@@ -156,6 +170,8 @@
 	src/compiled_method.cc \
 	src/compiler/driver/compiler_driver.cc \
 	src/compiler/llvm/runtime_support_llvm.cc \
+        src/compiler/stubs/portable/stubs.cc \
+        src/compiler/stubs/quick/stubs.cc \
 	src/debugger.cc \
 	src/dex_file.cc \
 	src/dex_file_verifier.cc \
@@ -164,20 +180,22 @@
 	src/disassembler_arm.cc \
 	src/disassembler_mips.cc \
 	src/disassembler_x86.cc \
-	src/dlmalloc.cc \
 	src/elf_file.cc \
 	src/file_output_stream.cc \
-	src/gc/card_table.cc \
-	src/gc/garbage_collector.cc \
-	src/gc/heap_bitmap.cc \
-	src/gc/large_object_space.cc \
-	src/gc/mark_sweep.cc \
-	src/gc/mod_union_table.cc \
-	src/gc/partial_mark_sweep.cc \
-	src/gc/space.cc \
-	src/gc/space_bitmap.cc \
-	src/gc/sticky_mark_sweep.cc \
-	src/heap.cc \
+	src/gc/allocator/dlmalloc.cc \
+	src/gc/accounting/card_table.cc \
+	src/gc/accounting/heap_bitmap.cc \
+	src/gc/accounting/mod_union_table.cc \
+	src/gc/accounting/space_bitmap.cc \
+	src/gc/collector/garbage_collector.cc \
+	src/gc/collector/mark_sweep.cc \
+	src/gc/collector/partial_mark_sweep.cc \
+	src/gc/collector/sticky_mark_sweep.cc \
+	src/gc/heap.cc \
+	src/gc/space/dlmalloc_space.cc \
+	src/gc/space/image_space.cc \
+	src/gc/space/large_object_space.cc \
+	src/gc/space/space.cc \
 	src/hprof/hprof.cc \
 	src/image.cc \
 	src/image_writer.cc \
@@ -357,9 +375,9 @@
 	src/compiler/dex/compiler_enums.h \
 	src/dex_file.h \
 	src/dex_instruction.h \
-	src/gc/gc_type.h \
-	src/gc/space.h \
-	src/heap.h \
+	src/gc/collector/gc_type.h \
+	src/gc/space/space.h \
+	src/gc/heap.h \
 	src/indirect_reference_table.h \
 	src/instruction_set.h \
 	src/invoke_type.h \
@@ -392,10 +410,10 @@
 	src/dex_method_iterator_test.cc \
 	src/elf_writer_test.cc \
 	src/exception_test.cc \
-	src/gc/space_bitmap_test.cc \
-	src/gc/space_test.cc \
+	src/gc/accounting/space_bitmap_test.cc \
+	src/gc/heap_test.cc \
+	src/gc/space/space_test.cc \
 	src/gtest_test.cc \
-	src/heap_test.cc \
 	src/image_test.cc \
 	src/indenter_test.cc \
 	src/indirect_reference_table_test.cc \
diff --git a/build/Android.libart-compiler.mk b/build/Android.libart-compiler.mk
index 4452f05..b73a329 100644
--- a/build/Android.libart-compiler.mk
+++ b/build/Android.libart-compiler.mk
@@ -45,7 +45,6 @@
 	src/compiler/dex/quick/x86/utility_x86.cc \
 	src/compiler/dex/portable/mir_to_gbc.cc \
 	src/compiler/dex/mir_dataflow.cc \
-	src/compiler/dex/dataflow_iterator.cc \
 	src/compiler/dex/mir_optimization.cc \
 	src/compiler/dex/frontend.cc \
 	src/compiler/dex/mir_graph.cc \
diff --git a/src/atomic.cc b/src/atomic.cc
index 4efb061..f2a9982 100644
--- a/src/atomic.cc
+++ b/src/atomic.cc
@@ -130,20 +130,9 @@
   } while (__builtin_expect(status != 0, 0));
   return prev == old_value;
 #elif defined(__i386__)
-  // cmpxchg8b implicitly uses %ebx which is also the PIC register.
-  int8_t status;
-  __asm__ __volatile__ (
-      "pushl          %%ebx\n"
-      "movl           (%3), %%ebx\n"
-      "movl           4(%3), %%ecx\n"
-      "lock cmpxchg8b %1\n"
-      "sete           %0\n"
-      "popl           %%ebx"
-      : "=R" (status), "+m" (*addr)
-      : "A"(old_value), "D" (&new_value)
-      : "%ecx"
-      );
-  return status != 0;
+  // The compiler does the right job and works better than inline assembly, especially with -O0
+  // compilation.
+  return __sync_bool_compare_and_swap(addr, old_value, new_value);
 #else
 #error Unexpected architecture
 #endif
diff --git a/src/atomic_integer.h b/src/atomic_integer.h
index 188f4c2..c4a8de9 100644
--- a/src/atomic_integer.h
+++ b/src/atomic_integer.h
@@ -71,7 +71,7 @@
     return success;
   }
  private:
-  int32_t value_;
+  volatile int32_t value_;
 };
 
 }
diff --git a/src/barrier_test.cc b/src/barrier_test.cc
index 093ba35..55d2d3d 100644
--- a/src/barrier_test.cc
+++ b/src/barrier_test.cc
@@ -88,7 +88,7 @@
   // at this point.
   EXPECT_EQ(num_threads, count2);
   // Wait for all the threads to finish.
-  thread_pool.Wait(self);
+  thread_pool.Wait(self, true, false);
   // All three counts should be equal to num_threads now.
   EXPECT_EQ(count1, count2);
   EXPECT_EQ(count2, count3);
diff --git a/src/base/macros.h b/src/base/macros.h
index 8579872..847105d 100644
--- a/src/base/macros.h
+++ b/src/base/macros.h
@@ -136,6 +136,12 @@
 #define ALWAYS_INLINE  __attribute__ ((always_inline))
 #endif
 
+#if defined (__APPLE__)
+#define HOT_ATTR
+#else
+#define HOT_ATTR __attribute__ ((hot))
+#endif
+
 // bionic and glibc both have TEMP_FAILURE_RETRY, but Mac OS' libc doesn't.
 #ifndef TEMP_FAILURE_RETRY
 #define TEMP_FAILURE_RETRY(exp) ({ \
diff --git a/src/base/mutex.cc b/src/base/mutex.cc
index a2851e5..fbec826 100644
--- a/src/base/mutex.cc
+++ b/src/base/mutex.cc
@@ -777,6 +777,11 @@
 }
 
 void ConditionVariable::Wait(Thread* self) {
+  guard_.CheckSafeToWait(self);
+  WaitHoldingLocks(self);
+}
+
+void ConditionVariable::WaitHoldingLocks(Thread* self) {
   DCHECK(self == NULL || self == Thread::Current());
   guard_.AssertExclusiveHeld(self);
   unsigned int old_recursion_count = guard_.recursion_count_;
@@ -811,6 +816,7 @@
 void ConditionVariable::TimedWait(Thread* self, int64_t ms, int32_t ns) {
   DCHECK(self == NULL || self == Thread::Current());
   guard_.AssertExclusiveHeld(self);
+  guard_.CheckSafeToWait(self);
   unsigned int old_recursion_count = guard_.recursion_count_;
 #if ART_USE_FUTEXES
   timespec rel_ts;
diff --git a/src/base/mutex.h b/src/base/mutex.h
index a3efd5c..24df572 100644
--- a/src/base/mutex.h
+++ b/src/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 {
@@ -141,7 +141,7 @@
 
   // Assert that the Mutex is exclusively held by the current thread.
   void AssertExclusiveHeld(const Thread* self) {
-    if (kDebugLocking && !gAborting) {
+    if (kDebugLocking && (gAborting == 0)) {
       CHECK(IsExclusiveHeld(self)) << *this;
     }
   }
@@ -149,7 +149,7 @@
 
   // Assert that the Mutex is not held by the current thread.
   void AssertNotHeldExclusive(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking && (gAborting == 0)) {
       CHECK(!IsExclusiveHeld(self)) << *this;
     }
   }
@@ -238,7 +238,7 @@
 
   // Assert the current thread has exclusive access to the ReaderWriterMutex.
   void AssertExclusiveHeld(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking & (gAborting == 0)) {
       CHECK(IsExclusiveHeld(self)) << *this;
     }
   }
@@ -246,8 +246,8 @@
 
   // Assert the current thread doesn't have exclusive access to the ReaderWriterMutex.
   void AssertNotExclusiveHeld(const Thread* self) {
-    if (kDebugLocking) {
-      CHECK(!IsExclusiveHeld(self));
+    if (kDebugLocking & (gAborting == 0)) {
+      CHECK(!IsExclusiveHeld(self)) << *this;
     }
   }
   void AssertNotWriterHeld(const Thread* self) { AssertNotExclusiveHeld(self); }
@@ -257,7 +257,7 @@
 
   // Assert the current thread has shared access to the ReaderWriterMutex.
   void AssertSharedHeld(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking  & (gAborting == 0)) {
       // TODO: we can only assert this well when self != NULL.
       CHECK(IsSharedHeld(self) || self == NULL) << *this;
     }
@@ -267,7 +267,7 @@
   // Assert the current thread doesn't hold this ReaderWriterMutex either in shared or exclusive
   // mode.
   void AssertNotHeld(const Thread* self) {
-    if (kDebugLocking) {
+    if (kDebugLocking && (gAborting == 0)) {
       CHECK(!IsSharedHeld(self)) << *this;
     }
   }
@@ -307,6 +307,10 @@
   //       pointer copy, thereby defeating annotalysis.
   void Wait(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
   void TimedWait(Thread* self, int64_t ms, int32_t ns) NO_THREAD_SAFETY_ANALYSIS;
+  // Variant of Wait that should be used with caution. Doesn't validate that no mutexes are held
+  // when waiting.
+  // TODO: remove this.
+  void WaitHoldingLocks(Thread* self) NO_THREAD_SAFETY_ANALYSIS;
 
  private:
   const char* const name_;
diff --git a/src/base/stringpiece.cc b/src/base/stringpiece.cc
index 715d964..47140e3 100644
--- a/src/base/stringpiece.cc
+++ b/src/base/stringpiece.cc
@@ -21,12 +21,6 @@
 
 namespace art {
 
-bool operator<(const StringPiece& x, const StringPiece& y) {
-  const int r = memcmp(x.data(), y.data(),
-                       std::min(x.size(), y.size()));
-  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
-}
-
 void StringPiece::CopyToString(std::string* target) const {
   target->assign(ptr_, length_);
 }
diff --git a/src/base/stringpiece.h b/src/base/stringpiece.h
index 193f5f7..3664218 100644
--- a/src/base/stringpiece.h
+++ b/src/base/stringpiece.h
@@ -188,7 +188,11 @@
   return !(x == y);
 }
 
-bool operator<(const StringPiece& x, const StringPiece& y);
+inline bool operator<(const StringPiece& x, const StringPiece& y) {
+  const int r = memcmp(x.data(), y.data(),
+                       std::min(x.size(), y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
 
 inline bool operator>(const StringPiece& x, const StringPiece& y) {
   return y < x;
diff --git a/src/base/timing_logger.cc b/src/base/timing_logger.cc
index 6d5586c..c7cbbe5 100644
--- a/src/base/timing_logger.cc
+++ b/src/base/timing_logger.cc
@@ -82,7 +82,7 @@
 }
 
 void CumulativeLogger::SetName(const std::string& name) {
-  name_ = name;
+  name_.assign(name);
 }
 
 void CumulativeLogger::Start() {
@@ -123,13 +123,40 @@
   }
 }
 
+void CumulativeLogger::AddNewLogger(const base::NewTimingLogger &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;
+  if (kIsDebugBuild && splits.size() != histograms_.size()) {
+    LOG(ERROR) << "Mismatch in splits.";
+    typedef std::vector<Histogram<uint64_t> *>::const_iterator It2;
+    It it = splits.begin();
+    It2 it2 = histograms_.begin();
+    while ((it != splits.end()) && (it2 != histograms_.end())) {
+      if (it != splits.end()) {
+        LOG(ERROR) << "\tsplit: " << it->second;
+        ++it;
+      }
+      if (it2 != histograms_.end()) {
+        LOG(ERROR) << "\tpreviously record: " << (*it2)->Name();
+        ++it2;
+      }
+    }
+  }
+  for (It it = splits.begin(), end = splits.end(); it != end; ++it) {
+    std::pair<uint64_t, const char*> split = *it;
+    uint64_t split_time = split.first;
+    const char* split_name = split.second;
+    AddPair(split_name, split_time);
+  }
+}
+
 void CumulativeLogger::Dump(std::ostream &os) {
   MutexLock mu(Thread::Current(), lock_);
   DumpHistogram(os);
 }
 
 void CumulativeLogger::AddPair(const std::string &label, uint64_t delta_time) {
-
   // Convert delta time to microseconds so that we don't overflow our counters.
   delta_time /= kAdjust;
   if (index_ >= histograms_.size()) {
@@ -154,4 +181,89 @@
   os << "Done Dumping histograms \n";
 }
 
+
+namespace base {
+
+NewTimingLogger::NewTimingLogger(const char* name, bool precise, bool verbose)
+    : name_(name), precise_(precise), verbose_(verbose),
+      current_split_(NULL), current_split_start_ns_(0) {
+}
+
+void NewTimingLogger::Reset() {
+  current_split_ = NULL;
+  current_split_start_ns_ = 0;
+  splits_.clear();
+}
+
+void NewTimingLogger::StartSplit(const char* new_split_label) {
+  DCHECK(current_split_ == NULL);
+  if (verbose_) {
+    LOG(INFO) << "Begin: " << new_split_label;
+  }
+  current_split_ = new_split_label;
+  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) {
+  DCHECK(current_split_ != NULL);
+  uint64_t current_time = NanoTime();
+  uint64_t split_time = current_time - current_split_start_ns_;
+  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;
+  current_split_start_ns_ = current_time;
+}
+
+void NewTimingLogger::EndSplit() {
+  DCHECK(current_split_ != NULL);
+  uint64_t current_time = NanoTime();
+  uint64_t split_time = current_time - current_split_start_ns_;
+  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 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) {
+    std::pair<uint64_t, const char*> split = *it;
+    total_ns += split.first;
+  }
+  return total_ns;
+}
+
+void NewTimingLogger::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;
+  for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
+    std::pair<uint64_t, const char*> split = *it;
+    uint64_t split_time = split.first;
+    longest_split = std::max(longest_split, split_time);
+    total_ns += split_time;
+  }
+  // Compute which type of unit we will use for printing the timings.
+  TimeUnit tu = GetAppropriateTimeUnit(longest_split);
+  uint64_t divisor = GetNsToTimeUnitDivisor(tu);
+  // Print formatted splits.
+  for (It it = splits_.begin(), end = splits_.end(); it != end; ++it) {
+    std::pair<uint64_t, const char*> split = *it;
+    uint64_t split_time = split.first;
+    if (!precise_ && divisor >= 1000) {
+      // Make the fractional part 0.
+      split_time -= split_time % (divisor / 1000);
+    }
+    os << name_ << ": " << std::setw(8) << FormatDuration(split_time, tu) << " "
+       << split.second << "\n";
+  }
+  os << name_ << ": end, " << NsToMs(total_ns) << " ms\n";
+}
+
+}  // namespace base
 }  // namespace art
diff --git a/src/base/timing_logger.h b/src/base/timing_logger.h
index bbcc286..65732b1 100644
--- a/src/base/timing_logger.h
+++ b/src/base/timing_logger.h
@@ -45,6 +45,10 @@
   friend class CumulativeLogger;
 };
 
+namespace base {
+  class NewTimingLogger;
+}  // namespace base
+
 class CumulativeLogger {
 
  public:
@@ -61,6 +65,7 @@
   // 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_);
 
  private:
 
@@ -79,6 +84,59 @@
   DISALLOW_COPY_AND_ASSIGN(CumulativeLogger);
 };
 
+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 {
+ public:
+  explicit NewTimingLogger(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);
+
+  // Ends the current split and starts the one given by the label.
+  void NewSplit(const char* new_split_label);
+
+  // Ends the current split and records the end time.
+  void EndSplit();
+
+  uint64_t GetTotalNs() const;
+
+  void Dump(std::ostream& os) const;
+
+  const std::vector<std::pair<uint64_t, const char*> >& GetSplits() const {
+    return splits_;
+  }
+
+ protected:
+  // The name of the timing logger.
+  const std::string name_;
+
+  // Do we want to print the exactly recorded split (true) or round down to the time unit being
+  // used (false).
+  const bool precise_;
+
+  // Verbose logging.
+  const bool verbose_;
+
+  // The name of the current split.
+  const char* current_split_;
+
+  // The nanosecond time the current split started on.
+  uint64_t current_split_start_ns_;
+
+  // Splits are nanosecond times and split names.
+  std::vector<std::pair<uint64_t, const char*> > splits_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NewTimingLogger);
+};
+
+}  // namespace base
 }  // namespace art
 
 #endif  // ART_SRC_TIMING_LOGGER_H_
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 19f8abf..403a2eb 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -23,7 +23,7 @@
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
-#include "gc/space.h"
+#include "gc/space/space.h"
 #include "mirror/class-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/abstract_method-inl.h"
@@ -36,7 +36,7 @@
 #include "thread.h"
 
 #define LIBCORE_CPP_JNI_HELPERS
-#include <JNIHelp.h> // from libcore
+#include <JNIHelp.h>  // from libcore
 #undef LIBCORE_CPP_JNI_HELPERS
 
 namespace art {
@@ -1215,7 +1215,10 @@
   }
 
   static void FatalError(JNIEnv* env, const char* msg) {
-    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
+    // The JNI specification doesn't say it's okay to call FatalError with a pending exception,
+    // but you're about to abort anyway, and it's quite likely that you have a pending exception,
+    // and it's not unimaginable that you don't know that you do. So we allow it.
+    CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_NullableUtf, "Eu", env, msg);
     baseEnv(env)->FatalError(env, msg);
     CHECK_JNI_EXIT_VOID();
   }
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 70c7ff3..68d0fbb 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -34,8 +34,10 @@
 #include "class_linker-inl.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "leb128.h"
@@ -44,7 +46,7 @@
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/iftable-inl.h"
 #include "mirror/abstract_method.h"
@@ -63,8 +65,6 @@
 #include "ScopedLocalRef.h"
 #include "scoped_thread_state_change.h"
 #include "sirt_ref.h"
-#include "gc/space.h"
-#include "gc/space_bitmap.h"
 #include "stack_indirect_reference_table.h"
 #include "thread.h"
 #include "UniquePtr.h"
@@ -74,7 +74,9 @@
 
 namespace art {
 
-void artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
 
 static void ThrowNoClassDefFoundError(const char* fmt, ...)
     __attribute__((__format__(__printf__, 1, 2)))
@@ -195,12 +197,14 @@
 
 ClassLinker::ClassLinker(InternTable* intern_table)
     // dex_lock_ is recursive as it may be used in stack dumping.
-    : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel, true),
+    : dex_lock_("ClassLinker dex lock", kDefaultMutexLevel),
       class_roots_(NULL),
       array_iftable_(NULL),
       init_done_(false),
       is_dirty_(false),
-      intern_table_(intern_table) {
+      intern_table_(intern_table),
+      portable_resolution_trampoline_(NULL),
+      quick_resolution_trampoline_(NULL) {
   CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
 }
 
@@ -212,7 +216,7 @@
 
   // java_lang_Class comes first, it's needed for AllocClass
   Thread* self = Thread::Current();
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   SirtRef<mirror::Class>
       java_lang_Class(self,
                       down_cast<mirror::Class*>(heap->AllocObject(self, NULL,
@@ -545,7 +549,7 @@
   CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_,
            GetClassRoot(kJavaLangObject)->GetDexTypeIndex());
 
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   heap->SetReferenceOffsets(referent->GetOffset(),
                             queue->GetOffset(),
                             queueNext->GetOffset(),
@@ -591,7 +595,7 @@
 
   const char* class_path = Runtime::Current()->GetClassPathString().c_str();
 
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   std::string boot_image_option_string("--boot-image=");
   boot_image_option_string += heap->GetImageSpace()->GetImageFilename();
   const char* boot_image_option = boot_image_option_string.c_str();
@@ -662,22 +666,22 @@
 }
 
 void ClassLinker::RegisterOatFile(const OatFile& oat_file) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterOatFileLocked(oat_file);
 }
 
 void ClassLinker::RegisterOatFileLocked(const OatFile& oat_file) {
-  dex_lock_.AssertHeld(Thread::Current());
-#ifndef NDEBUG
-  for (size_t i = 0; i < oat_files_.size(); ++i) {
-    CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+  dex_lock_.AssertExclusiveHeld(Thread::Current());
+  if (kIsDebugBuild) {
+    for (size_t i = 0; i < oat_files_.size(); ++i) {
+      CHECK_NE(&oat_file, oat_files_[i]) << oat_file.GetLocation();
+    }
   }
-#endif
   oat_files_.push_back(&oat_file);
 }
 
-OatFile* ClassLinker::OpenOat(const ImageSpace* space) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+OatFile* ClassLinker::OpenOat(const gc::space::ImageSpace* space) {
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   const Runtime* runtime = Runtime::Current();
   const ImageHeader& image_header = space->GetImageHeader();
   // Grab location but don't use Object::AsString as we haven't yet initialized the roots to
@@ -708,7 +712,7 @@
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return FindOpenedOatFileFromDexLocation(dex_file.GetLocation());
 }
 
@@ -724,10 +728,9 @@
   return NULL;
 }
 
-static const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
-                                               uint32_t dex_location_checksum,
-                                               const std::string& oat_location)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+const DexFile* ClassLinker::FindDexFileInOatLocation(const std::string& dex_location,
+                                                     uint32_t dex_location_checksum,
+                                                     const std::string& oat_location) {
   UniquePtr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL));
   if (oat_file.get() == NULL) {
     return NULL;
@@ -748,13 +751,13 @@
   if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
     return NULL;
   }
-  runtime->GetClassLinker()->RegisterOatFile(*oat_file.release());
+  RegisterOatFileLocked(*oat_file.release());
   return oat_dex_file->OpenDexFile();
 }
 
 const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(const std::string& dex_location,
                                                               const std::string& oat_location) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   return FindOrCreateOatFileForDexLocationLocked(dex_location, oat_location);
 }
 
@@ -856,7 +859,7 @@
 }
 
 const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const std::string& dex_location) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
 
   const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location);
   if (open_oat_file != NULL) {
@@ -923,7 +926,7 @@
 }
 
 const OatFile* ClassLinker::FindOatFileFromOatLocation(const std::string& oat_location) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return FindOatFileFromOatLocationLocked(oat_location);
 }
 
@@ -944,13 +947,15 @@
   VLOG(startup) << "ClassLinker::InitFromImage entering";
   CHECK(!init_done_);
 
-  Heap* heap = Runtime::Current()->GetHeap();
-  ImageSpace* space = heap->GetImageSpace();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  gc::space::ImageSpace* space = heap->GetImageSpace();
   OatFile* oat_file = OpenOat(space);
   CHECK(oat_file != NULL) << "Failed to open oat file for image";
   CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
   CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0U);
   CHECK(oat_file->GetOatHeader().GetImageFileLocation().empty());
+  portable_resolution_trampoline_ = oat_file->GetOatHeader().GetPortableResolutionTrampoline();
+  quick_resolution_trampoline_ = oat_file->GetOatHeader().GetQuickResolutionTrampoline();
   mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   mirror::ObjectArray<mirror::DexCache>* dex_caches =
       dex_caches_object->AsObjectArray<mirror::DexCache>();
@@ -1037,17 +1042,14 @@
     return;
   }
 
-  // Check if object is a method without its code set and point it to the resolution trampoline.
+  // Set entry points to interpreter for methods in interpreter only mode.
   if (obj->IsMethod()) {
     mirror::AbstractMethod* method = obj->AsMethod();
-    // Install entry point from interpreter.
-    if (method->GetEntryPointFromCompiledCode() == NULL && !method->IsNative() && !method->IsProxyMethod()) {
-      method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
-    } else {
-      method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
-    }
-    if (method->GetEntryPointFromCompiledCode() == NULL) {
-      method->SetEntryPointFromCompiledCode(GetResolutionTrampoline());
+    if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) {
+      method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
+      if (method != Runtime::Current()->GetResolutionMethod()) {
+        method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
+      }
     }
   }
 }
@@ -1055,18 +1057,18 @@
 // Keep in sync with InitCallback. Anything we visit, we need to
 // reinit references to when reinitializing a ClassLinker from a
 // mapped image.
-void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg) {
+void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) {
   visitor(class_roots_, arg);
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, dex_lock_);
+    ReaderMutexLock mu(self, dex_lock_);
     for (size_t i = 0; i < dex_caches_.size(); i++) {
       visitor(dex_caches_[i], arg);
     }
   }
 
   {
-    MutexLock mu(self, *Locks::classlinker_classes_lock_);
+    ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
     typedef Table::const_iterator It;  // TODO: C++0x auto
     for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
       visitor(it->second, arg);
@@ -1077,11 +1079,13 @@
   }
 
   visitor(array_iftable_, arg);
-  is_dirty_ = false;
+  if (clean_dirty) {
+    is_dirty_ = false;
+  }
 }
 
 void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) const {
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
     if (!visitor(it->second, arg)) {
@@ -1133,7 +1137,7 @@
 }
 
 mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) {
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   mirror::Class* dex_cache_class = GetClassRoot(kJavaLangDexCache);
   SirtRef<mirror::DexCache> dex_cache(self,
                               down_cast<mirror::DexCache*>(heap->AllocObject(self, dex_cache_class,
@@ -1186,7 +1190,7 @@
 mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class,
                                        size_t class_size) {
   DCHECK_GE(class_size, sizeof(mirror::Class));
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   SirtRef<mirror::Class> klass(self,
                        heap->AllocObject(self, java_lang_Class, class_size)->AsClass());
   klass->SetPrimitiveType(Primitive::kPrimNot);  // default to not being primitive
@@ -1608,14 +1612,16 @@
   oat_method.LinkMethod(method.get());
 
   // Install entry point from interpreter.
-  if (method->GetEntryPointFromCompiledCode() == NULL && !method->IsNative() &&
-      !method->IsProxyMethod()) {
-    method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter);
+  Runtime* runtime = Runtime::Current();
+  bool enter_interpreter = method->GetEntryPointFromCompiledCode() == NULL ||
+                           (runtime->GetInstrumentation()->InterpretOnly() &&
+                           !method->IsNative() && !method->IsProxyMethod());
+  if (enter_interpreter) {
+    method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry);
   } else {
     method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry);
   }
 
-  Runtime* runtime = Runtime::Current();
   if (method->IsAbstract()) {
     method->SetEntryPointFromCompiledCode(GetAbstractMethodErrorStub());
     return;
@@ -1623,7 +1629,7 @@
 
   if (method->IsStatic() && !method->IsConstructor()) {
     // For static methods excluding the class initializer, install the trampoline.
-    method->SetEntryPointFromCompiledCode(GetResolutionTrampoline());
+    method->SetEntryPointFromCompiledCode(GetResolutionTrampoline(runtime->GetClassLinker()));
   }
 
   if (method->IsNative()) {
@@ -1631,8 +1637,8 @@
     method->UnregisterNative(Thread::Current());
   }
 
-  if (method->GetEntryPointFromCompiledCode() == NULL) {
-    // No code? You must mean to go into the interpreter.
+  if (enter_interpreter) {
+    // Set entry point from compiled code if there's no code or in interpreter only mode.
     method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint());
   }
 
@@ -1807,7 +1813,7 @@
 }
 
 bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
-  dex_lock_.AssertHeld(Thread::Current());
+  dex_lock_.AssertSharedHeld(Thread::Current());
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     if (dex_caches_[i]->GetDexFile() == &dex_file) {
       return true;
@@ -1817,12 +1823,12 @@
 }
 
 bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return IsDexFileRegisteredLocked(dex_file);
 }
 
 void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
-  dex_lock_.AssertHeld(Thread::Current());
+  dex_lock_.AssertExclusiveHeld(Thread::Current());
   CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()));
   dex_caches_.push_back(dex_cache.get());
@@ -1833,7 +1839,7 @@
 void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, dex_lock_);
+    ReaderMutexLock mu(self, dex_lock_);
     if (IsDexFileRegisteredLocked(dex_file)) {
       return;
     }
@@ -1843,7 +1849,7 @@
   // get to a suspend point.
   SirtRef<mirror::DexCache> dex_cache(self, AllocDexCache(self, dex_file));
   {
-    MutexLock mu(self, dex_lock_);
+    WriterMutexLock mu(self, dex_lock_);
     if (IsDexFileRegisteredLocked(dex_file)) {
       return;
     }
@@ -1852,12 +1858,12 @@
 }
 
 void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterDexFileLocked(dex_file, dex_cache);
 }
 
 mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   // Search assuming unique-ness of dex file.
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     mirror::DexCache* dex_cache = dex_caches_[i];
@@ -1883,7 +1889,7 @@
 }
 
 void ClassLinker::FixupDexCaches(mirror::AbstractMethod* resolution_method) const {
-  MutexLock mu(Thread::Current(), dex_lock_);
+  ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
     dex_caches_[i]->Fixup(resolution_method);
   }
@@ -2017,15 +2023,16 @@
   CHECK(array_iftable_ != NULL);
   new_class->SetIfTable(array_iftable_);
 
-  // Inherit access flags from the component type.  Arrays can't be
-  // used as a superclass or interface, so we want to add "final"
+  // Inherit access flags from the component type.
+  int access_flags = new_class->GetComponentType()->GetAccessFlags();
+  // Lose any implementation detail flags; in particular, arrays aren't finalizable.
+  access_flags &= kAccJavaFlagsMask;
+  // Arrays can't be used as a superclass or interface, so we want to add "abstract final"
   // and remove "interface".
-  //
-  // Don't inherit any non-standard flags (e.g., kAccFinal)
-  // from component_type.  We assume that the array class does not
-  // override finalize().
-  new_class->SetAccessFlags(((new_class->GetComponentType()->GetAccessFlags() &
-                             ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask);
+  access_flags |= kAccAbstract | kAccFinal;
+  access_flags &= ~kAccInterface;
+
+  new_class->SetAccessFlags(access_flags);
 
   mirror::Class* existing = InsertClass(descriptor, new_class.get(), false);
   if (existing == NULL) {
@@ -2068,7 +2075,8 @@
   return NULL;
 }
 
-mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass, bool image_class) {
+mirror::Class* ClassLinker::InsertClass(const StringPiece& descriptor, mirror::Class* klass,
+                                        bool image_class) {
   if (VLOG_IS_ON(class_linker)) {
     mirror::DexCache* dex_cache = klass->GetDexCache();
     std::string source;
@@ -2079,9 +2087,10 @@
     LOG(INFO) << "Loaded class " << descriptor << source;
   }
   size_t hash = StringPieceHash()(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   Table& classes = image_class ? image_classes_ : classes_;
-  mirror::Class* existing = LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
+  mirror::Class* existing =
+      LookupClassLocked(descriptor.data(), klass->GetClassLoader(), hash, classes);
 #ifndef NDEBUG
   // Check we don't have the class in the other table in error
   Table& other_classes = image_class ? classes_ : image_classes_;
@@ -2090,6 +2099,7 @@
   if (existing != NULL) {
     return existing;
   }
+  Runtime::Current()->GetHeap()->VerifyObject(klass);
   classes.insert(std::make_pair(hash, klass));
   Dirty();
   return NULL;
@@ -2097,7 +2107,7 @@
 
 bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
   size_t hash = Hash(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   typedef Table::iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
   ClassHelper kh;
@@ -2125,7 +2135,7 @@
 mirror::Class* ClassLinker::LookupClass(const char* descriptor,
                                         const mirror::ClassLoader* class_loader) {
   size_t hash = Hash(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   // TODO: determine if its better to search classes_ or image_classes_ first
   mirror::Class* klass = NULL;
   // Use image class only if the class_loader is null.
@@ -2165,7 +2175,7 @@
 void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& classes) {
   classes.clear();
   size_t hash = Hash(descriptor);
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   typedef Table::const_iterator It;  // TODO: C++0x auto
   // TODO: determine if its better to search classes_ or image_classes_ first
   ClassHelper kh(NULL, this);
@@ -2243,7 +2253,6 @@
   const DexFile& dex_file = *klass->GetDexCache()->GetDexFile();
   mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
   bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
-  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   if (oat_file_class_status == mirror::Class::kStatusError) {
     LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass)
                  << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
@@ -2252,9 +2261,11 @@
     klass->SetStatus(mirror::Class::kStatusError);
     return;
   }
+  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
   std::string error_msg;
   if (!preverified) {
-    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, Runtime::Current()->IsCompiler());
+    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg,
+                                                             Runtime::Current()->IsCompiler());
   }
   if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
     if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
@@ -2286,6 +2297,15 @@
     ThrowVerifyError(klass, "%s", error_msg.c_str());
     klass->SetStatus(mirror::Class::kStatusError);
   }
+  if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
+    // Class is verified so we don't need to do any access check in its methods.
+    // Let the interpreter know it by setting the kAccPreverified flag onto each
+    // method.
+    // Note: we're going here during compilation and at runtime. When we set the
+    // kAccPreverified flag when compiling image classes, the flag is recorded
+    // in the image and is set when loading the image.
+    klass->SetPreverifiedFlagOnAllMethods();
+  }
 }
 
 bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
@@ -2499,7 +2519,7 @@
   mirror::DexCache* dex_cache = NULL;
   {
     mirror::ObjectArray<mirror::Class>* resolved_types = proxy_method->GetDexCacheResolvedTypes();
-    MutexLock mu(Thread::Current(), dex_lock_);
+    ReaderMutexLock mu(Thread::Current(), dex_lock_);
     for (size_t i = 0; i != dex_caches_.size(); ++i) {
       if (dex_caches_[i]->GetResolvedTypes() == resolved_types) {
         dex_cache = dex_caches_[i];
@@ -3880,7 +3900,7 @@
   // lock held, because it might need to resolve a field's type, which would try to take the lock.
   std::vector<mirror::Class*> all_classes;
   {
-    MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+    ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
     typedef Table::const_iterator It;  // TODO: C++0x auto
     for (It it = classes_.begin(), end = classes_.end(); it != end; ++it) {
       all_classes.push_back(it->second);
@@ -3896,13 +3916,13 @@
 }
 
 void ClassLinker::DumpForSigQuit(std::ostream& os) const {
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   os << "Loaded classes: " << image_classes_.size() << " image classes; "
      << classes_.size() << " allocated classes\n";
 }
 
 size_t ClassLinker::NumLoadedClasses() const {
-  MutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   return classes_.size() + image_classes_.size();
 }
 
diff --git a/src/class_linker.h b/src/class_linker.h
index d41373c..df33672 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -29,6 +29,11 @@
 #include "oat_file.h"
 
 namespace art {
+namespace gc {
+namespace space {
+  class ImageSpace;
+}  // namespace space
+}  // namespace gc
 namespace mirror {
   class ClassLoader;
   class DexCache;
@@ -37,7 +42,7 @@
   template<class T> class ObjectArray;
   class StackTraceElement;
 }  // namespace mirror
-class ImageSpace;
+
 class InternTable;
 class ObjectLock;
 template<class T> class SirtRef;
@@ -219,7 +224,7 @@
   void VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* arg) const
       LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
 
-  void VisitRoots(RootVisitor* visitor, void* arg)
+  void VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty)
       LOCKS_EXCLUDED(Locks::classlinker_classes_lock_, dex_lock_);
 
   mirror::DexCache* FindDexCache(const DexFile& dex_file) const
@@ -240,7 +245,7 @@
       LOCKS_EXCLUDED(dex_lock_);
 
   const OatFile* FindOatFileFromOatLocationLocked(const std::string& location)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+      SHARED_LOCKS_REQUIRED(dex_lock_);
 
   // Finds the oat file for a dex location, generating the oat file if
   // it is missing or out of date. Returns the DexFile from within the
@@ -334,6 +339,14 @@
     is_dirty_ = true;
   }
 
+  const void* GetPortableResolutionTrampoline() const {
+    return portable_resolution_trampoline_;
+  }
+
+  const void* GetQuickResolutionTrampoline() const {
+    return quick_resolution_trampoline_;
+  }
+
  private:
   explicit ClassLinker(InternTable*);
 
@@ -346,7 +359,7 @@
 
   // Initialize class linker from one or more images.
   void InitFromImage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  OatFile* OpenOat(const ImageSpace* space)
+  OatFile* OpenOat(const gc::space::ImageSpace* space)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void InitFromImageCallback(mirror::Object* obj, void* arg)
@@ -420,7 +433,7 @@
   void RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_);
   void RegisterOatFileLocked(const OatFile& oat_file) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
 
@@ -489,10 +502,15 @@
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const OatFile* FindOpenedOatFileFromDexLocation(const std::string& dex_location)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
+  const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
+      SHARED_LOCKS_REQUIRED(dex_lock_);
+  const DexFile* FindDexFileInOatLocation(const std::string& dex_location,
+                                          uint32_t dex_location_checksum,
+                                          const std::string& oat_location)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
-      EXCLUSIVE_LOCKS_REQUIRED(dex_lock_);
+
   const DexFile* VerifyAndOpenDexFileFromOatFile(const OatFile* oat_file,
                                                  const std::string& dex_location,
                                                  uint32_t dex_location_checksum)
@@ -508,7 +526,7 @@
 
   std::vector<const DexFile*> boot_class_path_;
 
-  mutable Mutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::vector<mirror::DexCache*> dex_caches_ GUARDED_BY(dex_lock_);
   std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
 
@@ -522,8 +540,7 @@
 
   mirror::Class* LookupClassLocked(const char* descriptor, const mirror::ClassLoader* class_loader,
                                    size_t hash, const Table& classes)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::classlinker_classes_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::classlinker_classes_lock_);
 
   // indexes into class_roots_.
   // needs to be kept in sync with class_roots_descriptors_.
@@ -595,6 +612,9 @@
 
   InternTable* intern_table_;
 
+  const void* portable_resolution_trampoline_;
+  const void* quick_resolution_trampoline_;
+
   friend class CommonTest;
   friend class ImageWriter;  // for GetClassRoots
   friend class ObjectTest;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 73bdc61..e5844b0 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -22,7 +22,7 @@
 #include "class_linker-inl.h"
 #include "common_test.h"
 #include "dex_file.h"
-#include "heap.h"
+#include "gc/heap.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache.h"
 #include "mirror/field-inl.h"
@@ -90,6 +90,7 @@
     EXPECT_TRUE(primitive->GetVTable() == NULL);
     EXPECT_EQ(0, primitive->GetIfTableCount());
     EXPECT_TRUE(primitive->GetIfTable() == NULL);
+    EXPECT_EQ(kAccPublic | kAccFinal | kAccAbstract, primitive->GetAccessFlags());
   }
 
   void AssertArrayClass(const std::string& array_descriptor,
@@ -100,6 +101,7 @@
     ClassHelper array_component_ch(array->GetComponentType());
     EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor());
     EXPECT_EQ(class_loader, array->GetClassLoader());
+    EXPECT_EQ(kAccFinal | kAccAbstract, (array->GetAccessFlags() & (kAccFinal | kAccAbstract)));
     AssertArrayClass(array_descriptor, array);
   }
 
@@ -331,7 +333,7 @@
       const char* descriptor = dex->GetTypeDescriptor(type_id);
       AssertDexFileClass(class_loader, descriptor);
     }
-    class_linker_->VisitRoots(TestRootVisitor, NULL);
+    class_linker_->VisitRoots(TestRootVisitor, NULL, false);
     // Verify the dex cache has resolution methods in all resolved method slots
     DexCache* dex_cache = class_linker_->FindDexCache(*dex);
     ObjectArray<AbstractMethod>* resolved_methods = dex_cache->GetResolvedMethods();
diff --git a/src/common_test.h b/src/common_test.h
index 3baa77c..88da8a2 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -28,8 +28,8 @@
 #include "class_linker.h"
 #include "compiler/driver/compiler_driver.h"
 #include "dex_file-inl.h"
+#include "gc/heap.h"
 #include "gtest/gtest.h"
-#include "heap.h"
 #include "instruction_set.h"
 #include "mirror/class_loader.h"
 #include "oat_file.h"
@@ -296,8 +296,8 @@
     boot_class_path_.push_back(java_lang_dex_file_);
     boot_class_path_.push_back(conscrypt_file_);
 
-    std::string min_heap_string(StringPrintf("-Xms%zdm", Heap::kDefaultInitialSize / MB));
-    std::string max_heap_string(StringPrintf("-Xmx%zdm", Heap::kDefaultMaximumSize / MB));
+    std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
+    std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
 
     Runtime::Options options;
     options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
@@ -313,47 +313,50 @@
     // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
     // give it away now and then switch to a more managable ScopedObjectAccess.
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
-    // Whilst we're in native take the opportunity to initialize well known classes.
-    WellKnownClasses::InitClasses(Thread::Current()->GetJniEnv());
-    ScopedObjectAccess soa(Thread::Current());
-    ASSERT_TRUE(runtime_.get() != NULL);
-    class_linker_ = runtime_->GetClassLinker();
+    {
+      ScopedObjectAccess soa(Thread::Current());
+      ASSERT_TRUE(runtime_.get() != NULL);
+      class_linker_ = runtime_->GetClassLinker();
 
-    InstructionSet instruction_set = kNone;
+      InstructionSet instruction_set = kNone;
 #if defined(__arm__)
-    instruction_set = kThumb2;
+      instruction_set = kThumb2;
 #elif defined(__mips__)
-    instruction_set = kMips;
+      instruction_set = kMips;
 #elif defined(__i386__)
-    instruction_set = kX86;
+      instruction_set = kX86;
 #endif
 
-    // TODO: make selectable
+      // TODO: make selectable
 #if defined(ART_USE_PORTABLE_COMPILER)
-    CompilerBackend compiler_backend = kPortable;
+      CompilerBackend compiler_backend = kPortable;
 #else
-    CompilerBackend compiler_backend = kQuick;
+      CompilerBackend compiler_backend = kQuick;
 #endif
 
-    if (!runtime_->HasResolutionMethod()) {
-      runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
-    }
-    for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-      Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
-      if (!runtime_->HasCalleeSaveMethod(type)) {
-        runtime_->SetCalleeSaveMethod(
-            runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
+      if (!runtime_->HasResolutionMethod()) {
+        runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod());
       }
+      for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+        Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+        if (!runtime_->HasCalleeSaveMethod(type)) {
+          runtime_->SetCalleeSaveMethod(
+              runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
+        }
+      }
+      class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+      compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set,
+                                                true, new CompilerDriver::DescriptorSet,
+                                                2, false, true, true));
     }
-    class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
-    image_classes_.reset(new std::set<std::string>);
-    compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, true, 2, false,
-                                              image_classes_.get(), true, true));
+    // We typically don't generate an image in unit tests, disable this optimization by default.
+    compiler_driver_->SetSupportBootImageFixup(false);
 
+    // We're back in native, take the opportunity to initialize well known classes.
+    WellKnownClasses::InitClasses(Thread::Current()->GetJniEnv());
     // Create the heap thread pool so that the GC runs in parallel for tests. Normally, the thread
     // pool is created by the runtime.
     runtime_->GetHeap()->CreateThreadPool();
-
     runtime_->GetHeap()->VerifyHeap();  // Check for heap corruption before the test
   }
 
@@ -389,7 +392,6 @@
     (*icu_cleanup_fn)();
 
     compiler_driver_.reset();
-    image_classes_.reset();
     STLDeleteElements(&opened_dex_files_);
 
     Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
@@ -522,7 +524,6 @@
   // Owned by the runtime
   ClassLinker* class_linker_;
   UniquePtr<CompilerDriver> compiler_driver_;
-  UniquePtr<std::set<std::string> > image_classes_;
 
  private:
   std::vector<const DexFile*> opened_dex_files_;
diff --git a/src/compiler/dex/arena_bit_vector.cc b/src/compiler/dex/arena_bit_vector.cc
index 6f664e5..1fbf774 100644
--- a/src/compiler/dex/arena_bit_vector.cc
+++ b/src/compiler/dex/arena_bit_vector.cc
@@ -113,18 +113,6 @@
   }
 }
 
-// Are we equal to another bit vector?  Note: expandability attributes must also match.
-bool ArenaBitVector::Equal(const ArenaBitVector* src) {
-  if (storage_size_ != src->GetStorageSize() ||
-      expandable_ != src->IsExpandable())
-    return false;
-
-  for (unsigned int idx = 0; idx < storage_size_; idx++) {
-    if (storage_[idx] != src->GetRawStorageWord(idx)) return false;
-  }
-  return true;
-}
-
 // Count the number of bits that are set.
 int ArenaBitVector::NumSetBits()
 {
@@ -136,43 +124,6 @@
   return count;
 }
 
-// Return the position of the next set bit.  -1 means end-of-element reached.
-// TUNING: Hot function.
-int ArenaBitVector::Iterator::Next()
-{
-  // Did anything obviously change since we started?
-  DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
-  DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
-
-  if (bit_index_ >= bit_size_) return -1;
-
-  uint32_t word_index = bit_index_ >> 5;
-  uint32_t end_word_index = bit_size_ >> 5;
-  uint32_t word = bit_storage_[word_index++];
-
-  // Mask out any bits in the first word we've already considered.
-  word &= ~((1 << (bit_index_ & 0x1f))-1);
-
-  for (; word_index <= end_word_index;) {
-    uint32_t bit_pos = bit_index_ & 0x1f;
-    if (word == 0) {
-      bit_index_ += (32 - bit_pos);
-      word = bit_storage_[word_index++];
-      continue;
-    }
-    for (; bit_pos < 32; bit_pos++) {
-      if (word & (1 << bit_pos)) {
-        bit_index_++;
-        return bit_index_ - 1;
-      }
-      bit_index_++;
-    }
-    word = bit_storage_[word_index++];
-  }
-  bit_index_ = bit_size_;
-  return -1;
-}
-
 /*
  * Mark specified number of bits as "set". Cannot set all bits like ClearAll
  * since there might be unused bits - setting those to one will confuse the
diff --git a/src/compiler/dex/arena_bit_vector.h b/src/compiler/dex/arena_bit_vector.h
index f5c471c..a950e82 100644
--- a/src/compiler/dex/arena_bit_vector.h
+++ b/src/compiler/dex/arena_bit_vector.h
@@ -39,7 +39,33 @@
             bit_index_(0),
             bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {};
 
-        int Next();  // Returns -1 when no next.
+        // Return the position of the next set bit.  -1 means end-of-element reached.
+        int Next() {
+          // Did anything obviously change since we started?
+          DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
+          DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
+
+          if (bit_index_ >= bit_size_) return -1;
+
+          uint32_t word_index = bit_index_ / 32;
+          uint32_t word = bit_storage_[word_index];
+          // Mask out any bits in the first word we've already considered.
+          word >>= bit_index_ & 0x1f;
+          if (word == 0) {
+            bit_index_ &= ~0x1f;
+            do {
+              word_index++;
+              if ((word_index * 32) >= bit_size_) {
+                bit_index_ = bit_size_;
+                return -1;
+              }
+              word = bit_storage_[word_index];
+              bit_index_ += 32;
+            } while (word == 0);
+          }
+          bit_index_ += CTZ(word) + 1;
+          return bit_index_ - 1;
+        }
 
         static void* operator new(size_t size, ArenaAllocator* arena) {
           return arena->NewMem(sizeof(ArenaBitVector::Iterator), true,
@@ -73,13 +99,19 @@
     void Copy(ArenaBitVector* src);
     void Intersect(const ArenaBitVector* src2);
     void Union(const ArenaBitVector* src);
-    bool Equal(const ArenaBitVector* src);
+    // Are we equal to another bit vector?  Note: expandability attributes must also match.
+    bool Equal(const ArenaBitVector* src) {
+      return (storage_size_ == src->GetStorageSize()) &&
+        (expandable_ == src->IsExpandable()) &&
+        (memcmp(storage_, src->GetRawStorage(), storage_size_ * 4) == 0);
+    }
     int NumSetBits();
 
     uint32_t GetStorageSize() const { return storage_size_; }
     bool IsExpandable() const { return expandable_; }
     uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; }
     uint32_t* GetRawStorage() { return storage_; }
+    const uint32_t* GetRawStorage() const { return storage_; }
 
   private:
     ArenaAllocator* const arena_;
diff --git a/src/compiler/dex/dataflow_iterator-inl.h b/src/compiler/dex/dataflow_iterator-inl.h
new file mode 100644
index 0000000..b20004d
--- /dev/null
+++ b/src/compiler/dex/dataflow_iterator-inl.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
+#define ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
+
+#include "dataflow_iterator.h"
+
+namespace art {
+
+inline BasicBlock* DataflowIterator::NextBody(bool had_change) {
+  changed_ |= had_change;
+  BasicBlock* res = NULL;
+  if (reverse_) {
+    if (is_iterative_ && changed_ && (idx_ < 0)) {
+      idx_ = start_idx_;
+      changed_ = false;
+    }
+    if (idx_ >= 0) {
+      int bb_id = block_id_list_->Get(idx_--);
+      res = mir_graph_->GetBasicBlock(bb_id);
+    }
+  } else {
+    if (is_iterative_ && changed_ && (idx_ >= end_idx_)) {
+      idx_ = start_idx_;
+      changed_ = false;
+    }
+    if (idx_ < end_idx_) {
+      int bb_id = block_id_list_->Get(idx_++);
+      res = mir_graph_->GetBasicBlock(bb_id);
+    }
+  }
+  return res;
+}
+
+// AllNodes uses the existing GrowableArray iterator, so use different NextBody().
+inline BasicBlock* AllNodesIterator::NextBody(bool had_change) {
+  changed_ |= had_change;
+  BasicBlock* res = NULL;
+  bool keep_looking = true;
+  while (keep_looking) {
+    res = all_nodes_iterator_->Next();
+    if (is_iterative_ && changed_ && (res == NULL)) {
+      all_nodes_iterator_->Reset();
+      changed_ = false;
+    } else if ((res == NULL) || (!res->hidden)) {
+      keep_looking = false;
+    }
+  }
+  return res;
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
diff --git a/src/compiler/dex/dataflow_iterator.cc b/src/compiler/dex/dataflow_iterator.cc
deleted file mode 100644
index bb5b969..0000000
--- a/src/compiler/dex/dataflow_iterator.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dataflow_iterator.h"
-
-namespace art {
-
-  BasicBlock* DataflowIterator::NextBody(bool had_change) {
-    changed_ |= had_change;
-    BasicBlock* res = NULL;
-    if (reverse_) {
-      if (is_iterative_ && changed_ && (idx_ < 0)) {
-        idx_ = start_idx_;
-        changed_ = false;
-      }
-      if (idx_ >= 0) {
-        int bb_id = block_id_list_->Get(idx_--);
-        res = mir_graph_->GetBasicBlock(bb_id);
-      }
-    } else {
-      if (is_iterative_ && changed_ && (idx_ >= end_idx_)) {
-        idx_ = start_idx_;
-        changed_ = false;
-      }
-      if (idx_ < end_idx_) {
-        int bb_id = block_id_list_->Get(idx_++);
-        res = mir_graph_->GetBasicBlock(bb_id);
-      }
-    }
-    return res;
-  }
-
-  // AllNodes uses the existing GrowableArray iterator, so use different NextBody().
-  BasicBlock* AllNodesIterator::NextBody(bool had_change) {
-    changed_ |= had_change;
-    BasicBlock* res = NULL;
-    bool keep_looking = true;
-    while (keep_looking) {
-      res = all_nodes_iterator_->Next();
-      if (is_iterative_ && changed_ && (res == NULL)) {
-        all_nodes_iterator_->Reset();
-        changed_ = false;
-      } else if ((res == NULL) || (!res->hidden)) {
-        keep_looking = false;
-      }
-    }
-    return res;
-  }
-
-}  // namespace art
diff --git a/src/compiler/dex/dataflow_iterator.h b/src/compiler/dex/dataflow_iterator.h
index a4b38bd..12cbf9c 100644
--- a/src/compiler/dex/dataflow_iterator.h
+++ b/src/compiler/dex/dataflow_iterator.h
@@ -71,7 +71,7 @@
             idx_(0),
             changed_(false) {}
 
-      virtual BasicBlock* NextBody(bool had_change);
+      virtual BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
 
       MIRGraph* const mir_graph_;
       const bool is_iterative_;
@@ -86,7 +86,6 @@
 
   class ReachableNodesIterator : public DataflowIterator {
     public:
-
       ReachableNodesIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0,
                              mir_graph->GetNumReachableBlocks(), false) {
@@ -97,7 +96,6 @@
 
   class PreOrderDfsIterator : public DataflowIterator {
     public:
-
       PreOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0,
                              mir_graph->GetNumReachableBlocks(), false) {
@@ -119,7 +117,6 @@
 
   class ReversePostOrderDfsIterator : public DataflowIterator {
     public:
-
       ReversePostOrderDfsIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative,
                              mir_graph->GetNumReachableBlocks() -1, 0, true) {
@@ -130,7 +127,6 @@
 
   class PostOrderDOMIterator : public DataflowIterator {
     public:
-
       PostOrderDOMIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0,
                              mir_graph->GetNumReachableBlocks(), false) {
@@ -141,18 +137,17 @@
 
   class AllNodesIterator : public DataflowIterator {
     public:
-
       AllNodesIterator(MIRGraph* mir_graph, bool is_iterative)
           : DataflowIterator(mir_graph, is_iterative, 0, 0, false) {
         all_nodes_iterator_ =
             new (mir_graph->GetArena()) GrowableArray<BasicBlock*>::Iterator (mir_graph->GetBlockList());
       }
 
-      virtual void Reset() {
+      void Reset() {
         all_nodes_iterator_->Reset();
       }
 
-      virtual BasicBlock* NextBody(bool had_change);
+      BasicBlock* NextBody(bool had_change) ALWAYS_INLINE;
 
     private:
       GrowableArray<BasicBlock*>::Iterator* all_nodes_iterator_;
diff --git a/src/compiler/dex/frontend.cc b/src/compiler/dex/frontend.cc
index ca751ab..e015645 100644
--- a/src/compiler/dex/frontend.cc
+++ b/src/compiler/dex/frontend.cc
@@ -18,7 +18,7 @@
 
 #include "compiler/driver/compiler_driver.h"
 #include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 #if defined(ART_USE_PORTABLE_COMPILER)
 #include "compiler/llvm/llvm_compilation_unit.h"
 #include "compiler/dex/portable/mir_to_gbc.h"
diff --git a/src/compiler/dex/mir_dataflow.cc b/src/compiler/dex/mir_dataflow.cc
index 9f61d73..3b2c1a6 100644
--- a/src/compiler/dex/mir_dataflow.cc
+++ b/src/compiler/dex/mir_dataflow.cc
@@ -16,7 +16,7 @@
 
 #include "compiler_internals.h"
 #include "local_value_numbering.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 
 namespace art {
 
@@ -70,7 +70,7 @@
   DF_DA | DF_REF_A,
 
   // 0D MOVE_EXCEPTION vAA
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 0E RETURN_VOID
   DF_NOP,
@@ -109,13 +109,13 @@
   DF_DA | DF_A_WIDE | DF_SETS_CONST,
 
   // 1A CONST_STRING vAA, string@BBBB
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1B CONST_STRING_JUMBO vAA, string@BBBBBBBB
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1C CONST_CLASS vAA, type@BBBB
-  DF_DA | DF_REF_A,
+  DF_DA | DF_REF_A | DF_NON_NULL_DST,
 
   // 1D MONITOR_ENTER vAA
   DF_UA | DF_NULL_CHK_0 | DF_REF_A,
@@ -933,11 +933,6 @@
   SetNumSSARegs(ssa_reg + 1);
   ssa_base_vregs_->Insert(v_reg);
   ssa_subscripts_->Insert(subscript);
-  std::string ssa_name = GetSSAName(ssa_reg);
-  char* name = static_cast<char*>(arena_->NewMem(ssa_name.length() + 1, false,
-                                                 ArenaAllocator::kAllocDFInfo));
-  strncpy(name, ssa_name.c_str(), ssa_name.length() + 1);
-  ssa_strings_->Insert(name);
   DCHECK_EQ(ssa_base_vregs_->Size(), ssa_subscripts_->Size());
   return ssa_reg;
 }
@@ -1140,8 +1135,6 @@
                                             kGrowableArraySSAtoDalvikMap);
   ssa_subscripts_ = new (arena_) GrowableArray<int>(arena_, num_dalvik_reg + GetDefCount() + 128,
                                             kGrowableArraySSAtoDalvikMap);
-  ssa_strings_ = new (arena_) GrowableArray<char*>(arena_, num_dalvik_reg + GetDefCount() + 128,
-                                           kGrowableArraySSAtoDalvikMap);
   /*
    * Initial number of SSA registers is equal to the number of Dalvik
    * registers.
@@ -1156,11 +1149,6 @@
   for (unsigned int i = 0; i < num_dalvik_reg; i++) {
     ssa_base_vregs_->Insert(i);
     ssa_subscripts_->Insert(0);
-    std::string ssa_name = GetSSAName(i);
-    char* name = static_cast<char*>(arena_->NewMem(ssa_name.length() + 1, true,
-                                                   ArenaAllocator::kAllocDFInfo));
-    strncpy(name, ssa_name.c_str(), ssa_name.length() + 1);
-    ssa_strings_->Insert(name);
   }
 
   /*
@@ -1237,17 +1225,17 @@
       return false;
   }
   DexCompilationUnit m_unit(cu_);
-  // TODO: add a flag so we don't counts the stats for this twice
-  uint32_t dex_method_idx = mir->dalvikInsn.vB;
+  CompilerDriver::MethodReference target_method(cu_->dex_file, mir->dalvikInsn.vB);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
   uint32_t current_offset = static_cast<uint32_t>(current_offset_);
   bool fast_path =
-      cu_->compiler_driver->ComputeInvokeInfo(dex_method_idx, current_offset,
-                                              &m_unit, type,
-                                              vtable_idx, direct_code,
-                                              direct_method) &&
+      cu_->compiler_driver->ComputeInvokeInfo(&m_unit, current_offset,
+                                              type, target_method,
+                                              vtable_idx,
+                                              direct_code, direct_method,
+                                              false) &&
                                               !(cu_->enable_debug & (1 << kDebugSlowInvokePath));
   return (((type == kDirect) || (type == kStatic)) &&
           fast_path && ((direct_code == 0) || (direct_method == 0)));
diff --git a/src/compiler/dex/mir_graph.cc b/src/compiler/dex/mir_graph.cc
index 6154eec..11e100d 100644
--- a/src/compiler/dex/mir_graph.cc
+++ b/src/compiler/dex/mir_graph.cc
@@ -77,7 +77,6 @@
       cu_(cu),
       ssa_base_vregs_(NULL),
       ssa_subscripts_(NULL),
-      ssa_strings_(NULL),
       vreg_to_ssa_map_(NULL),
       ssa_last_defs_(NULL),
       is_constant_v_(NULL),
@@ -1037,6 +1036,9 @@
 
 std::string MIRGraph::GetSSAName(int ssa_reg)
 {
+  // TODO: This value is needed for LLVM and debugging. Currently, we compute this and then copy to
+  //       the arena. We should be smarter and just place straight into the arena, or compute the
+  //       value more lazily.
   return StringPrintf("v%d_%d", SRegToVReg(ssa_reg), GetSSASubscript(ssa_reg));
 }
 
diff --git a/src/compiler/dex/mir_graph.h b/src/compiler/dex/mir_graph.h
index 882a508..2b1c21f 100644
--- a/src/compiler/dex/mir_graph.h
+++ b/src/compiler/dex/mir_graph.h
@@ -452,10 +452,6 @@
     return ssa_subscripts_->Get(ssa_reg);
   }
 
-  const char* GetSSAString(int ssa_reg) const {
-    return ssa_strings_->Get(ssa_reg);
-  }
-
   RegLocation GetRawSrc(MIR* mir, int num)
   {
     DCHECK(num < mir->ssa_rep->num_uses);
@@ -628,7 +624,6 @@
    CompilationUnit* const cu_;
    GrowableArray<int>* ssa_base_vregs_;
    GrowableArray<int>* ssa_subscripts_;
-   GrowableArray<char*>* ssa_strings_;
    // Map original Dalvik virtual reg i to the current SSA name.
    int* vreg_to_ssa_map_;            // length == method->registers_size
    int* ssa_last_defs_;              // length == method->registers_size
diff --git a/src/compiler/dex/mir_optimization.cc b/src/compiler/dex/mir_optimization.cc
index 5345501..6b8f3f0 100644
--- a/src/compiler/dex/mir_optimization.cc
+++ b/src/compiler/dex/mir_optimization.cc
@@ -16,7 +16,7 @@
 
 #include "compiler_internals.h"
 #include "local_value_numbering.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 
 namespace art {
 
@@ -418,6 +418,13 @@
                   static_cast<bool*>(arena_->NewMem(sizeof(bool) * 1, false,
                                                     ArenaAllocator::kAllocDFInfo));
               mir->ssa_rep->fp_def[0] = if_true->ssa_rep->fp_def[0];
+              // Match type of uses to def.
+              mir->ssa_rep->fp_use =
+                  static_cast<bool*>(arena_->NewMem(sizeof(bool) * mir->ssa_rep->num_uses, false,
+                                                    ArenaAllocator::kAllocDFInfo));
+              for (int i = 0; i < mir->ssa_rep->num_uses; i++) {
+                mir->ssa_rep->fp_use[i] = mir->ssa_rep->fp_def[0];
+              }
               /*
                * There is usually a Phi node in the join block for our two cases.  If the
                * Phi node only contains our two cases as input, we will use the result
@@ -634,8 +641,29 @@
       int this_reg = cu_->num_dalvik_registers - cu_->num_ins;
       temp_ssa_register_v_->SetBit(this_reg);
     }
+  } else if (bb->predecessors->Size() == 1) {
+    BasicBlock* pred_bb = bb->predecessors->Get(0);
+    temp_ssa_register_v_->Copy(pred_bb->data_flow_info->ending_null_check_v);
+    if (pred_bb->block_type == kDalvikByteCode) {
+      // Check to see if predecessor had an explicit null-check.
+      MIR* last_insn = pred_bb->last_mir_insn;
+      Instruction::Code last_opcode = last_insn->dalvikInsn.opcode;
+      if (last_opcode == Instruction::IF_EQZ) {
+        if (pred_bb->fall_through == bb) {
+          // The fall-through of a block following a IF_EQZ, set the vA of the IF_EQZ to show that
+          // it can't be null.
+          temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
+        }
+      } else if (last_opcode == Instruction::IF_NEZ) {
+        if (pred_bb->taken == bb) {
+          // The taken block following a IF_NEZ, set the vA of the IF_NEZ to show that it can't be
+          // null.
+          temp_ssa_register_v_->SetBit(last_insn->ssa_rep->uses[0]);
+        }
+      }
+    }
   } else {
-    // Starting state is intesection of all incoming arcs
+    // Starting state is intersection of all incoming arcs
     GrowableArray<BasicBlock*>::Iterator iter(bb->predecessors);
     BasicBlock* pred_bb = iter.Next();
     DCHECK(pred_bb != NULL);
diff --git a/src/compiler/dex/portable/mir_to_gbc.cc b/src/compiler/dex/portable/mir_to_gbc.cc
index 6fccb47..1f9c92a 100644
--- a/src/compiler/dex/portable/mir_to_gbc.cc
+++ b/src/compiler/dex/portable/mir_to_gbc.cc
@@ -28,7 +28,7 @@
 #include <llvm/Support/ToolOutputFile.h>
 
 #include "compiler/dex/compiler_internals.h"
-#include "compiler/dex/dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
 #include "compiler/dex/frontend.h"
 #include "mir_to_gbc.h"
 
@@ -1964,7 +1964,7 @@
       ::llvm::Constant* imm_value = mir_graph_->reg_location_[i].wide ?
          irb_->getJLong(0) : irb_->getJInt(0);
       val = EmitConst(imm_value, mir_graph_->reg_location_[i]);
-      val->setName(mir_graph_->GetSSAString(i));
+      val->setName(mir_graph_->GetSSAName(i));
       llvm_values_.Insert(val);
     } else {
       // Recover previously-created argument values
diff --git a/src/compiler/dex/quick/arm/assemble_arm.cc b/src/compiler/dex/quick/arm/assemble_arm.cc
index 23a87dc..36038f7 100644
--- a/src/compiler/dex/quick/arm/assemble_arm.cc
+++ b/src/compiler/dex/quick/arm/assemble_arm.cc
@@ -16,6 +16,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/arm/call_arm.cc b/src/compiler/dex/quick/arm/call_arm.cc
index 32d4ed6..879065f 100644
--- a/src/compiler/dex/quick/arm/call_arm.cc
+++ b/src/compiler/dex/quick/arm/call_arm.cc
@@ -18,6 +18,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
 namespace art {
@@ -561,7 +562,7 @@
   int reg_card_no = AllocTemp();
   LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   LoadWordDisp(rARM_SELF, Thread::CardTableOffset().Int32Value(), reg_card_base);
-  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, CardTable::kCardShift);
+  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0,
                    kUnsignedByte);
   LIR* target = NewLIR0(kPseudoTargetLabel);
diff --git a/src/compiler/dex/quick/arm/codegen_arm.h b/src/compiler/dex/quick/arm/codegen_arm.h
index 9e409e6..60111d1 100644
--- a/src/compiler/dex/quick/arm/codegen_arm.h
+++ b/src/compiler/dex/quick/arm/codegen_arm.h
@@ -23,143 +23,142 @@
 
 class ArmMir2Lir : public Mir2Lir {
   public:
-
     ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen helpers.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
-    virtual int LoadHelper(int offset);
-    virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
-    virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
-                                  int s_reg);
-    virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
-    virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
-                                     int r_dest, int r_dest_hi, OpSize size, int s_reg);
-    virtual LIR* LoadConstantNoClobber(int r_dest, int value);
-    virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
-    virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
-    virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
-    virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
-    virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
-                                      int r_src, int r_src_hi, OpSize size, int s_reg);
-    virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+    int LoadHelper(int offset);
+    LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+    LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+                          int s_reg);
+    LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+    LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+                             int r_dest, int r_dest_hi, OpSize size, int s_reg);
+    LIR* LoadConstantNoClobber(int r_dest, int value);
+    LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+    LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+    LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+    LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+    LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+                              int r_src, int r_src_hi, OpSize size, int s_reg);
+    void MarkGCCard(int val_reg, int tgt_addr_reg);
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg);
-    virtual bool SameRegType(int reg1, int reg2);
-    virtual int AllocTypedTemp(bool fp_hint, int reg_class);
-    virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
-    virtual int S2d(int low_reg, int high_reg);
-    virtual int TargetReg(SpecialTargetRegister reg);
-    virtual RegisterInfo* GetRegInfo(int reg);
-    virtual RegLocation GetReturnAlt();
-    virtual RegLocation GetReturnWideAlt();
-    virtual RegLocation LocCReturn();
-    virtual RegLocation LocCReturnDouble();
-    virtual RegLocation LocCReturnFloat();
-    virtual RegLocation LocCReturnWide();
-    virtual uint32_t FpRegMask();
-    virtual uint64_t GetRegMaskCommon(int reg);
-    virtual void AdjustSpillMask();
-    virtual void ClobberCalleeSave();
-    virtual void FlushReg(int reg);
-    virtual void FlushRegWide(int reg1, int reg2);
-    virtual void FreeCallTemps();
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
-    virtual void LockCallTemps();
-    virtual void MarkPreservedSingle(int v_reg, int reg);
-    virtual void CompilerInitializeRegAlloc();
+    bool IsFpReg(int reg);
+    bool SameRegType(int reg1, int reg2);
+    int AllocTypedTemp(bool fp_hint, int reg_class);
+    int AllocTypedTempPair(bool fp_hint, int reg_class);
+    int S2d(int low_reg, int high_reg);
+    int TargetReg(SpecialTargetRegister reg);
+    RegisterInfo* GetRegInfo(int reg);
+    RegLocation GetReturnAlt();
+    RegLocation GetReturnWideAlt();
+    RegLocation LocCReturn();
+    RegLocation LocCReturnDouble();
+    RegLocation LocCReturnFloat();
+    RegLocation LocCReturnWide();
+    uint32_t FpRegMask();
+    uint64_t GetRegMaskCommon(int reg);
+    void AdjustSpillMask();
+    void ClobberCalleeSave();
+    void FlushReg(int reg);
+    void FlushRegWide(int reg1, int reg2);
+    void FreeCallTemps();
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+    void LockCallTemps();
+    void MarkPreservedSingle(int v_reg, int reg);
+    void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
-    virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
-    virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
-    virtual void SetupTargetResourceMasks(LIR* lir);
-    virtual const char* GetTargetInstFmt(int opcode);
-    virtual const char* GetTargetInstName(int opcode);
-    virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
-    virtual uint64_t GetPCUseDefEncoding();
-    virtual uint64_t GetTargetInstFlags(int opcode);
-    virtual int GetInsnSize(LIR* lir);
-    virtual bool IsUnconditionalBranch(LIR* lir);
+    AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+    void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+    void SetupTargetResourceMasks(LIR* lir);
+    const char* GetTargetInstFmt(int opcode);
+    const char* GetTargetInstName(int opcode);
+    std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+    uint64_t GetPCUseDefEncoding();
+    uint64_t GetTargetInstFlags(int opcode);
+    int GetInsnSize(LIR* lir);
+    bool IsUnconditionalBranch(LIR* lir);
 
     // Required for target - Dalvik-level generators.
-    virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
-                                RegLocation rl_src, int scale);
-    virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
-                             RegLocation rl_index, RegLocation rl_dest, int scale);
-    virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
-                             RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
-                                   RegLocation rl_src1, RegLocation rl_shift);
-    virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
-                                  RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
-                                 RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
-                          RegLocation rl_src2);
-    virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
-    virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
-    virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
-    virtual bool GenInlinedSqrt(CallInfo* info);
-    virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+    void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+                           RegLocation rl_src1, RegLocation rl_src2);
+    void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
+                        RegLocation rl_src, int scale);
+    void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+                     RegLocation rl_index, RegLocation rl_dest, int scale);
+    void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+                     RegLocation rl_index, RegLocation rl_src, int scale);
+    void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+                           RegLocation rl_src1, RegLocation rl_shift);
+    void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+                          RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+                         RegLocation rl_src1, RegLocation rl_src2);
+    void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+                  RegLocation rl_src2);
+    void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+    bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+    bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+    bool GenInlinedSqrt(CallInfo* info);
+    void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+    void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
                                 ThrowKind kind);
-    virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
-    virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
-    virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
-    virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual void GenExitSequence();
-    virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
-    virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
-    virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
-    virtual void GenSelect(BasicBlock* bb, MIR* mir);
-    virtual void GenMemBarrier(MemBarrierKind barrier_kind);
-    virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
-    virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
-    virtual void GenMoveException(RegLocation rl_dest);
-    virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
+    RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+    RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+    void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenDivZeroCheck(int reg_lo, int reg_hi);
+    void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+    void GenExitSequence();
+    void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+    void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+    void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+    void GenSelect(BasicBlock* bb, MIR* mir);
+    void GenMemBarrier(MemBarrierKind barrier_kind);
+    void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+    void GenMonitorExit(int opt_flags, RegLocation rl_src);
+    void GenMoveException(RegLocation rl_dest);
+    void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
                                                int first_bit, int second_bit);
-    virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+    void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+    void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+    void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
 
     // Required for target - single operation generators.
-    virtual LIR* OpUnconditionalBranch(LIR* target);
-    virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
-    virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
-    virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
-    virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
-    virtual LIR* OpFpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpIT(ConditionCode cond, const char* guide);
-    virtual LIR* OpMem(OpKind op, int rBase, int disp);
-    virtual LIR* OpPcRelLoad(int reg, LIR* target);
-    virtual LIR* OpReg(OpKind op, int r_dest_src);
-    virtual LIR* OpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
-    virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
-    virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
-    virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
-    virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
-    virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
-    virtual LIR* OpTestSuspend(LIR* target);
-    virtual LIR* OpThreadMem(OpKind op, int thread_offset);
-    virtual LIR* OpVldm(int rBase, int count);
-    virtual LIR* OpVstm(int rBase, int count);
-    virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
-    virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
-    virtual void OpTlsCmp(int offset, int val);
+    LIR* OpUnconditionalBranch(LIR* target);
+    LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+    LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+    LIR* OpCondBranch(ConditionCode cc, LIR* target);
+    LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+    LIR* OpFpRegCopy(int r_dest, int r_src);
+    LIR* OpIT(ConditionCode cond, const char* guide);
+    LIR* OpMem(OpKind op, int rBase, int disp);
+    LIR* OpPcRelLoad(int reg, LIR* target);
+    LIR* OpReg(OpKind op, int r_dest_src);
+    LIR* OpRegCopy(int r_dest, int r_src);
+    LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+    LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+    LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+    LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+    LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+    LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+    LIR* OpTestSuspend(LIR* target);
+    LIR* OpThreadMem(OpKind op, int thread_offset);
+    LIR* OpVldm(int rBase, int count);
+    LIR* OpVstm(int rBase, int count);
+    void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+    void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+    void OpTlsCmp(int offset, int val);
 
     RegLocation ArgLoc(RegLocation loc);
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
diff --git a/src/compiler/dex/quick/arm/fp_arm.cc b/src/compiler/dex/quick/arm/fp_arm.cc
index 4bf8738..cd71c07 100644
--- a/src/compiler/dex/quick/arm/fp_arm.cc
+++ b/src/compiler/dex/quick/arm/fp_arm.cc
@@ -16,6 +16,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/arm/int_arm.cc b/src/compiler/dex/quick/arm/int_arm.cc
index 586a3a4..110e9f4 100644
--- a/src/compiler/dex/quick/arm/int_arm.cc
+++ b/src/compiler/dex/quick/arm/int_arm.cc
@@ -18,6 +18,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mirror/array.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
diff --git a/src/compiler/dex/quick/arm/target_arm.cc b/src/compiler/dex/quick/arm/target_arm.cc
index 0a05a3a..ee127a8 100644
--- a/src/compiler/dex/quick/arm/target_arm.cc
+++ b/src/compiler/dex/quick/arm/target_arm.cc
@@ -19,6 +19,7 @@
 #include "arm_lir.h"
 #include "codegen_arm.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/arm/utility_arm.cc b/src/compiler/dex/quick/arm/utility_arm.cc
index c689f72..ef0cc72 100644
--- a/src/compiler/dex/quick/arm/utility_arm.cc
+++ b/src/compiler/dex/quick/arm/utility_arm.cc
@@ -16,7 +16,7 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
-#include "compiler/dex/quick/mir_to_lir.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 
 namespace art {
 
diff --git a/src/compiler/dex/quick/codegen_util.cc b/src/compiler/dex/quick/codegen_util.cc
index 517d1b5..ac2828c 100644
--- a/src/compiler/dex/quick/codegen_util.cc
+++ b/src/compiler/dex/quick/codegen_util.cc
@@ -17,6 +17,7 @@
 #include "compiler/dex/compiler_internals.h"
 #include "dex_file-inl.h"
 #include "gc_map.h"
+#include "mir_to_lir-inl.h"
 #include "verifier/dex_gc_map.h"
 #include "verifier/method_verifier.h"
 
@@ -112,81 +113,6 @@
 }
 
 /*
- * Mark the corresponding bit(s).
- */
-void Mir2Lir::SetupRegMask(uint64_t* mask, int reg)
-{
-  *mask |= GetRegMaskCommon(reg);
-}
-
-/*
- * Set up the proper fields in the resource mask
- */
-void Mir2Lir::SetupResourceMasks(LIR* lir)
-{
-  int opcode = lir->opcode;
-
-  if (opcode <= 0) {
-    lir->use_mask = lir->def_mask = 0;
-    return;
-  }
-
-  uint64_t flags = GetTargetInstFlags(opcode);
-
-  if (flags & NEEDS_FIXUP) {
-    lir->flags.pcRelFixup = true;
-  }
-
-  /* Get the starting size of the instruction's template */
-  lir->flags.size = GetInsnSize(lir);
-
-  /* Set up the mask for resources that are updated */
-  if (flags & (IS_LOAD | IS_STORE)) {
-    /* Default to heap - will catch specialized classes later */
-    SetMemRefType(lir, flags & IS_LOAD, kHeapRef);
-  }
-
-  /*
-   * Conservatively assume the branch here will call out a function that in
-   * turn will trash everything.
-   */
-  if (flags & IS_BRANCH) {
-    lir->def_mask = lir->use_mask = ENCODE_ALL;
-    return;
-  }
-
-  if (flags & REG_DEF0) {
-    SetupRegMask(&lir->def_mask, lir->operands[0]);
-  }
-
-  if (flags & REG_DEF1) {
-    SetupRegMask(&lir->def_mask, lir->operands[1]);
-  }
-
-
-  if (flags & SETS_CCODES) {
-    lir->def_mask |= ENCODE_CCODE;
-  }
-
-  if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
-    int i;
-
-    for (i = 0; i < 4; i++) {
-      if (flags & (1 << (kRegUse0 + i))) {
-        SetupRegMask(&lir->use_mask, lir->operands[i]);
-      }
-    }
-  }
-
-  if (flags & USES_CCODES) {
-    lir->use_mask |= ENCODE_CCODE;
-  }
-
-  // Handle target-specific actions
-  SetupTargetResourceMasks(lir);
-}
-
-/*
  * Debugging macros
  */
 #define DUMP_RESOURCE_MASK(X)
@@ -361,99 +287,6 @@
   DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, dex2pc_mapping_table_);
 }
 
-
-LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
-                     int op1, int op2, int op3, int op4, LIR* target)
-{
-  LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
-  insn->dalvik_offset = dalvik_offset;
-  insn->opcode = opcode;
-  insn->operands[0] = op0;
-  insn->operands[1] = op1;
-  insn->operands[2] = op2;
-  insn->operands[3] = op3;
-  insn->operands[4] = op4;
-  insn->target = target;
-  SetupResourceMasks(insn);
-  if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
-      (opcode == kPseudoExportedPC)) {
-    // Always make labels scheduling barriers
-    insn->use_mask = insn->def_mask = ENCODE_ALL;
-  }
-  return insn;
-}
-
-/*
- * The following are building blocks to construct low-level IRs with 0 - 4
- * operands.
- */
-LIR* Mir2Lir::NewLIR0(int opcode)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR1(int opcode, int dest)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR2(int opcode, int dest, int src1)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR3(int opcode, int dest, int src1, int src2)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR4(int opcode, int dest, int src1, int src2, int info)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info);
-  AppendLIR(insn);
-  return insn;
-}
-
-LIR* Mir2Lir::NewLIR5(int opcode, int dest, int src1, int src2, int info1,
-                      int info2)
-{
-  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP))
-      << GetTargetInstName(opcode) << " " << opcode << " "
-      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
-      << current_dalvik_offset_;
-  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info1, info2);
-  AppendLIR(insn);
-  return insn;
-}
-
 /*
  * Search the existing constants in the literal pool for an exact or close match
  * within specified delta (greater or equal to 0).
diff --git a/src/compiler/dex/quick/gen_common.cc b/src/compiler/dex/quick/gen_common.cc
index 15aa904..7aa71cf 100644
--- a/src/compiler/dex/quick/gen_common.cc
+++ b/src/compiler/dex/quick/gen_common.cc
@@ -16,8 +16,10 @@
 
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mirror/array.h"
 #include "oat/runtime/oat_support_entrypoints.h"
+#include "verifier/method_verifier.h"
 
 namespace art {
 
@@ -881,23 +883,81 @@
   CallRuntimeHelperRegLocation(ENTRYPOINT_OFFSET(pDeliverException), rl_src, true);
 }
 
-void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
-                            RegLocation rl_src)
-{
+// For final classes there are no sub-classes to check and so we can answer the instance-of
+// question with simple comparisons.
+void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
+                                 RegLocation rl_src) {
+  RegLocation object = LoadValue(rl_src, kCoreReg);
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  int result_reg = rl_result.low_reg;
+  if (result_reg == object.low_reg) {
+    result_reg = AllocTypedTemp(false, kCoreReg);
+  }
+  LoadConstant(result_reg, 0);     // assume false
+  LIR* null_branchover = OpCmpImmBranch(kCondEq, object.low_reg, 0, NULL);
+
+  int check_class = AllocTypedTemp(false, kCoreReg);
+  int object_class = AllocTypedTemp(false, kCoreReg);
+
+  LoadCurrMethodDirect(check_class);
+  if (use_declaring_class) {
+    LoadWordDisp(check_class, mirror::AbstractMethod::DeclaringClassOffset().Int32Value(),
+                 check_class);
+    LoadWordDisp(object.low_reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
+  } else {
+    LoadWordDisp(check_class, mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(),
+                 check_class);
+    LoadWordDisp(object.low_reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
+    int32_t offset_of_type =
+      mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
+      (sizeof(mirror::Class*) * type_idx);
+    LoadWordDisp(check_class, offset_of_type, check_class);
+  }
+
+  LIR* ne_branchover = NULL;
+  if (cu_->instruction_set == kThumb2) {
+    OpRegReg(kOpCmp, check_class, object_class);  // Same?
+    OpIT(kCondEq, "");   // if-convert the test
+    LoadConstant(result_reg, 1);     // .eq case - load true
+  } else {
+    ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL);
+    LoadConstant(result_reg, 1);     // eq case - load true
+  }
+  LIR* target = NewLIR0(kPseudoTargetLabel);
+  null_branchover->target = target;
+  if (ne_branchover != NULL) {
+    ne_branchover->target = target;
+  }
+  FreeTemp(object_class);
+  FreeTemp(check_class);
+  if (IsTemp(result_reg)) {
+    OpRegCopy(rl_result.low_reg, result_reg);
+    FreeTemp(result_reg);
+  }
+  StoreValue(rl_dest, rl_result);
+}
+
+void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                         bool type_known_abstract, bool use_declaring_class,
+                                         bool can_assume_type_is_in_dex_cache,
+                                         uint32_t type_idx, RegLocation rl_dest,
+                                         RegLocation rl_src) {
   FlushAllRegs();
   // May generate a call - use explicit registers
   LockCallTemps();
   LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 <= current Method*
   int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*
-  if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
-                                                   *cu_->dex_file,
-                                                   type_idx)) {
+  if (needs_access_check) {
     // Check we have access to type_idx and if not throw IllegalAccessError,
     // returns Class* in kArg0
     CallRuntimeHelperImm(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
                          type_idx, true);
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
+  } else if (use_declaring_class) {
+    LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
+    LoadWordDisp(TargetReg(kArg1),
+                 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
   } else {
     // Load dex cache entry into class_reg (kArg2)
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
@@ -907,8 +967,7 @@
         mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
         * type_idx);
     LoadWordDisp(class_reg, offset_of_type, class_reg);
-    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
-        *cu_->dex_file, type_idx)) {
+    if (!can_assume_type_is_in_dex_cache) {
       // Need to test presence of type in dex cache at runtime
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
       // Not resolved
@@ -924,65 +983,120 @@
   /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */
   RegLocation rl_result = GetReturn(false);
   if (cu_->instruction_set == kMips) {
-    LoadConstant(rl_result.low_reg, 0);  // store false result for if branch is taken
+    // On MIPS rArg0 != rl_result, place false in result if branch is taken.
+    LoadConstant(rl_result.low_reg, 0);
   }
   LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL);
+
   /* load object->klass_ */
   DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
   LoadWordDisp(TargetReg(kArg0),  mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
   /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */
-  LIR* call_inst;
   LIR* branchover = NULL;
-  if (cu_->instruction_set == kThumb2) {
-    /* Uses conditional nullification */
-    int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
-    OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
-    OpIT(kCondEq, "EE");   // if-convert the test
-    LoadConstant(TargetReg(kArg0), 1);     // .eq case - load true
-    OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
-    call_inst = OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
-    FreeTemp(r_tgt);
+  if (type_known_final) {
+    // rl_result == ref == null == 0.
+    if (cu_->instruction_set == kThumb2) {
+      OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
+      OpIT(kCondEq, "E");   // if-convert the test
+      LoadConstant(rl_result.low_reg, 1);     // .eq case - load true
+      LoadConstant(rl_result.low_reg, 0);     // .ne case - load false
+    } else {
+      LoadConstant(rl_result.low_reg, 0);     // ne case - load false
+      branchover = OpCmpBranch(kCondNe, TargetReg(kArg1), TargetReg(kArg2), NULL);
+      LoadConstant(rl_result.low_reg, 1);     // eq case - load true
+    }
   } else {
-    /* Uses branchovers */
-    LoadConstant(rl_result.low_reg, 1);     // assume true
-    branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
-    if (cu_->instruction_set != kX86) {
+    if (cu_->instruction_set == kThumb2) {
       int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+      if (!type_known_abstract) {
+      /* Uses conditional nullification */
+        OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2));  // Same?
+        OpIT(kCondEq, "EE");   // if-convert the test
+        LoadConstant(TargetReg(kArg0), 1);     // .eq case - load true
+      }
       OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
-      call_inst = OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
+      OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
       FreeTemp(r_tgt);
     } else {
-      OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
-      call_inst = OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+      if (!type_known_abstract) {
+        /* Uses branchovers */
+        LoadConstant(rl_result.low_reg, 1);     // assume true
+        branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL);
+      }
+      if (cu_->instruction_set != kX86) {
+        int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));    // .ne case - arg0 <= class
+        OpReg(kOpBlx, r_tgt);    // .ne case: helper(class, ref->class)
+        FreeTemp(r_tgt);
+      } else {
+        OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
+        OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pInstanceofNonTrivialFromCode));
+      }
     }
   }
-  MarkSafepointPC(call_inst);
+  // TODO: only clobber when type isn't final?
   ClobberCalleeSave();
   /* branch targets here */
   LIR* target = NewLIR0(kPseudoTargetLabel);
   StoreValue(rl_dest, rl_result);
   branch1->target = target;
-  if (cu_->instruction_set != kThumb2) {
+  if (branchover != NULL) {
     branchover->target = target;
   }
 }
 
-void Mir2Lir::GenCheckCast(uint32_t type_idx, RegLocation rl_src)
+void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) {
+  bool type_known_final, type_known_abstract, use_declaring_class;
+  bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
+                                                                              *cu_->dex_file,
+                                                                              type_idx,
+                                                                              &type_known_final,
+                                                                              &type_known_abstract,
+                                                                              &use_declaring_class);
+  bool can_assume_type_is_in_dex_cache = !needs_access_check &&
+      cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx);
+
+  if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) {
+    GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src);
+  } else {
+    GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract,
+                               use_declaring_class, can_assume_type_is_in_dex_cache,
+                               type_idx, rl_dest, rl_src);
+  }
+}
+
+void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src)
 {
+  bool type_known_final, type_known_abstract, use_declaring_class;
+  bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
+                                                                              *cu_->dex_file,
+                                                                              type_idx,
+                                                                              &type_known_final,
+                                                                              &type_known_abstract,
+                                                                              &use_declaring_class);
+  // Note: currently type_known_final is unused, as optimizing will only improve the performance
+  // of the exception throw path.
+  DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit();
+  const CompilerDriver::MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex());
+  if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) {
+    // Verifier type analysis proved this check cast would never cause an exception.
+    return;
+  }
   FlushAllRegs();
   // May generate a call - use explicit registers
   LockCallTemps();
   LoadCurrMethodDirect(TargetReg(kArg1));  // kArg1 <= current Method*
   int class_reg = TargetReg(kArg2);  // kArg2 will hold the Class*
-  if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx,
-                                                   *cu_->dex_file,
-                                                   type_idx)) {
+  if (needs_access_check) {
     // Check we have access to type_idx and if not throw IllegalAccessError,
     // returns Class* in kRet0
     // InitializeTypeAndVerifyAccess(idx, method)
     CallRuntimeHelperImmReg(ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccessFromCode),
                             type_idx, TargetReg(kArg1), true);
     OpRegCopy(class_reg, TargetReg(kRet0));  // Align usage with fast path
+  } else if (use_declaring_class) {
+    LoadWordDisp(TargetReg(kArg1),
+                 mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg);
   } else {
     // Load dex cache entry into class_reg (kArg2)
     LoadWordDisp(TargetReg(kArg1),
@@ -991,8 +1105,7 @@
         mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
         (sizeof(mirror::Class*) * type_idx);
     LoadWordDisp(class_reg, offset_of_type, class_reg);
-    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(
-        *cu_->dex_file, type_idx)) {
+    if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
       // Need to test presence of type in dex cache at runtime
       LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL);
       // Not resolved
@@ -1014,25 +1127,18 @@
   DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0);
   LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1));
   /* kArg1 now contains object->klass_ */
-  LIR* branch2;
-  if (cu_->instruction_set == kThumb2) {
-    int r_tgt = LoadHelper(ENTRYPOINT_OFFSET(pCheckCastFromCode));
-    OpRegReg(kOpCmp, TargetReg(kArg1), class_reg);
-    branch2 = OpCondBranch(kCondEq, NULL); /* If eq, trivial yes */
-    OpRegCopy(TargetReg(kArg0), TargetReg(kArg1));
-    OpRegCopy(TargetReg(kArg1), TargetReg(kArg2));
-    ClobberCalleeSave();
-    LIR* call_inst = OpReg(kOpBlx, r_tgt);
-    MarkSafepointPC(call_inst);
-    FreeTemp(r_tgt);
-  } else {
+  LIR* branch2 = NULL;
+  if (!type_known_abstract) {
     branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL);
-    CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2), true);
   }
+  CallRuntimeHelperRegReg(ENTRYPOINT_OFFSET(pCheckCastFromCode), TargetReg(kArg1), TargetReg(kArg2),
+                          true);
   /* branch target here */
   LIR* target = NewLIR0(kPseudoTargetLabel);
   branch1->target = target;
-  branch2->target = target;
+  if (branch2 != NULL) {
+    branch2->target = target;
+  }
 }
 
 void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
diff --git a/src/compiler/dex/quick/gen_invoke.cc b/src/compiler/dex/quick/gen_invoke.cc
index afcd9ef..4b12bb4 100644
--- a/src/compiler/dex/quick/gen_invoke.cc
+++ b/src/compiler/dex/quick/gen_invoke.cc
@@ -15,9 +15,11 @@
  */
 
 #include "compiler/dex/compiler_ir.h"
+#include "dex_file-inl.h"
 #include "invoke_type.h"
 #include "mirror/array.h"
 #include "mirror/string.h"
+#include "mir_to_lir-inl.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 #include "x86/codegen_x86.h"
 
@@ -311,7 +313,8 @@
  * emit the next instruction in static & direct invoke sequences.
  */
 static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
-                          int state, uint32_t dex_idx, uint32_t unused,
+                          int state, const CompilerDriver::MethodReference& target_method,
+                          uint32_t unused,
                           uintptr_t direct_code, uintptr_t direct_method,
                           InvokeType type)
 {
@@ -327,9 +330,11 @@
       if (direct_code != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
       } else {
-        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+        CHECK_EQ(cu->dex_file, target_method.dex_file);
+        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
+                                               target_method.dex_method_index, 0);
         if (data_target == NULL) {
-          data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
+          data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
           data_target->operands[1] = type;
         }
         LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
@@ -339,9 +344,11 @@
       if (direct_method != static_cast<unsigned int>(-1)) {
         cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
       } else {
-        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+        CHECK_EQ(cu->dex_file, target_method.dex_file);
+        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
+                                               target_method.dex_method_index, 0);
         if (data_target == NULL) {
-          data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
+          data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
           data_target->operands[1] = type;
         }
         LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -366,9 +373,11 @@
         if (direct_code != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
         } else {
-          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
+          CHECK_EQ(cu->dex_file, target_method.dex_file);
+          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
+                                                 target_method.dex_method_index, 0);
           if (data_target == NULL) {
-            data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
+            data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
             data_target->operands[1] = type;
           }
           LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
@@ -378,8 +387,10 @@
       }
       break;
     case 2:  // Grab target method*
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadWordDisp(cg->TargetReg(kArg0),
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+                           (target_method.dex_method_index * 4),
                        cg-> TargetReg(kArg0));
       break;
     case 3:  // Grab the code from the method*
@@ -407,8 +418,9 @@
  * kArg1 here rather than the standard LoadArgRegs.
  */
 static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
-                         int state, uint32_t dex_idx, uint32_t method_idx,
-                         uintptr_t unused, uintptr_t unused2, InvokeType unused3)
+                         int state, const CompilerDriver::MethodReference& target_method,
+                         uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
+                         InvokeType unused3)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
@@ -455,7 +467,8 @@
  * which will locate the target and continue on via a tail call.
  */
 static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
-                                 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
+                                 const CompilerDriver::MethodReference& target_method,
+                                 uint32_t unused, uintptr_t unused2,
                                  uintptr_t direct_method, InvokeType unused4)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
@@ -476,9 +489,12 @@
         if (direct_method != static_cast<unsigned int>(-1)) {
           cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
         } else {
-          LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
+          CHECK_EQ(cu->dex_file, target_method.dex_file);
+          LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
+                                                 target_method.dex_method_index, 0);
           if (data_target == NULL) {
-            data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
+            data_target = cg->AddWordData(&cg->method_literal_list_,
+                                          target_method.dex_method_index);
             data_target->operands[1] = kInterface;
           }
           LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
@@ -505,8 +521,10 @@
                        cg->TargetReg(kArg0));
       break;
     case 2:  // Grab target method* [set/use kArg0]
+      CHECK_EQ(cu->dex_file, target_method.dex_file);
       cg->LoadWordDisp(cg->TargetReg(kArg0),
-                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
+                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
+                           (target_method.dex_method_index * 4),
                        cg->TargetReg(kArg0));
       break;
     default:
@@ -517,7 +535,8 @@
 }
 
 static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
-                            int state, uint32_t dex_idx, uint32_t method_idx)
+                            int state, const CompilerDriver::MethodReference& target_method,
+                            uint32_t method_idx)
 {
   Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
   /*
@@ -530,58 +549,66 @@
       cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
     }
     // Load kArg0 with method index
-    cg->LoadConstant(cg->TargetReg(kArg0), dex_idx);
+    CHECK_EQ(cu->dex_file, target_method.dex_file);
+    cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
     return 1;
   }
   return -1;
 }
 
 static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
-                                int state, uint32_t dex_idx, uint32_t method_idx,
+                                int state,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t method_idx,
                                 uintptr_t unused, uintptr_t unused2,
-                         InvokeType unused3)
+                                InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                                uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t method_idx, uintptr_t unused,
                                 uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                               uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
-                        uintptr_t unused2, InvokeType unused3)
+                               const CompilerDriver::MethodReference& target_method,
+                               uint32_t method_idx, uintptr_t unused,
+                               uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
-                           uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
+                           const CompilerDriver::MethodReference& target_method,
+                           uint32_t method_idx, uintptr_t unused,
                            uintptr_t unused2, InvokeType unused3)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
                                                 CallInfo* info, int state,
-                                         uint32_t dex_idx, uint32_t unused,
-                                         uintptr_t unused2, uintptr_t unused3,
-                                         InvokeType unused4)
+                                                const CompilerDriver::MethodReference& target_method,
+                                                uint32_t unused,
+                                                uintptr_t unused2, uintptr_t unused3,
+                                                InvokeType unused4)
 {
   int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
-  return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
+  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
 }
 
 int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
-                         NextCallInsn next_call_insn, uint32_t dex_idx,
-                         uint32_t method_idx, uintptr_t direct_code,
+                         NextCallInsn next_call_insn,
+                         const CompilerDriver::MethodReference& target_method,
+                         uint32_t vtable_idx, uintptr_t direct_code,
                          uintptr_t direct_method, InvokeType type, bool skip_this)
 {
   int last_arg_reg = TargetReg(kArg3);
@@ -605,8 +632,8 @@
       }
       LoadValueDirectFixed(rl_arg, next_reg);
     }
-    call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                 direct_code, direct_method, type);
+    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                                direct_code, direct_method, type);
   }
   return call_state;
 }
@@ -620,7 +647,8 @@
  */
 int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
                                   int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
-                                  uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
+                                  const CompilerDriver::MethodReference& target_method,
+                                  uint32_t vtable_idx, uintptr_t direct_code,
                                   uintptr_t direct_method, InvokeType type, bool skip_this)
 {
   RegLocation rl_arg;
@@ -629,8 +657,8 @@
   if (info->num_arg_words == 0)
     return call_state;
 
-  call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                           direct_code, direct_method, type);
+  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                              direct_code, direct_method, type);
 
   DCHECK_LE(info->num_arg_words, 5);
   if (info->num_arg_words > 3) {
@@ -650,13 +678,13 @@
         // kArg2 & rArg3 can safely be used here
         reg = TargetReg(kArg3);
         LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
-        call_state = next_call_insn(cu_, info, call_state, dex_idx,
-                                 method_idx, direct_code, direct_method, type);
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
       }
       StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
       StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
-                               direct_code, direct_method, type);
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+                                  direct_code, direct_method, type);
       next_use++;
     }
     // Loop through the rest
@@ -676,8 +704,8 @@
         } else {
           LoadValueDirectFixed(rl_arg, low_reg);
         }
-        call_state = next_call_insn(cu_, info, call_state, dex_idx,
-                                 method_idx, direct_code, direct_method, type);
+        call_state = next_call_insn(cu_, info, call_state, target_method,
+                                    vtable_idx, direct_code, direct_method, type);
       }
       int outs_offset = (next_use + 1) * 4;
       if (rl_arg.wide) {
@@ -687,14 +715,14 @@
         StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
         next_use++;
       }
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
     }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
-                          dex_idx, method_idx, direct_code, direct_method,
-                          type, skip_this);
+                           target_method, vtable_idx, direct_code, direct_method,
+                           type, skip_this);
 
   if (pcrLabel) {
     *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -718,15 +746,16 @@
  *
  */
 int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
-                                LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
-                                uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
+                                LIR** pcrLabel, NextCallInsn next_call_insn,
+                                const CompilerDriver::MethodReference& target_method,
+                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
                                 InvokeType type, bool skip_this)
 {
 
   // If we can treat it as non-range (Jumbo ops will use range form)
   if (info->num_arg_words <= 5)
     return GenDalvikArgsNoRange(info, call_state, pcrLabel,
-                                next_call_insn, dex_idx, method_idx,
+                                next_call_insn, target_method, vtable_idx,
                                 direct_code, direct_method, type, skip_this);
   /*
    * First load the non-register arguments.  Both forms expect all
@@ -772,31 +801,31 @@
     } else {
       // Use vldm/vstm pair using kArg3 as a temp
       int regs_left = std::min(info->num_arg_words - 3, 16);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
       LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
       //TUNING: loosen barrier
       ld->def_mask = ENCODE_ALL;
       SetMemRefType(ld, true /* is_load */, kDalvikReg);
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
       LIR* st = OpVstm(TargetReg(kArg3), regs_left);
       SetMemRefType(st, false /* is_load */, kDalvikReg);
       st->def_mask = ENCODE_ALL;
-      call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                                direct_code, direct_method, type);
     }
   }
 
   call_state = LoadArgRegs(info, call_state, next_call_insn,
-                          dex_idx, method_idx, direct_code, direct_method,
-                          type, skip_this);
+                           target_method, vtable_idx, direct_code, direct_method,
+                           type, skip_this);
 
-  call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
+  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
                            direct_code, direct_method, type);
   if (pcrLabel) {
     *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
@@ -1150,6 +1179,10 @@
     // TODO - add Mips implementation
     return false;
   }
+  if (cu_->instruction_set == kX86 && is_object) {
+    // TODO: fix X86, it exhausts registers for card marking.
+    return false;
+  }
   // Unused - RegLocation rl_src_unsafe = info->args[0];
   RegLocation rl_src_obj = info->args[1];  // Object
   RegLocation rl_src_offset = info->args[2];  // long low
@@ -1193,20 +1226,27 @@
    * method.  By doing this during basic block construction, we can also
    * take advantage of/generate new useful dataflow info.
    */
-  std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
-  if (tgt_method.find(" java.lang") != std::string::npos) {
+  StringPiece tgt_methods_declaring_class(
+      cu_->dex_file->GetMethodDeclaringClassDescriptor(cu_->dex_file->GetMethodId(info->index)));
+  if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
       return GenInlinedDoubleCvt(info);
     }
     if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
       return GenInlinedDoubleCvt(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Float;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
       return GenInlinedFloatCvt(info);
     }
     if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
       return GenInlinedFloatCvt(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Math;") ||
+             tgt_methods_declaring_class.starts_with("Ljava/lang/StrictMath;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "int java.lang.Math.abs(int)" ||
         tgt_method == "int java.lang.StrictMath.abs(int)") {
       return GenInlinedAbsInt(info);
@@ -1227,6 +1267,8 @@
         tgt_method == "double java.lang.StrictMath.sqrt(double)") {
       return GenInlinedSqrt(info);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/String;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "char java.lang.String.charAt(int)") {
       return GenInlinedCharAt(info);
     }
@@ -1245,10 +1287,13 @@
     if (tgt_method == "int java.lang.String.length()") {
       return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
     }
+  } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Thread;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
       return GenInlinedCurrentThread(info);
     }
-  } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
+  } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
+    std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
     if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
       return GenInlinedCas32(info, false);
     }
@@ -1327,20 +1372,24 @@
   // Explicit register usage
   LockCallTemps();
 
-  uint32_t dex_method_idx = info->index;
+  DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
+  CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
   int vtable_idx;
   uintptr_t direct_code;
   uintptr_t direct_method;
   bool skip_this;
-  bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
-      dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
-      direct_code, direct_method) && !SLOW_INVOKE_PATH;
+  bool fast_path =
+      cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
+                                              current_dalvik_offset_,
+                                              info->type, target_method,
+                                              vtable_idx,
+                                              direct_code, direct_method,
+                                              true) && !SLOW_INVOKE_PATH;
   if (info->type == kInterface) {
     if (fast_path) {
       p_null_ck = &null_ck;
     }
-    next_call_insn = fast_path ? NextInterfaceCallInsn
-                            : NextInterfaceCallInsnWithAccessCheck;
+    next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
     skip_this = false;
   } else if (info->type == kDirect) {
     if (fast_path) {
@@ -1362,20 +1411,20 @@
   }
   if (!info->is_range) {
     call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
-                                     next_call_insn, dex_method_idx,
-                                     vtable_idx, direct_code, direct_method,
-                                     original_type, skip_this);
+                                      next_call_insn, target_method,
+                                      vtable_idx, direct_code, direct_method,
+                                      original_type, skip_this);
   } else {
     call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
-                                   next_call_insn, dex_method_idx, vtable_idx,
-                                   direct_code, direct_method, original_type,
-                                   skip_this);
+                                    next_call_insn, target_method, vtable_idx,
+                                    direct_code, direct_method, original_type,
+                                    skip_this);
   }
   // Finish up any of the call sequence not interleaved in arg loading
   while (call_state >= 0) {
-    call_state = next_call_insn(cu_, info, call_state, dex_method_idx,
-                             vtable_idx, direct_code, direct_method,
-                             original_type);
+    call_state = next_call_insn(cu_, info, call_state, target_method,
+                                vtable_idx, direct_code, direct_method,
+                                original_type);
   }
   LIR* call_inst;
   if (cu_->instruction_set != kX86) {
diff --git a/src/compiler/dex/quick/gen_loadstore.cc b/src/compiler/dex/quick/gen_loadstore.cc
index 1cebd31..085f7f5 100644
--- a/src/compiler/dex/quick/gen_loadstore.cc
+++ b/src/compiler/dex/quick/gen_loadstore.cc
@@ -16,6 +16,7 @@
 
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "invoke_type.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mips/assemble_mips.cc b/src/compiler/dex/quick/mips/assemble_mips.cc
index 5223a0e..002a23e 100644
--- a/src/compiler/dex/quick/mips/assemble_mips.cc
+++ b/src/compiler/dex/quick/mips/assemble_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mips/call_mips.cc b/src/compiler/dex/quick/mips/call_mips.cc
index b53d1e3..ddaf081 100644
--- a/src/compiler/dex/quick/mips/call_mips.cc
+++ b/src/compiler/dex/quick/mips/call_mips.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
@@ -319,7 +320,7 @@
   int reg_card_no = AllocTemp();
   LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   LoadWordDisp(rMIPS_SELF, Thread::CardTableOffset().Int32Value(), reg_card_base);
-  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, CardTable::kCardShift);
+  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0,
                    kUnsignedByte);
   LIR* target = NewLIR0(kPseudoTargetLabel);
diff --git a/src/compiler/dex/quick/mips/codegen_mips.h b/src/compiler/dex/quick/mips/codegen_mips.h
index db262a8..9fa8f77 100644
--- a/src/compiler/dex/quick/mips/codegen_mips.h
+++ b/src/compiler/dex/quick/mips/codegen_mips.h
@@ -28,139 +28,139 @@
     MipsMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen utilities.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
-    virtual int LoadHelper(int offset);
-    virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
-    virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+    int LoadHelper(int offset);
+    LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+    LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
                                   int s_reg);
-    virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
-    virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+    LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                      int r_dest, int r_dest_hi, OpSize size, int s_reg);
-    virtual LIR* LoadConstantNoClobber(int r_dest, int value);
-    virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
-    virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
-    virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
-    virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
-    virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadConstantNoClobber(int r_dest, int value);
+    LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+    LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+    LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+    LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+    LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                       int r_src, int r_src_hi, OpSize size, int s_reg);
-    virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+    void MarkGCCard(int val_reg, int tgt_addr_reg);
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg);
-    virtual bool SameRegType(int reg1, int reg2);
-    virtual int AllocTypedTemp(bool fp_hint, int reg_class);
-    virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
-    virtual int S2d(int low_reg, int high_reg);
-    virtual int TargetReg(SpecialTargetRegister reg);
-    virtual RegisterInfo* GetRegInfo(int reg);
-    virtual RegLocation GetReturnAlt();
-    virtual RegLocation GetReturnWideAlt();
-    virtual RegLocation LocCReturn();
-    virtual RegLocation LocCReturnDouble();
-    virtual RegLocation LocCReturnFloat();
-    virtual RegLocation LocCReturnWide();
-    virtual uint32_t FpRegMask();
-    virtual uint64_t GetRegMaskCommon(int reg);
-    virtual void AdjustSpillMask();
-    virtual void ClobberCalleeSave();
-    virtual void FlushReg(int reg);
-    virtual void FlushRegWide(int reg1, int reg2);
-    virtual void FreeCallTemps();
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
-    virtual void LockCallTemps();
-    virtual void MarkPreservedSingle(int v_reg, int reg);
-    virtual void CompilerInitializeRegAlloc();
+    bool IsFpReg(int reg);
+    bool SameRegType(int reg1, int reg2);
+    int AllocTypedTemp(bool fp_hint, int reg_class);
+    int AllocTypedTempPair(bool fp_hint, int reg_class);
+    int S2d(int low_reg, int high_reg);
+    int TargetReg(SpecialTargetRegister reg);
+    RegisterInfo* GetRegInfo(int reg);
+    RegLocation GetReturnAlt();
+    RegLocation GetReturnWideAlt();
+    RegLocation LocCReturn();
+    RegLocation LocCReturnDouble();
+    RegLocation LocCReturnFloat();
+    RegLocation LocCReturnWide();
+    uint32_t FpRegMask();
+    uint64_t GetRegMaskCommon(int reg);
+    void AdjustSpillMask();
+    void ClobberCalleeSave();
+    void FlushReg(int reg);
+    void FlushRegWide(int reg1, int reg2);
+    void FreeCallTemps();
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+    void LockCallTemps();
+    void MarkPreservedSingle(int v_reg, int reg);
+    void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
-    virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
-    virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
-    virtual void SetupTargetResourceMasks(LIR* lir);
-    virtual const char* GetTargetInstFmt(int opcode);
-    virtual const char* GetTargetInstName(int opcode);
-    virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
-    virtual uint64_t GetPCUseDefEncoding();
-    virtual uint64_t GetTargetInstFlags(int opcode);
-    virtual int GetInsnSize(LIR* lir);
-    virtual bool IsUnconditionalBranch(LIR* lir);
+    AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+    void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+    void SetupTargetResourceMasks(LIR* lir);
+    const char* GetTargetInstFmt(int opcode);
+    const char* GetTargetInstName(int opcode);
+    std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+    uint64_t GetPCUseDefEncoding();
+    uint64_t GetTargetInstFlags(int opcode);
+    int GetInsnSize(LIR* lir);
+    bool IsUnconditionalBranch(LIR* lir);
 
     // Required for target - Dalvik-level generators.
-    virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
+    void GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index,
                                 RegLocation rl_src, int scale);
-    virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale);
-    virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_shift);
-    virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+    void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
                                   RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
                                  RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+    void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                           RegLocation rl_src2);
-    virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
-    virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
-    virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
-    virtual bool GenInlinedSqrt(CallInfo* info);
-    virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+    void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+    bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+    bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+    bool GenInlinedSqrt(CallInfo* info);
+    void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+    void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
                                 ThrowKind kind);
-    virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
-    virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
-    virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
-    virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual void GenExitSequence();
-    virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
-    virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
-    virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
-    virtual void GenSelect(BasicBlock* bb, MIR* mir);
-    virtual void GenMemBarrier(MemBarrierKind barrier_kind);
-    virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
-    virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
-    virtual void GenMoveException(RegLocation rl_dest);
-    virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
+    RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+    RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+    void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenDivZeroCheck(int reg_lo, int reg_hi);
+    void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+    void GenExitSequence();
+    void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+    void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+    void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+    void GenSelect(BasicBlock* bb, MIR* mir);
+    void GenMemBarrier(MemBarrierKind barrier_kind);
+    void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+    void GenMonitorExit(int opt_flags, RegLocation rl_src);
+    void GenMoveException(RegLocation rl_dest);
+    void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit,
                                                int first_bit, int second_bit);
-    virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+    void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+    void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+    void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
 
     // Required for target - single operation generators.
-    virtual LIR* OpUnconditionalBranch(LIR* target);
-    virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
-    virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
-    virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
-    virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
-    virtual LIR* OpFpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpIT(ConditionCode cond, const char* guide);
-    virtual LIR* OpMem(OpKind op, int rBase, int disp);
-    virtual LIR* OpPcRelLoad(int reg, LIR* target);
-    virtual LIR* OpReg(OpKind op, int r_dest_src);
-    virtual LIR* OpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
-    virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
-    virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
-    virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
-    virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
-    virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
-    virtual LIR* OpTestSuspend(LIR* target);
-    virtual LIR* OpThreadMem(OpKind op, int thread_offset);
-    virtual LIR* OpVldm(int rBase, int count);
-    virtual LIR* OpVstm(int rBase, int count);
-    virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
-    virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
-    virtual void OpTlsCmp(int offset, int val);
+    LIR* OpUnconditionalBranch(LIR* target);
+    LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+    LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+    LIR* OpCondBranch(ConditionCode cc, LIR* target);
+    LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+    LIR* OpFpRegCopy(int r_dest, int r_src);
+    LIR* OpIT(ConditionCode cond, const char* guide);
+    LIR* OpMem(OpKind op, int rBase, int disp);
+    LIR* OpPcRelLoad(int reg, LIR* target);
+    LIR* OpReg(OpKind op, int r_dest_src);
+    LIR* OpRegCopy(int r_dest, int r_src);
+    LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+    LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+    LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+    LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+    LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+    LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+    LIR* OpTestSuspend(LIR* target);
+    LIR* OpThreadMem(OpKind op, int thread_offset);
+    LIR* OpVldm(int rBase, int count);
+    LIR* OpVstm(int rBase, int count);
+    void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+    void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+    void OpTlsCmp(int offset, int val);
 
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
                           int s_reg);
diff --git a/src/compiler/dex/quick/mips/fp_mips.cc b/src/compiler/dex/quick/mips/fp_mips.cc
index 5ddec00..f384da1 100644
--- a/src/compiler/dex/quick/mips/fp_mips.cc
+++ b/src/compiler/dex/quick/mips/fp_mips.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_mips.h"
 #include "mips_lir.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "oat/runtime/oat_support_entrypoints.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mips/int_mips.cc b/src/compiler/dex/quick/mips/int_mips.cc
index fbff397..fe9e83f 100644
--- a/src/compiler/dex/quick/mips/int_mips.cc
+++ b/src/compiler/dex/quick/mips/int_mips.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the Mips ISA */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 #include "mirror/array.h"
 #include "oat/runtime/oat_support_entrypoints.h"
diff --git a/src/compiler/dex/quick/mips/target_mips.cc b/src/compiler/dex/quick/mips/target_mips.cc
index 46a625e..356104c 100644
--- a/src/compiler/dex/quick/mips/target_mips.cc
+++ b/src/compiler/dex/quick/mips/target_mips.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_mips.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
 #include <string>
diff --git a/src/compiler/dex/quick/mips/utility_mips.cc b/src/compiler/dex/quick/mips/utility_mips.cc
index 5f9f8c5..257b0f6 100644
--- a/src/compiler/dex/quick/mips/utility_mips.cc
+++ b/src/compiler/dex/quick/mips/utility_mips.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_mips.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "mips_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/mir_to_lir-inl.h b/src/compiler/dex/quick/mir_to_lir-inl.h
new file mode 100644
index 0000000..f754692
--- /dev/null
+++ b/src/compiler/dex/quick/mir_to_lir-inl.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
+#define ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
+
+#include "mir_to_lir.h"
+
+#include "compiler/dex/compiler_internals.h"
+
+namespace art {
+
+/* Mark a temp register as dead.  Does not affect allocation state. */
+inline void Mir2Lir::ClobberBody(RegisterInfo* p) {
+  if (p->is_temp) {
+    DCHECK(!(p->live && p->dirty))  << "Live & dirty temp in clobber";
+    p->live = false;
+    p->s_reg = INVALID_SREG;
+    p->def_start = NULL;
+    p->def_end = NULL;
+    if (p->pair) {
+      p->pair = false;
+      Clobber(p->partner);
+    }
+  }
+}
+
+inline LIR* Mir2Lir::RawLIR(int dalvik_offset, int opcode, int op0,
+                            int op1, int op2, int op3, int op4, LIR* target) {
+  LIR* insn = static_cast<LIR*>(arena_->NewMem(sizeof(LIR), true, ArenaAllocator::kAllocLIR));
+  insn->dalvik_offset = dalvik_offset;
+  insn->opcode = opcode;
+  insn->operands[0] = op0;
+  insn->operands[1] = op1;
+  insn->operands[2] = op2;
+  insn->operands[3] = op3;
+  insn->operands[4] = op4;
+  insn->target = target;
+  SetupResourceMasks(insn);
+  if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) ||
+      (opcode == kPseudoExportedPC)) {
+    // Always make labels scheduling barriers
+    insn->use_mask = insn->def_mask = ENCODE_ALL;
+  }
+  return insn;
+}
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 4
+ * operands.
+ */
+inline LIR* Mir2Lir::NewLIR0(int opcode) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR1(int opcode, int dest) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR2(int opcode, int dest, int src1) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR3(int opcode, int dest, int src1, int src2) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR4(int opcode, int dest, int src1, int src2, int info) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info);
+  AppendLIR(insn);
+  return insn;
+}
+
+inline LIR* Mir2Lir::NewLIR5(int opcode, int dest, int src1, int src2, int info1,
+                             int info2) {
+  DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP))
+      << GetTargetInstName(opcode) << " " << opcode << " "
+      << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " "
+      << current_dalvik_offset_;
+  LIR* insn = RawLIR(current_dalvik_offset_, opcode, dest, src1, src2, info1, info2);
+  AppendLIR(insn);
+  return insn;
+}
+
+/*
+ * Mark the corresponding bit(s).
+ */
+inline void Mir2Lir::SetupRegMask(uint64_t* mask, int reg) {
+  *mask |= GetRegMaskCommon(reg);
+}
+
+/*
+ * Set up the proper fields in the resource mask
+ */
+inline void Mir2Lir::SetupResourceMasks(LIR* lir) {
+  int opcode = lir->opcode;
+
+  if (opcode <= 0) {
+    lir->use_mask = lir->def_mask = 0;
+    return;
+  }
+
+  uint64_t flags = GetTargetInstFlags(opcode);
+
+  if (flags & NEEDS_FIXUP) {
+    lir->flags.pcRelFixup = true;
+  }
+
+  /* Get the starting size of the instruction's template */
+  lir->flags.size = GetInsnSize(lir);
+
+  /* Set up the mask for resources that are updated */
+  if (flags & (IS_LOAD | IS_STORE)) {
+    /* Default to heap - will catch specialized classes later */
+    SetMemRefType(lir, flags & IS_LOAD, kHeapRef);
+  }
+
+  /*
+   * Conservatively assume the branch here will call out a function that in
+   * turn will trash everything.
+   */
+  if (flags & IS_BRANCH) {
+    lir->def_mask = lir->use_mask = ENCODE_ALL;
+    return;
+  }
+
+  if (flags & REG_DEF0) {
+    SetupRegMask(&lir->def_mask, lir->operands[0]);
+  }
+
+  if (flags & REG_DEF1) {
+    SetupRegMask(&lir->def_mask, lir->operands[1]);
+  }
+
+
+  if (flags & SETS_CCODES) {
+    lir->def_mask |= ENCODE_CCODE;
+  }
+
+  if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
+    int i;
+
+    for (i = 0; i < 4; i++) {
+      if (flags & (1 << (kRegUse0 + i))) {
+        SetupRegMask(&lir->use_mask, lir->operands[i]);
+      }
+    }
+  }
+
+  if (flags & USES_CCODES) {
+    lir->use_mask |= ENCODE_CCODE;
+  }
+
+  // Handle target-specific actions
+  SetupTargetResourceMasks(lir);
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_INL_H_
diff --git a/src/compiler/dex/quick/mir_to_lir.cc b/src/compiler/dex/quick/mir_to_lir.cc
index 481078d..754aae4 100644
--- a/src/compiler/dex/quick/mir_to_lir.cc
+++ b/src/compiler/dex/quick/mir_to_lir.cc
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include "object_utils.h"
-
 #include "compiler/dex/compiler_internals.h"
-#include "compiler/dex/dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
+#include "mir_to_lir-inl.h"
+#include "object_utils.h"
 
 namespace art {
 
@@ -184,10 +184,10 @@
       GenMonitorExit(opt_flags, rl_src[0]);
       break;
 
-    case Instruction::CHECK_CAST:
-      GenCheckCast(vB, rl_src[0]);
+    case Instruction::CHECK_CAST: {
+      GenCheckCast(mir->offset, vB, rl_src[0]);
       break;
-
+    }
     case Instruction::INSTANCE_OF:
       GenInstanceof(vC, rl_dest, rl_src[0]);
       break;
diff --git a/src/compiler/dex/quick/mir_to_lir.h b/src/compiler/dex/quick/mir_to_lir.h
index 21a0aac..9eb4524 100644
--- a/src/compiler/dex/quick/mir_to_lir.h
+++ b/src/compiler/dex/quick/mir_to_lir.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
-#define ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
+#ifndef ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
+#define ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
 
 #include "invoke_type.h"
 #include "compiled_method.h"
@@ -24,6 +24,7 @@
 #include "compiler/dex/backend.h"
 #include "compiler/dex/growable_array.h"
 #include "compiler/dex/arena_allocator.h"
+#include "compiler/driver/compiler_driver.h"
 #include "safe_map.h"
 
 namespace art {
@@ -98,7 +99,8 @@
 class MIRGraph;
 class Mir2Lir;
 
-typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int, uint32_t dex_idx,
+typedef int (*NextCallInsn)(CompilationUnit*, CallInfo*, int,
+                            const CompilerDriver::MethodReference& target_method,
                             uint32_t method_idx, uintptr_t direct_code,
                             uintptr_t direct_method, InvokeType type);
 
@@ -312,8 +314,10 @@
     void DumpRegPool(RegisterInfo* p, int num_regs);
     void DumpCoreRegPool();
     void DumpFpRegPool();
-    void ClobberBody(RegisterInfo* p);
-    void Clobber(int reg);
+    /* Mark a temp register as dead.  Does not affect allocation state. */
+    void Clobber(int reg) {
+      ClobberBody(GetRegInfo(reg));
+    }
     void ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg);
     void ClobberSReg(int s_reg);
     int SRegToPMap(int s_reg);
@@ -337,7 +341,6 @@
     RegisterInfo* IsPromoted(int reg);
     bool IsDirty(int reg);
     void LockTemp(int reg);
-    void ResetDefBody(RegisterInfo* p);
     void ResetDef(int reg);
     void NullifyRange(LIR *start, LIR *finish, int s_reg1, int s_reg2);
     void MarkDef(RegLocation rl, LIR *start, LIR *finish);
@@ -410,7 +413,8 @@
     void GenThrow(RegLocation rl_src);
     void GenInstanceof(uint32_t type_idx, RegLocation rl_dest,
                        RegLocation rl_src);
-    void GenCheckCast(uint32_t type_idx, RegLocation rl_src);
+    void GenCheckCast(uint32_t insn_idx, uint32_t type_idx,
+                      RegLocation rl_src);
     void GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest,
                       RegLocation rl_src1, RegLocation rl_src2);
     void GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
@@ -462,11 +466,15 @@
     void GenInvoke(CallInfo* info);
     void FlushIns(RegLocation* ArgLocs, RegLocation rl_method);
     int GenDalvikArgsNoRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                             NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                             NextCallInsn next_call_insn,
+                             const CompilerDriver::MethodReference& target_method,
+                             uint32_t vtable_idx,
                              uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                              bool skip_this);
     int GenDalvikArgsRange(CallInfo* info, int call_state, LIR** pcrLabel,
-                           NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                           NextCallInsn next_call_insn,
+                           const CompilerDriver::MethodReference& target_method,
+                           uint32_t vtable_idx,
                            uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                            bool skip_this);
     RegLocation InlineTarget(CallInfo* info);
@@ -486,7 +494,9 @@
                              bool is_volatile, bool is_ordered);
     bool GenIntrinsic(CallInfo* info);
     int LoadArgRegs(CallInfo* info, int call_state,
-                    NextCallInsn next_call_insn, uint32_t dex_idx, uint32_t method_idx,
+                    NextCallInsn next_call_insn,
+                    const CompilerDriver::MethodReference& target_method,
+                    uint32_t vtable_idx,
                     uintptr_t direct_code, uintptr_t direct_method, InvokeType type,
                     bool skip_this);
 
@@ -681,11 +691,6 @@
     // Temp workaround
     void Workaround7250540(RegLocation rl_dest, int value);
 
-    // TODO: add accessors for these.
-    LIR* literal_list_;                        // Constants.
-    LIR* method_literal_list_;                 // Method literals requiring patching.
-    LIR* code_literal_list_;                   // Code literals requiring patching.
-
   protected:
     Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
@@ -693,6 +698,28 @@
       return cu_;
     }
 
+  private:
+    void GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest,
+                            RegLocation rl_src);
+    void GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final,
+                                    bool type_known_abstract, bool use_declaring_class,
+                                    bool can_assume_type_is_in_dex_cache,
+                                    uint32_t type_idx, RegLocation rl_dest,
+                                    RegLocation rl_src);
+
+    void ClobberBody(RegisterInfo* p);
+    void ResetDefBody(RegisterInfo* p) {
+      p->def_start = NULL;
+      p->def_end = NULL;
+    }
+
+  public:
+    // TODO: add accessors for these.
+    LIR* literal_list_;                        // Constants.
+    LIR* method_literal_list_;                 // Method literals requiring patching.
+    LIR* code_literal_list_;                   // Code literals requiring patching.
+
+  protected:
     CompilationUnit* const cu_;
     MIRGraph* const mir_graph_;
     GrowableArray<SwitchTable*> switch_tables_;
@@ -749,4 +776,4 @@
 
 }  // namespace art
 
-#endif // ART_SRC_COMPILER_DEX_QUICK_CODEGEN_H_
+#endif  //ART_SRC_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
diff --git a/src/compiler/dex/quick/ralloc_util.cc b/src/compiler/dex/quick/ralloc_util.cc
index 30ed1b7..8e0dba3 100644
--- a/src/compiler/dex/quick/ralloc_util.cc
+++ b/src/compiler/dex/quick/ralloc_util.cc
@@ -18,6 +18,7 @@
 
 #include "compiler/dex/compiler_ir.h"
 #include "compiler/dex/compiler_internals.h"
+#include "mir_to_lir-inl.h"
 
 namespace art {
 
@@ -84,28 +85,6 @@
   DumpRegPool(reg_pool_->FPRegs, reg_pool_->num_fp_regs);
 }
 
-/* Mark a temp register as dead.  Does not affect allocation state. */
-void Mir2Lir::ClobberBody(RegisterInfo* p)
-{
-  if (p->is_temp) {
-    DCHECK(!(p->live && p->dirty))  << "Live & dirty temp in clobber";
-    p->live = false;
-    p->s_reg = INVALID_SREG;
-    p->def_start = NULL;
-    p->def_end = NULL;
-    if (p->pair) {
-      p->pair = false;
-      Clobber(p->partner);
-    }
-  }
-}
-
-/* Mark a temp register as dead.  Does not affect allocation state. */
-void Mir2Lir::Clobber(int reg)
-{
-  ClobberBody(GetRegInfo(reg));
-}
-
 void Mir2Lir::ClobberSRegBody(RegisterInfo* p, int num_regs, int s_reg)
 {
   int i;
@@ -555,12 +534,6 @@
   LOG(FATAL) << "Tried to lock a non-existant temp: r" << reg;
 }
 
-void Mir2Lir::ResetDefBody(RegisterInfo* p)
-{
-  p->def_start = NULL;
-  p->def_end = NULL;
-}
-
 void Mir2Lir::ResetDef(int reg)
 {
   ResetDefBody(GetRegInfo(reg));
diff --git a/src/compiler/dex/quick/x86/assemble_x86.cc b/src/compiler/dex/quick/x86/assemble_x86.cc
index f7c1594..83dabe6 100644
--- a/src/compiler/dex/quick/x86/assemble_x86.cc
+++ b/src/compiler/dex/quick/x86/assemble_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/call_x86.cc b/src/compiler/dex/quick/x86/call_x86.cc
index 614a72d..dba0e24 100644
--- a/src/compiler/dex/quick/x86/call_x86.cc
+++ b/src/compiler/dex/quick/x86/call_x86.cc
@@ -17,6 +17,7 @@
 /* This file contains codegen for the X86 ISA */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
@@ -212,7 +213,7 @@
   int reg_card_no = AllocTemp();
   LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
   NewLIR2(kX86Mov32RT, reg_card_base, Thread::CardTableOffset().Int32Value());
-  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, CardTable::kCardShift);
+  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
   StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0,
                    kUnsignedByte);
   LIR* target = NewLIR0(kPseudoTargetLabel);
diff --git a/src/compiler/dex/quick/x86/codegen_x86.h b/src/compiler/dex/quick/x86/codegen_x86.h
index 99e5148..9050656 100644
--- a/src/compiler/dex/quick/x86/codegen_x86.h
+++ b/src/compiler/dex/quick/x86/codegen_x86.h
@@ -28,139 +28,139 @@
     X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena);
 
     // Required for target - codegen helpers.
-    virtual bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
+    bool SmallLiteralDivide(Instruction::Code dalvik_opcode, RegLocation rl_src,
                                     RegLocation rl_dest, int lit);
-    virtual int LoadHelper(int offset);
-    virtual LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
-    virtual LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
+    int LoadHelper(int offset);
+    LIR* LoadBaseDisp(int rBase, int displacement, int r_dest, OpSize size, int s_reg);
+    LIR* LoadBaseDispWide(int rBase, int displacement, int r_dest_lo, int r_dest_hi,
                                   int s_reg);
-    virtual LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
-    virtual LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadBaseIndexed(int rBase, int r_index, int r_dest, int scale, OpSize size);
+    LIR* LoadBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                      int r_dest, int r_dest_hi, OpSize size, int s_reg);
-    virtual LIR* LoadConstantNoClobber(int r_dest, int value);
-    virtual LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
-    virtual LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
-    virtual LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
-    virtual LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
-    virtual LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
+    LIR* LoadConstantNoClobber(int r_dest, int value);
+    LIR* LoadConstantWide(int r_dest_lo, int r_dest_hi, int64_t value);
+    LIR* StoreBaseDisp(int rBase, int displacement, int r_src, OpSize size);
+    LIR* StoreBaseDispWide(int rBase, int displacement, int r_src_lo, int r_src_hi);
+    LIR* StoreBaseIndexed(int rBase, int r_index, int r_src, int scale, OpSize size);
+    LIR* StoreBaseIndexedDisp(int rBase, int r_index, int scale, int displacement,
                                       int r_src, int r_src_hi, OpSize size, int s_reg);
-    virtual void MarkGCCard(int val_reg, int tgt_addr_reg);
+    void MarkGCCard(int val_reg, int tgt_addr_reg);
 
     // Required for target - register utilities.
-    virtual bool IsFpReg(int reg);
-    virtual bool SameRegType(int reg1, int reg2);
-    virtual int AllocTypedTemp(bool fp_hint, int reg_class);
-    virtual int AllocTypedTempPair(bool fp_hint, int reg_class);
-    virtual int S2d(int low_reg, int high_reg);
-    virtual int TargetReg(SpecialTargetRegister reg);
-    virtual RegisterInfo* GetRegInfo(int reg);
-    virtual RegLocation GetReturnAlt();
-    virtual RegLocation GetReturnWideAlt();
-    virtual RegLocation LocCReturn();
-    virtual RegLocation LocCReturnDouble();
-    virtual RegLocation LocCReturnFloat();
-    virtual RegLocation LocCReturnWide();
-    virtual uint32_t FpRegMask();
-    virtual uint64_t GetRegMaskCommon(int reg);
-    virtual void AdjustSpillMask();
-    virtual void ClobberCalleeSave();
-    virtual void FlushReg(int reg);
-    virtual void FlushRegWide(int reg1, int reg2);
-    virtual void FreeCallTemps();
-    virtual void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
-    virtual void LockCallTemps();
-    virtual void MarkPreservedSingle(int v_reg, int reg);
-    virtual void CompilerInitializeRegAlloc();
+    bool IsFpReg(int reg);
+    bool SameRegType(int reg1, int reg2);
+    int AllocTypedTemp(bool fp_hint, int reg_class);
+    int AllocTypedTempPair(bool fp_hint, int reg_class);
+    int S2d(int low_reg, int high_reg);
+    int TargetReg(SpecialTargetRegister reg);
+    RegisterInfo* GetRegInfo(int reg);
+    RegLocation GetReturnAlt();
+    RegLocation GetReturnWideAlt();
+    RegLocation LocCReturn();
+    RegLocation LocCReturnDouble();
+    RegLocation LocCReturnFloat();
+    RegLocation LocCReturnWide();
+    uint32_t FpRegMask();
+    uint64_t GetRegMaskCommon(int reg);
+    void AdjustSpillMask();
+    void ClobberCalleeSave();
+    void FlushReg(int reg);
+    void FlushRegWide(int reg1, int reg2);
+    void FreeCallTemps();
+    void FreeRegLocTemps(RegLocation rl_keep, RegLocation rl_free);
+    void LockCallTemps();
+    void MarkPreservedSingle(int v_reg, int reg);
+    void CompilerInitializeRegAlloc();
 
     // Required for target - miscellaneous.
-    virtual AssemblerStatus AssembleInstructions(uintptr_t start_addr);
-    virtual void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
-    virtual void SetupTargetResourceMasks(LIR* lir);
-    virtual const char* GetTargetInstFmt(int opcode);
-    virtual const char* GetTargetInstName(int opcode);
-    virtual std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
-    virtual uint64_t GetPCUseDefEncoding();
-    virtual uint64_t GetTargetInstFlags(int opcode);
-    virtual int GetInsnSize(LIR* lir);
-    virtual bool IsUnconditionalBranch(LIR* lir);
+    AssemblerStatus AssembleInstructions(uintptr_t start_addr);
+    void DumpResourceMask(LIR* lir, uint64_t mask, const char* prefix);
+    void SetupTargetResourceMasks(LIR* lir);
+    const char* GetTargetInstFmt(int opcode);
+    const char* GetTargetInstName(int opcode);
+    std::string BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr);
+    uint64_t GetPCUseDefEncoding();
+    uint64_t GetTargetInstFlags(int opcode);
+    int GetInsnSize(LIR* lir);
+    bool IsUnconditionalBranch(LIR* lir);
 
     // Required for target - Dalvik-level generators.
-    virtual void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArrayObjPut(int opt_flags, RegLocation rl_array,
+    void GenArrayObjPut(int opt_flags, RegLocation rl_array,
                                 RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale);
-    virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
+    void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_src, int scale);
-    virtual void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
+    void GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest,
                                    RegLocation rl_src1, RegLocation rl_shift);
-    virtual void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
+    void GenMulLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAddLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenAndLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenArithOpDouble(Instruction::Code opcode, RegLocation rl_dest,
                                   RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
+    void GenArithOpFloat(Instruction::Code opcode, RegLocation rl_dest,
                                  RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
+    void GenCmpFP(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src1,
                           RegLocation rl_src2);
-    virtual void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
-    virtual bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
-    virtual bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
-    virtual bool GenInlinedSqrt(CallInfo* info);
-    virtual void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
+    void GenConversion(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src);
+    bool GenInlinedCas32(CallInfo* info, bool need_write_barrier);
+    bool GenInlinedMinMaxInt(CallInfo* info, bool is_min);
+    bool GenInlinedSqrt(CallInfo* info);
+    void GenNegLong(RegLocation rl_dest, RegLocation rl_src);
+    void GenOrLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenSubLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenXorLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    LIR* GenRegMemCheck(ConditionCode c_code, int reg1, int base, int offset,
                                 ThrowKind kind);
-    virtual RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
-    virtual RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
-    virtual void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
-    virtual void GenDivZeroCheck(int reg_lo, int reg_hi);
-    virtual void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
-    virtual void GenExitSequence();
-    virtual void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
-    virtual void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
-    virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
-    virtual void GenSelect(BasicBlock* bb, MIR* mir);
-    virtual void GenMemBarrier(MemBarrierKind barrier_kind);
-    virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
-    virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
-    virtual void GenMoveException(RegLocation rl_dest);
-    virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result,
+    RegLocation GenDivRem(RegLocation rl_dest, int reg_lo, int reg_hi, bool is_div);
+    RegLocation GenDivRemLit(RegLocation rl_dest, int reg_lo, int lit, bool is_div);
+    void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
+    void GenDivZeroCheck(int reg_lo, int reg_hi);
+    void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
+    void GenExitSequence();
+    void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
+    void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
+    void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
+    void GenSelect(BasicBlock* bb, MIR* mir);
+    void GenMemBarrier(MemBarrierKind barrier_kind);
+    void GenMonitorEnter(int opt_flags, RegLocation rl_src);
+    void GenMonitorExit(int opt_flags, RegLocation rl_src);
+    void GenMoveException(RegLocation rl_dest);
+    void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result,
                                                int lit, int first_bit, int second_bit);
-    virtual void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
-    virtual void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
+    void GenNegDouble(RegLocation rl_dest, RegLocation rl_src);
+    void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
+    void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
+    void GenSpecialCase(BasicBlock* bb, MIR* mir, SpecialCaseHandler special_case);
 
     // Single operation generators.
-    virtual LIR* OpUnconditionalBranch(LIR* target);
-    virtual LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
-    virtual LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
-    virtual LIR* OpCondBranch(ConditionCode cc, LIR* target);
-    virtual LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
-    virtual LIR* OpFpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpIT(ConditionCode cond, const char* guide);
-    virtual LIR* OpMem(OpKind op, int rBase, int disp);
-    virtual LIR* OpPcRelLoad(int reg, LIR* target);
-    virtual LIR* OpReg(OpKind op, int r_dest_src);
-    virtual LIR* OpRegCopy(int r_dest, int r_src);
-    virtual LIR* OpRegCopyNoInsert(int r_dest, int r_src);
-    virtual LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
-    virtual LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
-    virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
-    virtual LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
-    virtual LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
-    virtual LIR* OpTestSuspend(LIR* target);
-    virtual LIR* OpThreadMem(OpKind op, int thread_offset);
-    virtual LIR* OpVldm(int rBase, int count);
-    virtual LIR* OpVstm(int rBase, int count);
-    virtual void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
-    virtual void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
-    virtual void OpTlsCmp(int offset, int val);
+    LIR* OpUnconditionalBranch(LIR* target);
+    LIR* OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target);
+    LIR* OpCmpImmBranch(ConditionCode cond, int reg, int check_value, LIR* target);
+    LIR* OpCondBranch(ConditionCode cc, LIR* target);
+    LIR* OpDecAndBranch(ConditionCode c_code, int reg, LIR* target);
+    LIR* OpFpRegCopy(int r_dest, int r_src);
+    LIR* OpIT(ConditionCode cond, const char* guide);
+    LIR* OpMem(OpKind op, int rBase, int disp);
+    LIR* OpPcRelLoad(int reg, LIR* target);
+    LIR* OpReg(OpKind op, int r_dest_src);
+    LIR* OpRegCopy(int r_dest, int r_src);
+    LIR* OpRegCopyNoInsert(int r_dest, int r_src);
+    LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
+    LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
+    LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+    LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
+    LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
+    LIR* OpTestSuspend(LIR* target);
+    LIR* OpThreadMem(OpKind op, int thread_offset);
+    LIR* OpVldm(int rBase, int count);
+    LIR* OpVstm(int rBase, int count);
+    void OpLea(int rBase, int reg1, int reg2, int scale, int offset);
+    void OpRegCopyWide(int dest_lo, int dest_hi, int src_lo, int src_hi);
+    void OpTlsCmp(int offset, int val);
 
     void OpRegThreadMem(OpKind op, int r_dest, int thread_offset);
     void SpillCoreRegs();
diff --git a/src/compiler/dex/quick/x86/fp_x86.cc b/src/compiler/dex/quick/x86/fp_x86.cc
index db2cf28..3341e28 100644
--- a/src/compiler/dex/quick/x86/fp_x86.cc
+++ b/src/compiler/dex/quick/x86/fp_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/int_x86.cc b/src/compiler/dex/quick/x86/int_x86.cc
index b2ee949..fffb900 100644
--- a/src/compiler/dex/quick/x86/int_x86.cc
+++ b/src/compiler/dex/quick/x86/int_x86.cc
@@ -18,6 +18,7 @@
 
 #include "codegen_x86.h"
 #include "mirror/array.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/quick/x86/target_x86.cc b/src/compiler/dex/quick/x86/target_x86.cc
index e6a49f8..9110b70 100644
--- a/src/compiler/dex/quick/x86/target_x86.cc
+++ b/src/compiler/dex/quick/x86/target_x86.cc
@@ -16,6 +16,7 @@
 
 #include "codegen_x86.h"
 #include "compiler/dex/compiler_internals.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 #include <string>
diff --git a/src/compiler/dex/quick/x86/utility_x86.cc b/src/compiler/dex/quick/x86/utility_x86.cc
index 45c0e9c..82466d4 100644
--- a/src/compiler/dex/quick/x86/utility_x86.cc
+++ b/src/compiler/dex/quick/x86/utility_x86.cc
@@ -15,6 +15,7 @@
  */
 
 #include "codegen_x86.h"
+#include "compiler/dex/quick/mir_to_lir-inl.h"
 #include "x86_lir.h"
 
 namespace art {
diff --git a/src/compiler/dex/ssa_transformation.cc b/src/compiler/dex/ssa_transformation.cc
index a90d705..4182072 100644
--- a/src/compiler/dex/ssa_transformation.cc
+++ b/src/compiler/dex/ssa_transformation.cc
@@ -15,7 +15,7 @@
  */
 
 #include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "dataflow_iterator-inl.h"
 
 #define NOTVISITED (-1)
 
diff --git a/src/compiler/dex/vreg_analysis.cc b/src/compiler/dex/vreg_analysis.cc
index d4223f1..b941140 100644
--- a/src/compiler/dex/vreg_analysis.cc
+++ b/src/compiler/dex/vreg_analysis.cc
@@ -15,7 +15,7 @@
  */
 
 #include "compiler_internals.h"
-#include "dataflow_iterator.h"
+#include "compiler/dex/dataflow_iterator-inl.h"
 
 namespace art {
 
@@ -292,18 +292,10 @@
           is_high |= is_phi && rl_temp.wide && rl_temp.high_word;
         }
         /*
-         * TODO: cleaner fix
-         * We don't normally expect to see a Dalvik register
-         * definition used both as a floating point and core
-         * value.  However, the instruction rewriting that occurs
-         * during verification can eliminate some type information,
-         * leaving us confused.  The real fix here is either to
-         * add explicit type information to Dalvik byte codes,
-         * or to recognize THROW_VERIFICATION_ERROR as
-         * an unconditional branch and support dead code elimination.
-         * As a workaround we can detect this situation and
-         * disable register promotion (which is the only thing that
-         * relies on distinctions between core and fp usages.
+         * We don't normally expect to see a Dalvik register definition used both as a
+         * floating point and core value, though technically it could happen with constants.
+         * Until we have proper typing, detect this situation and disable register promotion
+         * (which relies on the distinction between core a fp usages).
          */
         if ((defined_fp && (defined_core | defined_ref)) &&
             ((cu_->disable_opt & (1 << kPromoteRegs)) == 0)) {
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 6985172..6050108 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -24,17 +24,19 @@
 #include "base/stl_util.h"
 #include "base/timing_logger.h"
 #include "class_linker.h"
+#include "compiler/stubs/stubs.h"
 #include "dex_compilation_unit.h"
 #include "dex_file-inl.h"
 #include "jni_internal.h"
 #include "oat_file.h"
 #include "object_utils.h"
 #include "runtime.h"
-#include "gc/card_table-inl.h"
-#include "gc/space.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/space/space.h"
 #include "mirror/class_loader.h"
 #include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
@@ -72,7 +74,8 @@
         resolved_types_(0), unresolved_types_(0),
         resolved_instance_fields_(0), unresolved_instance_fields_(0),
         resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
-        type_based_devirtualization_(0) {
+        type_based_devirtualization_(0),
+        safe_casts_(0), not_safe_casts_(0) {
     for (size_t i = 0; i <= kMaxInvokeType; i++) {
       resolved_methods_[i] = 0;
       unresolved_methods_[i] = 0;
@@ -91,8 +94,14 @@
              "static fields resolved");
     DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
              "static fields local to a class");
-    DumpStat(type_based_devirtualization_,virtual_made_direct_[kInterface] + virtual_made_direct_[kVirtual]
-             - type_based_devirtualization_, "sharpened calls based on type information");
+    DumpStat(safe_casts_, not_safe_casts_, "check-casts removed based on type information");
+    // Note, the code below subtracts the stat value so that when added to the stat value we have
+    // 100% of samples. TODO: clean this up.
+    DumpStat(type_based_devirtualization_,
+             resolved_methods_[kVirtual] + unresolved_methods_[kVirtual] +
+             resolved_methods_[kInterface] + unresolved_methods_[kInterface] -
+             type_based_devirtualization_,
+             "virtual/interface calls made direct based on type information");
 
     for (size_t i = 0; i <= kMaxInvokeType; i++) {
       std::ostringstream oss;
@@ -184,40 +193,61 @@
     unresolved_static_fields_++;
   }
 
+  // Indicate that type information from the verifier led to devirtualization.
   void PreciseTypeDevirtualization() {
     STATS_LOCK();
     type_based_devirtualization_++;
   }
+
+  // Indicate that a method of the given type was resolved at compile time.
   void ResolvedMethod(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     resolved_methods_[type]++;
   }
 
+  // Indicate that a method of the given type was unresolved at compile time as it was in an
+  // unknown dex file.
   void UnresolvedMethod(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     unresolved_methods_[type]++;
   }
 
+  // Indicate that a type of virtual method dispatch has been converted into a direct method
+  // dispatch.
   void VirtualMadeDirect(InvokeType type) {
-    DCHECK_LE(type, kMaxInvokeType);
+    DCHECK(type == kVirtual || type == kInterface || type == kSuper);
     STATS_LOCK();
     virtual_made_direct_[type]++;
   }
 
+  // Indicate that a method of the given type was able to call directly into boot.
   void DirectCallsToBoot(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     direct_calls_to_boot_[type]++;
   }
 
+  // Indicate that a method of the given type was able to be resolved directly from boot.
   void DirectMethodsToBoot(InvokeType type) {
     DCHECK_LE(type, kMaxInvokeType);
     STATS_LOCK();
     direct_methods_to_boot_[type]++;
   }
 
+  // A check-cast could be eliminated due to verifier type analysis.
+  void SafeCast() {
+    STATS_LOCK();
+    safe_casts_++;
+  }
+
+  // A check-cast couldn't be eliminated due to verifier type analysis.
+  void NotASafeCast() {
+    STATS_LOCK();
+    not_safe_casts_++;
+  }
+
  private:
   Mutex stats_lock_;
 
@@ -245,6 +275,9 @@
   size_t direct_calls_to_boot_[kMaxInvokeType + 1];
   size_t direct_methods_to_boot_[kMaxInvokeType + 1];
 
+  size_t safe_casts_;
+  size_t not_safe_casts_;
+
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
 };
 
@@ -292,8 +325,8 @@
 }
 
 CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
-                               bool image, size_t thread_count, bool support_debugging,
-                               const std::set<std::string>* image_classes,
+                               bool image, DescriptorSet* image_classes,
+                               size_t thread_count, bool support_debugging,
                                bool dump_stats, bool dump_timings)
     : compiler_backend_(compiler_backend),
       instruction_set_(instruction_set),
@@ -301,18 +334,20 @@
       compiled_classes_lock_("compiled classes lock"),
       compiled_methods_lock_("compiled method lock"),
       image_(image),
+      image_classes_(image_classes),
       thread_count_(thread_count),
       support_debugging_(support_debugging),
       start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
       dump_timings_(dump_timings),
-      image_classes_(image_classes),
       compiler_library_(NULL),
       compiler_(NULL),
       compiler_context_(NULL),
       jni_compiler_(NULL),
-      compiler_get_method_code_addr_(NULL)
+      compiler_enable_auto_elf_loading_(NULL),
+      compiler_get_method_code_addr_(NULL),
+      support_boot_image_fixup_(true)
 {
   std::string compiler_so_name(MakeCompilerSoName(compiler_backend_));
   compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY);
@@ -347,7 +382,7 @@
 
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
-    CHECK(image_classes_ == NULL);
+    CHECK(image_classes_.get() == NULL);
   }
 }
 
@@ -416,6 +451,66 @@
   return res;
 }
 
+const std::vector<uint8_t>* CompilerDriver::CreatePortableResolutionTrampoline() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreatePortableResolutionTrampoline();
+    case kMips:
+      return mips::CreatePortableResolutionTrampoline();
+    case kX86:
+      return x86::CreatePortableResolutionTrampoline();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateQuickResolutionTrampoline() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreateQuickResolutionTrampoline();
+    case kMips:
+      return mips::CreateQuickResolutionTrampoline();
+    case kX86:
+      return x86::CreateQuickResolutionTrampoline();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToInterpreterEntry() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreateInterpreterToInterpreterEntry();
+    case kMips:
+      return mips::CreateInterpreterToInterpreterEntry();
+    case kX86:
+      return x86::CreateInterpreterToInterpreterEntry();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
+const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToQuickEntry() const {
+  switch (instruction_set_) {
+    case kArm:
+    case kThumb2:
+      return arm::CreateInterpreterToQuickEntry();
+    case kMips:
+      return mips::CreateInterpreterToQuickEntry();
+    case kX86:
+      return x86::CreateInterpreterToQuickEntry();
+    default:
+      LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_;
+      return NULL;
+  }
+}
+
 void CompilerDriver::CompileAll(jobject class_loader,
                                 const std::vector<const DexFile*>& dex_files) {
   DCHECK(!Runtime::Current()->IsStarted());
@@ -483,20 +578,199 @@
 
 void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                                 ThreadPool& thread_pool, TimingLogger& timings) {
+  LoadImageClasses(timings);
+
   Resolve(class_loader, dex_files, thread_pool, timings);
 
   Verify(class_loader, dex_files, thread_pool, timings);
 
   InitializeClasses(class_loader, dex_files, thread_pool, timings);
+
+  UpdateImageClasses(timings);
 }
 
-bool CompilerDriver::IsImageClass(const std::string& descriptor) const {
-  if (image_classes_ == NULL) {
-    return false;
+bool CompilerDriver::IsImageClass(const char* descriptor) const {
+  DCHECK(descriptor != NULL);
+  if (image_classes_.get() == NULL) {
+    return true;
   }
   return image_classes_->find(descriptor) != image_classes_->end();
 }
 
+static void ResolveExceptionsForMethod(MethodHelper* mh,
+    std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const DexFile::CodeItem* code_item = mh->GetCodeItem();
+  if (code_item == NULL) {
+    return;  // native or abstract method
+  }
+  if (code_item->tries_size_ == 0) {
+    return;  // nothing to process
+  }
+  const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
+  size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
+  for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
+    int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
+    bool has_catch_all = false;
+    if (encoded_catch_handler_size <= 0) {
+      encoded_catch_handler_size = -encoded_catch_handler_size;
+      has_catch_all = true;
+    }
+    for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
+      uint16_t encoded_catch_handler_handlers_type_idx =
+          DecodeUnsignedLeb128(&encoded_catch_handler_list);
+      // Add to set of types to resolve if not already in the dex cache resolved types
+      if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
+        exceptions_to_resolve.insert(
+            std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
+                                                &mh->GetDexFile()));
+      }
+      // ignore address associated with catch handler
+      DecodeUnsignedLeb128(&encoded_catch_handler_list);
+    }
+    if (has_catch_all) {
+      // ignore catch all address
+      DecodeUnsignedLeb128(&encoded_catch_handler_list);
+    }
+  }
+}
+
+static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
+      reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
+  MethodHelper mh;
+  for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
+    mirror::AbstractMethod* m = c->GetVirtualMethod(i);
+    mh.ChangeMethod(m);
+    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+  }
+  for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
+    mirror::AbstractMethod* m = c->GetDirectMethod(i);
+    mh.ChangeMethod(m);
+    ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
+  }
+  return true;
+}
+
+static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CompilerDriver::DescriptorSet* image_classes =
+      reinterpret_cast<CompilerDriver::DescriptorSet*>(arg);
+  image_classes->insert(ClassHelper(klass).GetDescriptor());
+  return true;
+}
+
+// Make a list of descriptors for classes to include in the image
+void CompilerDriver::LoadImageClasses(TimingLogger& timings)
+      LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  if (image_classes_.get() == NULL) {
+    return;
+  }
+
+  // Make a first class to load all classes explicitly listed in the file
+  Thread* self = Thread::Current();
+  ScopedObjectAccess soa(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  typedef DescriptorSet::iterator It;  // TODO: C++0x auto
+  for (It it = image_classes_->begin(), end = image_classes_->end(); it != end;) {
+    std::string descriptor(*it);
+    SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
+    if (klass.get() == NULL) {
+      image_classes_->erase(it++);
+      LOG(WARNING) << "Failed to find class " << descriptor;
+      Thread::Current()->ClearException();
+    } else {
+      ++it;
+    }
+  }
+
+  // Resolve exception classes referenced by the loaded classes. The catch logic assumes
+  // exceptions are resolved by the verifier when there is a catch block in an interested method.
+  // Do this here so that exception classes appear to have been specified image classes.
+  std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
+  SirtRef<mirror::Class> java_lang_Throwable(self,
+                                     class_linker->FindSystemClass("Ljava/lang/Throwable;"));
+  do {
+    unresolved_exception_types.clear();
+    class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
+                               &unresolved_exception_types);
+    typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It;  // TODO: C++0x auto
+    for (It it = unresolved_exception_types.begin(),
+         end = unresolved_exception_types.end();
+         it != end; ++it) {
+      uint16_t exception_type_idx = it->first;
+      const DexFile* dex_file = it->second;
+      mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
+      mirror:: ClassLoader* class_loader = NULL;
+      SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
+                                                                   dex_cache, class_loader));
+      if (klass.get() == NULL) {
+        const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
+        const char* descriptor = dex_file->GetTypeDescriptor(type_id);
+        LOG(FATAL) << "Failed to resolve class " << descriptor;
+      }
+      DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
+    }
+    // Resolving exceptions may load classes that reference more exceptions, iterate until no
+    // more are found
+  } while (!unresolved_exception_types.empty());
+
+  // We walk the roots looking for classes so that we'll pick up the
+  // above classes plus any classes them depend on such super
+  // classes, interfaces, and the required ClassLinker roots.
+  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)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  while (!klass->IsObjectClass()) {
+    ClassHelper kh(klass);
+    const char* descriptor = kh.GetDescriptor();
+    std::pair<CompilerDriver::DescriptorSet::iterator, bool> result =
+        image_classes->insert(descriptor);
+    if (result.second) {
+      LOG(INFO) << "Adding " << descriptor << " to image classes";
+    } else {
+      return;
+    }
+    for (size_t i = 0; i < kh.NumDirectInterfaces(); ++i) {
+      MaybeAddToImageClasses(kh.GetDirectInterface(i), image_classes);
+    }
+    if (klass->IsArrayClass()) {
+      MaybeAddToImageClasses(klass->GetComponentType(), image_classes);
+    }
+    klass = klass->GetSuperClass();
+  }
+}
+
+void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
+  DCHECK(object != NULL);
+  DCHECK(arg != NULL);
+  CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
+  MaybeAddToImageClasses(object->GetClass(), compiler_driver->image_classes_.get());
+}
+
+void CompilerDriver::UpdateImageClasses(TimingLogger& timings) {
+  if (image_classes_.get() == NULL) {
+    return;
+  }
+
+  // Update image_classes_ with classes for objects created by <clinit> methods.
+  Thread* self = Thread::Current();
+  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  // TODO: Image spaces only?
+  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+  heap->FlushAllocStack();
+  heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
+  self->EndAssertNoThreadSuspension(old_cause);
+  timings.AddSplit("UpdateImageClasses");
+}
+
 void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
   MutexLock mu(Thread::Current(), CompilerDriver::compiled_classes_lock_);
   compiled_classes_.Put(ref, compiled_class);
@@ -504,24 +778,19 @@
 
 bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file,
                                                       uint32_t type_idx) {
-  ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
-  if (!IsImage()) {
-    stats_->TypeNotInDexCache();
-    return false;
-  }
-  mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
-  if (resolved_class == NULL) {
-    stats_->TypeNotInDexCache();
-    return false;
-  }
-  bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor());
-  if (result) {
+  if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) {
+    if (kIsDebugBuild) {
+      ScopedObjectAccess soa(Thread::Current());
+      mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
+      mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
+      CHECK(resolved_class != NULL);
+    }
     stats_->TypeInDexCache();
+    return true;
   } else {
     stats_->TypeNotInDexCache();
+    return false;
   }
-  return result;
 }
 
 bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file,
@@ -545,7 +814,18 @@
 }
 
 bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
-                                                uint32_t type_idx) {
+                                                uint32_t type_idx,
+                                                bool* type_known_final, bool* type_known_abstract,
+                                                bool* equals_referrers_class) {
+  if (type_known_final != NULL) {
+    *type_known_final = false;
+  }
+  if (type_known_abstract != NULL) {
+    *type_known_abstract = false;
+  }
+  if (equals_referrers_class != NULL) {
+    *equals_referrers_class = false;
+  }
   ScopedObjectAccess soa(Thread::Current());
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier
@@ -555,6 +835,9 @@
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
+  if (equals_referrers_class != NULL) {
+    *equals_referrers_class = (method_id.class_idx_ == type_idx);
+  }
   mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
   if (referrer_class == NULL) {
     stats_->TypeNeedsAccessCheck();
@@ -565,6 +848,12 @@
   bool result = referrer_class->CanAccess(resolved_class);
   if (result) {
     stats_->TypeDoesntNeedAccessCheck();
+    if (type_known_final != NULL) {
+      *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass();
+    }
+    if (type_known_abstract != NULL) {
+      *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass();
+    }
   } else {
     stats_->TypeNeedsAccessCheck();
   }
@@ -600,9 +889,14 @@
 }
 
 static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa,
+                                                   mirror::DexCache* dex_cache,
                                                    const DexCompilationUnit* mUnit)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+  // The passed dex_cache is a hint, sanity check before asking the class linker that will take a
+  // lock.
+  if (dex_cache->GetDexFile() != mUnit->GetDexFile()) {
+    dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile());
+  }
   mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
   const DexFile::MethodId& referrer_method_id = mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
   return mUnit->GetClassLinker()->ResolveType(*mUnit->GetDexFile(), referrer_method_id.class_idx_,
@@ -639,7 +933,9 @@
   // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static).
   mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
   if (resolved_field != NULL && !resolved_field->IsStatic()) {
-    mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+    mirror::Class* referrer_class =
+        ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(),
+                                     mUnit);
     if (referrer_class != NULL) {
       mirror::Class* fields_class = resolved_field->GetDeclaringClass();
       bool access_ok = referrer_class->CanAccess(fields_class) &&
@@ -688,7 +984,9 @@
   // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static).
   mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx);
   if (resolved_field != NULL && resolved_field->IsStatic()) {
-    mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
+    mirror::Class* referrer_class =
+        ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(),
+                                     mUnit);
     if (referrer_class != NULL) {
       mirror::Class* fields_class = resolved_field->GetDeclaringClass();
       if (fields_class == referrer_class) {
@@ -733,9 +1031,8 @@
           }
           // Search dex file for localized ssb index, may fail if field's class is a parent
           // of the class mentioned in the dex file and there is no dex cache entry.
-          std::string descriptor(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
           const DexFile::StringId* string_id =
-          mUnit->GetDexFile()->FindStringId(descriptor);
+              mUnit->GetDexFile()->FindStringId(FieldHelper(resolved_field).GetDeclaringClassDescriptor());
           if (string_id != NULL) {
             const DexFile::TypeId* type_id =
                mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id));
@@ -764,7 +1061,8 @@
                                                    mirror::Class* referrer_class,
                                                    mirror::AbstractMethod* method,
                                                    uintptr_t& direct_code,
-                                                   uintptr_t& direct_method) {
+                                                   uintptr_t& direct_method,
+                                                   bool update_stats) {
   // For direct and static methods compute possible direct_code and direct_method values, ie
   // an address for the Method* being invoked and an address of the code for that Method*.
   // For interface calls compute a value for direct_method that is the interface method being
@@ -789,14 +1087,15 @@
     // Ensure we run the clinit trampoline unless we are invoking a static method in the same class.
     return;
   }
-  if (sharp_type != kInterface) {  // Interfaces always go via a trampoline.
-    stats_->DirectCallsToBoot(type);
+  if (update_stats) {
+    if (sharp_type != kInterface) {  // Interfaces always go via a trampoline.
+      stats_->DirectCallsToBoot(type);
+    }
+    stats_->DirectMethodsToBoot(type);
   }
-  stats_->DirectMethodsToBoot(type);
-  bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+  bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1;
   if (compiling_boot) {
-    const bool kSupportBootImageFixup = true;
-    if (kSupportBootImageFixup) {
+    if (support_boot_image_fixup_) {
       MethodHelper mh(method);
       if (IsImageClass(mh.GetDeclaringClassDescriptor())) {
         // We can only branch directly to Methods that are resolved in the DexCache.
@@ -806,33 +1105,33 @@
       }
     }
   } else {
-    if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method)->IsImageSpace()) {
+    if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) {
       direct_method = reinterpret_cast<uintptr_t>(method);
     }
     direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode());
   }
 }
 
-bool CompilerDriver::ComputeInvokeInfo(uint32_t method_idx,const uint32_t dex_pc,
-                                       const DexCompilationUnit* mUnit, InvokeType& type,
-                                       int& vtable_idx, uintptr_t& direct_code,
-                                       uintptr_t& direct_method) {
+bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+                                       InvokeType& invoke_type,
+                                       MethodReference& target_method,
+                                       int& vtable_idx,
+                                       uintptr_t& direct_code, uintptr_t& direct_method,
+                                       bool update_stats) {
   ScopedObjectAccess soa(Thread::Current());
-
-  const bool kEnableVerifierBasedSharpening = true;
-  const CompilerDriver::MethodReference ref_caller(mUnit->GetDexFile(), mUnit->GetDexMethodIndex());
-  const CompilerDriver::MethodReference* ref_sharpen = verifier::MethodVerifier::GetDevirtMap(ref_caller, dex_pc);
-  bool can_devirtualize = (dex_pc != art::kDexPCNotReady) && (ref_sharpen != NULL);
   vtable_idx = -1;
   direct_code = 0;
   direct_method = 0;
   mirror::AbstractMethod* resolved_method =
-      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, method_idx, type);
+      ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index,
+                                                 invoke_type);
   if (resolved_method != NULL) {
     // Don't try to fast-path if we don't understand the caller's class or this appears to be an
     // Incompatible Class Change Error.
-    mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, mUnit);
-    bool icce = resolved_method->CheckIncompatibleClassChange(type);
+    mirror::Class* referrer_class =
+        ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(),
+                                     mUnit);
+    bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type);
     if (referrer_class != NULL && !icce) {
       mirror::Class* methods_class = resolved_method->GetDeclaringClass();
       if (!referrer_class->CanAccess(methods_class) ||
@@ -842,74 +1141,168 @@
         // protected method being made public by implementing an interface that re-declares the
         // method public. Resort to the dex file to determine the correct class for the access
         // check.
-        const DexFile& dex_file = *referrer_class->GetDexCache()->GetDexFile();
-        methods_class =
-            mUnit->GetClassLinker()->ResolveType(dex_file,
-                                                 dex_file.GetMethodId(method_idx).class_idx_,
-                                                 referrer_class);
+        uint16_t class_idx =
+            target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_;
+        methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file,
+                                                             class_idx, referrer_class);
       }
       if (referrer_class->CanAccess(methods_class) &&
           referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) {
-        vtable_idx = resolved_method->GetMethodIndex();
-        const bool kEnableSharpening = true;
-        // Sharpen a virtual call into a direct call when the target is known.
-        bool can_sharpen = type == kVirtual && (resolved_method->IsFinal() ||
-            methods_class->IsFinal());
-        // Ensure the vtable index will be correct to dispatch in the vtable of the super class.
-        can_sharpen = can_sharpen || (type == kSuper && referrer_class != methods_class &&
-            referrer_class->IsSubClass(methods_class) &&
-            vtable_idx < methods_class->GetVTable()->GetLength() &&
-            methods_class->GetVTable()->Get(vtable_idx) == resolved_method);
+        const bool kEnableFinalBasedSharpening = true;
+        // Sharpen a virtual call into a direct call when the target is known not to have been
+        // overridden (ie is final).
+        bool can_sharpen_virtual_based_on_type =
+            (invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal());
+        // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
+        // the super class.
+        bool can_sharpen_super_based_on_type = (invoke_type == kSuper) &&
+            (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) &&
+            resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() &&
+            (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method);
 
-        if (kEnableSharpening && can_sharpen) {
-          stats_->ResolvedMethod(type);
+        if (kEnableFinalBasedSharpening && (can_sharpen_virtual_based_on_type ||
+                                            can_sharpen_super_based_on_type)) {
           // Sharpen a virtual call into a direct call. The method_idx is into referrer's
           // dex cache, check that this resolved method is where we expect it.
-          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(method_idx) == resolved_method)
-              << PrettyMethod(resolved_method);
-          stats_->VirtualMadeDirect(type);
-          GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, resolved_method,
-                                        direct_code, direct_method);
-          type = kDirect;
+          CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) ==
+                resolved_method) << PrettyMethod(resolved_method);
+          if (update_stats) {
+            stats_->ResolvedMethod(invoke_type);
+            stats_->VirtualMadeDirect(invoke_type);
+          }
+          GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method,
+                                        direct_code, direct_method, update_stats);
+          invoke_type = kDirect;
           return true;
-        } else if(can_devirtualize && kEnableSharpening && kEnableVerifierBasedSharpening) {
-            // If traditional sharpening fails, try the sharpening based on type information (Devirtualization)
-            mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*ref_sharpen->first);
-            mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
-            mirror::AbstractMethod* concrete_method = mUnit->GetClassLinker()->ResolveMethod(
-                *ref_sharpen->first, ref_sharpen->second, dex_cache, class_loader, NULL, kVirtual);
-            CHECK(concrete_method != NULL);
-            CHECK(!concrete_method->IsAbstract());
-            // TODO: fix breakage in image patching to be able to devirtualize cases with different
-            // resolved and concrete methods.
-            if(resolved_method == concrete_method) {
-              GetCodeAndMethodForDirectCall(type, kDirect, referrer_class, concrete_method, direct_code, direct_method);
-              stats_->VirtualMadeDirect(type);
-              type = kDirect;
-              stats_->PreciseTypeDevirtualization();
-            }
-            stats_->ResolvedMethod(type);
-            return true;
         }
-        else if (type == kSuper) {
+        const bool kEnableVerifierBasedSharpening = true;
+        if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual ||
+                                               invoke_type == kInterface)) {
+          // Did the verifier record a more precise invoke target based on its type information?
+          const CompilerDriver::MethodReference caller_method(mUnit->GetDexFile(),
+                                                              mUnit->GetDexMethodIndex());
+          const CompilerDriver::MethodReference* devirt_map_target =
+              verifier::MethodVerifier::GetDevirtMap(caller_method, dex_pc);
+          if (devirt_map_target != NULL) {
+            mirror::DexCache* target_dex_cache =
+                mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file);
+            mirror::ClassLoader* class_loader =
+                soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+            mirror::AbstractMethod* called_method =
+                mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file,
+                                                       devirt_map_target->dex_method_index,
+                                                       target_dex_cache, class_loader, NULL,
+                                                       kVirtual);
+            CHECK(called_method != NULL);
+            CHECK(!called_method->IsAbstract());
+            GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method,
+                                          direct_code, direct_method, update_stats);
+            bool compiler_needs_dex_cache =
+                (GetCompilerBackend() == kPortable) ||
+                (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) ||
+                (direct_code == 0) || (direct_code == static_cast<unsigned int>(-1)) ||
+                (direct_method == 0) || (direct_method == static_cast<unsigned int>(-1));
+            if ((devirt_map_target->dex_file != target_method.dex_file) &&
+                compiler_needs_dex_cache) {
+              // We need to use the dex cache to find either the method or code, and the dex file
+              // containing the method isn't the one expected for the target method. Try to find
+              // the method within the expected target dex file.
+              // TODO: the -1 could be handled as direct code if the patching new the target dex
+              //       file.
+              // TODO: quick only supports direct pointers with Thumb2.
+              // TODO: the following should be factored into a common helper routine to find
+              //       one dex file's method within another.
+              const DexFile* dexfile = target_method.dex_file;
+              const DexFile* cm_dexfile =
+                  called_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+              const DexFile::MethodId& cm_method_id =
+                  cm_dexfile->GetMethodId(called_method->GetDexMethodIndex());
+              const char* cm_descriptor = cm_dexfile->StringByTypeIdx(cm_method_id.class_idx_);
+              const DexFile::StringId* descriptor = dexfile->FindStringId(cm_descriptor);
+              if (descriptor != NULL) {
+                const DexFile::TypeId* type_id =
+                    dexfile->FindTypeId(dexfile->GetIndexForStringId(*descriptor));
+                if (type_id != NULL) {
+                  const char* cm_name = cm_dexfile->GetMethodName(cm_method_id);
+                  const DexFile::StringId* name = dexfile->FindStringId(cm_name);
+                  if (name != NULL) {
+                    uint16_t return_type_idx;
+                    std::vector<uint16_t> param_type_idxs;
+                    bool success = dexfile->CreateTypeList(&return_type_idx, &param_type_idxs,
+                                                           cm_dexfile->GetMethodSignature(cm_method_id));
+                    if (success) {
+                      const DexFile::ProtoId* sig =
+                          dexfile->FindProtoId(return_type_idx, param_type_idxs);
+                      if (sig != NULL) {
+                        const  DexFile::MethodId* method_id = dexfile->FindMethodId(*type_id,
+                                                                                    *name, *sig);
+                        if (method_id != NULL) {
+                          if (update_stats) {
+                            stats_->ResolvedMethod(invoke_type);
+                            stats_->VirtualMadeDirect(invoke_type);
+                            stats_->PreciseTypeDevirtualization();
+                          }
+                          target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id);
+                          invoke_type = kDirect;
+                          return true;
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+              // TODO: the stats for direct code and method are off as we failed to find the direct
+              //       method in the referring method's dex cache/file.
+            } else {
+              if (update_stats) {
+                stats_->ResolvedMethod(invoke_type);
+                stats_->VirtualMadeDirect(invoke_type);
+                stats_->PreciseTypeDevirtualization();
+              }
+              target_method = *devirt_map_target;
+              invoke_type = kDirect;
+              return true;
+            }
+          }
+        }
+        if (invoke_type == kSuper) {
           // Unsharpened super calls are suspicious so go slow-path.
         } else {
-          stats_->ResolvedMethod(type);
-          GetCodeAndMethodForDirectCall(type, type, referrer_class, resolved_method,
-                                        direct_code, direct_method);
+          // Sharpening failed so generate a regular resolved method dispatch.
+          if (update_stats) {
+            stats_->ResolvedMethod(invoke_type);
+          }
+          if (invoke_type == kVirtual || invoke_type == kSuper) {
+            vtable_idx = resolved_method->GetMethodIndex();
+          }
+          GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method,
+                                        direct_code, direct_method, update_stats);
           return true;
         }
       }
     }
   }
-  // Clean up any exception left by method/type resolution
+  // Clean up any exception left by method/invoke_type resolution
   if (soa.Self()->IsExceptionPending()) {
       soa.Self()->ClearException();
   }
-  stats_->UnresolvedMethod(type);
+  if (update_stats) {
+    stats_->UnresolvedMethod(invoke_type);
+  }
   return false;  // Incomplete knowledge needs slow path.
 }
 
+bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) {
+  bool result = verifier::MethodVerifier::IsSafeCast(mr, dex_pc);
+  if (result) {
+    stats_->SafeCast();
+  } else {
+    stats_->NotASafeCast();
+  }
+  return result;
+}
+
+
 void CompilerDriver::AddCodePatch(const DexFile* dex_file,
                             uint32_t referrer_method_idx,
                             InvokeType referrer_invoke_type,
@@ -990,7 +1383,7 @@
     CHECK_NE(self->GetState(), kRunnable);
 
     // Wait for all the worker threads to finish.
-    thread_pool_->Wait(self);
+    thread_pool_->Wait(self, true, false);
   }
 
  private:
@@ -1404,10 +1797,13 @@
   "Ljava/io/ObjectStreamClass;",  // Calls to Class.forName -> java.io.FileDescriptor.
   "Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission.
   "Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/lang/HexStringParser;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Ljava/lang/ProcessManager;", // Calls Thread.currentThread.
   "Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants.
   "Ljava/lang/System;", // Calls OsConstants.initConstants.
   "Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Ljava/math/Primality;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Ljava/net/InetAddress;", // Requires libcore.io.OsConstants.
   "Ljava/net/Inet4Address;", // Sub-class of InetAddress.
@@ -1416,23 +1812,57 @@
   "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
   "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset.
   "Ljava/nio/charset/Charsets;", // Calls Charset.forName.
+  "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants.
+  "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants.
   "Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants.
   "Ljava/security/Security;", // Tries to do disk IO for "security.properties".
+  "Ljava/security/spec/RSAKeyGenParameterSpec;", // java.math.NativeBN.BN_new()
   "Ljava/sql/Date;", // Calls OsConstants.initConstants.
+  "Ljava/sql/DriverManager;", // Calls OsConstants.initConstants.
+  "Ljava/sql/Time;", // Calls OsConstants.initConstants.
+  "Ljava/sql/Timestamp;", // Calls OsConstants.initConstants.
   "Ljava/util/Date;", // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
+  "Ljava/util/ListResourceBundle;", // Calls OsConstants.initConstants.
   "Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/PropertyResourceBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/ResourceBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/ResourceBundle$MissingBundle;", // Calls OsConstants.initConstants.
+  "Ljava/util/Scanner;", // regex.Pattern.compileImpl.
   "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone.
   "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
   "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors().
+  "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/Exchanger;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/ForkJoinPool;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/LinkedTransferQueue;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/Phaser;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8()
+  "Ljava/util/concurrent/SynchronousQueue;", // Calls OsConstants.initConstants.
+  "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8()
   "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/FilePreferencesImpl;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/FilePreferencesFactoryImpl;", // Calls OsConstants.initConstants.
+  "Ljava/util/prefs/Preferences;", // Calls OsConstants.initConstants.
+  "Ljavax/crypto/KeyAgreement;", // Calls OsConstants.initConstants.
+  "Ljavax/crypto/KeyGenerator;", // Calls OsConstants.initConstants.
+  "Ljavax/security/cert/X509Certificate;", // Calls VMClassLoader.getBootClassPathSize.
+  "Ljavax/security/cert/X509Certificate$1;", // Calls VMClassLoader.getBootClassPathSize.
   "Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext.
   "Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl.
   "Ljavax/net/ssl/HttpsURLConnection;", // Calls SSLSocketFactory.getDefault -> java.security.Security.getProperty.
+  "Ljavax/xml/datatype/DatatypeConstants;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/datatype/FactoryFinder;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/namespace/QName;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/validation/SchemaFactoryFinder;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/xpath/XPathConstants;", // Calls OsConstants.initConstants.
+  "Ljavax/xml/xpath/XPathFactoryFinder;", // Calls OsConstants.initConstants.
   "Llibcore/icu/LocaleData;", // Requires java.util.Locale.
   "Llibcore/icu/TimeZoneNames;", // Requires java.util.TimeZone.
   "Llibcore/io/IoUtils;",  // Calls Random.<init> -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants.
   "Llibcore/io/OsConstants;", // Platform specific.
   "Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
+  "Llibcore/reflect/Types;", // Calls OsConstants.initConstants.
   "Llibcore/util/ZoneInfo;", // Sub-class of TimeZone.
   "Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants.
   "Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty.
@@ -1440,17 +1870,40 @@
   "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets.
   "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File.
   "Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale.
+  "Lorg/apache/harmony/security/pkcs10/CertificationRequest;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/SignedData;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs7/SignerInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;", // Calls OsConstants.initConstants.
   "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread.
   "Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger.
   "Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
+  "Lorg/apache/harmony/security/x509/AccessDescription;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/CRLDistributionPoints;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate.
-  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
+  "Lorg/apache/harmony/security/x509/CertificateIssuer;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/CertificateList;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/DistributionPoint;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/DistributionPointName;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name.
   "Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName.
+  "Lorg/apache/harmony/security/x509/GeneralSubtree;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/GeneralSubtrees;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/InfoAccessSyntax;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/NameConstraints;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;", // Calls NativeBN.BN_new().
+  "Lorg/apache/harmony/security/x509/TBSCertList;", // Calls Thread.currentThread.
+  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
   "Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new().
   "Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time.
+  "Lorg/apache/harmony/security/x509/tsp/TSTInfo;", // Calls Thread.currentThread.
   "Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize.
+  "Lorg/apache/harmony/xml/ExpatParser$EntityParser;", // Calls ExpatParser.staticInitialize.
   "Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale.
   "Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty.
   "Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
@@ -1463,7 +1916,7 @@
   mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
   const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def);
   mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader);
-  bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+  bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1;
   bool can_init_static_fields = compiling_boot &&
       manager->GetCompiler()->IsImageClass(descriptor);
   if (klass != NULL) {
@@ -1473,13 +1926,17 @@
     // on a second thread the sub-class is initialized (holding its lock) after first initializing
     // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
     // lock ordering and consequent potential deadlock.
-    static Mutex lock1("Initializer lock", kMonitorLock);
-    MutexLock mu(soa.Self(), lock1);
+    // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
+    // than use a special Object for the purpose we use the Class of java.lang.Class.
+    ObjectLock lock1(soa.Self(), klass->GetClass());
     // The lock required to initialize the class.
     ObjectLock lock2(soa.Self(), klass);
     // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
       manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
+      if (soa.Self()->IsExceptionPending()) {
+        soa.Self()->GetException(NULL)->Dump();
+      }
       if (!klass->IsInitialized()) {
         if (can_init_static_fields) {
           bool is_black_listed = false;
@@ -1517,7 +1974,7 @@
       compiled_class = new CompiledClass(status);
       manager->GetCompiler()->RecordClassStatus(ref, compiled_class);
     } else {
-      DCHECK_EQ(status, compiled_class->GetStatus());
+      DCHECK_GE(status, compiled_class->GetStatus()) << descriptor;
     }
   }
   // Clear any class not found or verification exceptions.
@@ -1641,7 +2098,8 @@
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     // In small mode we only compile image classes.
-    bool dont_compile = Runtime::Current()->IsSmallMode() && ((image_classes_ == NULL) || (image_classes_->size() == 0));
+    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)) {
diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h
index 75d276d..fbfcadb 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -39,7 +39,6 @@
 class DexCompilationUnit;
 class TimingLogger;
 
-const uint32_t kDexPCNotReady = 0xFFFFFF;
 enum CompilerBackend {
   kQuick,
   kPortable,
@@ -62,14 +61,16 @@
 
 class CompilerDriver {
  public:
+  typedef std::set<std::string> DescriptorSet;
+
   // Create a compiler targeting the requested "instruction_set".
   // "image" should be true if image specific optimizations should be
   // enabled.  "image_classes" lets the compiler know what classes it
   // can assume will be in the image, with NULL implying all available
   // classes.
-  explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, bool image,
+  explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set,
+                          bool image, DescriptorSet* image_classes,
                           size_t thread_count, bool support_debugging,
-                          const std::set<std::string>* image_classes, 
                           bool dump_stats, bool dump_timings);
 
   ~CompilerDriver();
@@ -97,8 +98,22 @@
     return image_;
   }
 
+  DescriptorSet* GetImageClasses() const {
+    return image_classes_.get();
+  }
+
   CompilerTls* GetTls();
 
+  // Generate the trampolines that are invoked by unresolved direct methods.
+  const std::vector<uint8_t>* CreatePortableResolutionTrampoline() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  const std::vector<uint8_t>* CreateInterpreterToQuickEntry() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
   typedef std::pair<const DexFile*, uint32_t> ClassReference;
 
@@ -106,7 +121,22 @@
       LOCKS_EXCLUDED(compiled_classes_lock_);
 
   // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
-  typedef std::pair<const DexFile*, uint32_t> MethodReference;
+  struct MethodReference {
+    MethodReference(const DexFile* file, uint32_t index) : dex_file(file), dex_method_index(index) {
+    }
+    const DexFile* dex_file;
+    uint32_t dex_method_index;
+  };
+
+  struct MethodReferenceComparator {
+    bool operator()(MethodReference mr1, MethodReference mr2) const {
+      if (mr1.dex_file == mr2.dex_file) {
+        return mr1.dex_method_index < mr2.dex_method_index;
+      } else {
+        return mr1.dex_file < mr2.dex_file;
+      }
+    }
+  };
 
   CompiledMethod* GetCompiledMethod(MethodReference ref) const
       LOCKS_EXCLUDED(compiled_methods_lock_);
@@ -124,7 +154,9 @@
 
   // Are runtime access checks necessary in the compiled code?
   bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
-                                  uint32_t type_idx)
+                                  uint32_t type_idx, bool* type_known_final = NULL,
+                                  bool* type_known_abstract = NULL,
+                                  bool* equals_referrers_class = NULL)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Are runtime access and instantiable checks necessary in the code?
@@ -146,11 +178,13 @@
 
   // Can we fastpath a interface, super class or virtual method call? Computes method's vtable
   // index.
-  bool ComputeInvokeInfo(uint32_t method_idx, uint32_t dex_pc,
-                         const DexCompilationUnit* mUnit, InvokeType& type, int& vtable_idx,
-                         uintptr_t& direct_code, uintptr_t& direct_method)
+  bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
+                         InvokeType& type, MethodReference& target_method, int& vtable_idx,
+                         uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc);
+
   // Record patch information for later fix up.
   void AddCodePatch(const DexFile* dex_file,
                     uint32_t referrer_method_idx,
@@ -169,6 +203,15 @@
 
   void SetBitcodeFileName(std::string const& filename);
 
+  bool GetSupportBootImageFixup() const {
+    return support_boot_image_fixup_;
+  }
+
+  void SetSupportBootImageFixup(bool support_boot_image_fixup) {
+    support_boot_image_fixup_ = support_boot_image_fixup;
+  }
+
+
   // TODO: remove these Elf wrappers when libart links against LLVM (when separate compiler library is gone)
   bool WriteElf(const std::string& android_root,
                 bool is_host,
@@ -253,7 +296,7 @@
   }
 
   // Checks if class specified by type_idx is one of the image_classes_
-  bool IsImageClass(const std::string& descriptor) const;
+  bool IsImageClass(const char* descriptor) const;
 
   void RecordClassStatus(ClassReference ref, CompiledClass* compiled_class);
 
@@ -262,13 +305,16 @@
   void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type,
                                      mirror::Class* referrer_class,
                                      mirror::AbstractMethod* method,
-                                     uintptr_t& direct_code, uintptr_t& direct_method)
+                                     uintptr_t& direct_code, uintptr_t& direct_method,
+                                     bool update_stats)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                   ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  void LoadImageClasses(TimingLogger& timings);
+
   // Attempt to resolve all type, methods, fields, and strings
   // referenced from code in the dex file following PathClassLoader
   // ordering semantics.
@@ -292,6 +338,10 @@
                          ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
 
+  void UpdateImageClasses(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);
   void CompileDexFile(jobject class_loader, const DexFile& dex_file,
@@ -321,12 +371,18 @@
   mutable Mutex compiled_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   ClassTable compiled_classes_ GUARDED_BY(compiled_classes_lock_);
 
-  typedef SafeMap<const MethodReference, CompiledMethod*> MethodTable;
+  typedef SafeMap<const MethodReference, CompiledMethod*, MethodReferenceComparator> MethodTable;
   // All method references that this compiler has compiled.
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
 
-  bool image_;
+  const bool image_;
+
+  // If image_ is true, specifies the classes that will be included in
+  // the image. Note if image_classes_ is NULL, all classes are
+  // included in the image.
+  UniquePtr<DescriptorSet> image_classes_;
+
   size_t thread_count_;
   bool support_debugging_;
   uint64_t start_ns_;
@@ -336,8 +392,6 @@
   bool dump_stats_;
   bool dump_timings_;
 
-  const std::set<std::string>* image_classes_;
-
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
@@ -366,6 +420,8 @@
       (const CompilerDriver& driver, const CompiledMethod* cm, const mirror::AbstractMethod* method);
   CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_;
 
+  bool support_boot_image_fixup_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
 };
 
diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc
index c87fefd..abf8a9a 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -23,10 +23,10 @@
 #include "class_linker.h"
 #include "common_test.h"
 #include "dex_file.h"
-#include "heap.h"
+#include "gc/heap.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
diff --git a/src/compiler/driver/dex_compilation_unit.cc b/src/compiler/driver/dex_compilation_unit.cc
index 962df42..c7a4df6 100644
--- a/src/compiler/driver/dex_compilation_unit.cc
+++ b/src/compiler/driver/dex_compilation_unit.cc
@@ -31,18 +31,17 @@
       code_item_(cu->code_item),
       class_def_idx_(cu->class_def_idx),
       dex_method_idx_(cu->method_idx),
-      access_flags_(cu->access_flags),
-      symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+      access_flags_(cu->access_flags) {
 }
 
-DexCompilationUnit:: DexCompilationUnit(CompilationUnit* cu,
-                                        jobject class_loader,
-                                        ClassLinker* class_linker,
-                                        const DexFile& dex_file,
-                                        const DexFile::CodeItem* code_item,
-                                        uint32_t class_def_idx,
-                                        uint32_t method_idx,
-                                        uint32_t access_flags)
+DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu,
+                                       jobject class_loader,
+                                       ClassLinker* class_linker,
+                                       const DexFile& dex_file,
+                                       const DexFile::CodeItem* code_item,
+                                       uint32_t class_def_idx,
+                                       uint32_t method_idx,
+                                       uint32_t access_flags)
     : cu_(cu),
       class_loader_(class_loader),
       class_linker_(class_linker),
@@ -50,8 +49,15 @@
       code_item_(code_item),
       class_def_idx_(class_def_idx),
       dex_method_idx_(method_idx),
-      access_flags_(access_flags),
-      symbol_(StringPrintf("dex_%s", MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_)).c_str())) {
+      access_flags_(access_flags) {
+}
+
+const std::string& DexCompilationUnit::GetSymbol() {
+  if (symbol_.empty()) {
+    symbol_ = "dex_";
+    symbol_ += MangleForJni(PrettyMethod(dex_method_idx_, *dex_file_));
+  }
+  return symbol_;
 }
 
 } // namespace art
diff --git a/src/compiler/driver/dex_compilation_unit.h b/src/compiler/driver/dex_compilation_unit.h
index 0b90aaa..3c6129d 100644
--- a/src/compiler/driver/dex_compilation_unit.h
+++ b/src/compiler/driver/dex_compilation_unit.h
@@ -92,9 +92,7 @@
     return ((access_flags_ & kAccSynchronized) != 0);
   }
 
-  const std::string& GetSymbol() const {
-    return symbol_;
-  }
+  const std::string& GetSymbol();
 
  private:
   CompilationUnit* const cu_;
@@ -110,7 +108,7 @@
   const uint32_t dex_method_idx_;
   const uint32_t access_flags_;
 
-  const std::string symbol_;
+  std::string symbol_;
 };
 
 } // namespace art
diff --git a/src/compiler/llvm/gbc_expander.cc b/src/compiler/llvm/gbc_expander.cc
index 99c8fd5..bdf9aca 100644
--- a/src/compiler/llvm/gbc_expander.cc
+++ b/src/compiler/llvm/gbc_expander.cc
@@ -776,7 +776,8 @@
   art::InvokeType invoke_type =
       static_cast<art::InvokeType>(LV2UInt(call_inst.getArgOperand(0)));
   bool is_static = (invoke_type == art::kStatic);
-  uint32_t callee_method_idx = LV2UInt(call_inst.getArgOperand(1));
+  art::CompilerDriver::MethodReference target_method(dex_compilation_unit_->GetDexFile(),
+                                                     LV2UInt(call_inst.getArgOperand(1)));
 
   // Load *this* actual parameter
   llvm::Value* this_addr = (!is_static) ? call_inst.getArgOperand(3) : NULL;
@@ -785,18 +786,17 @@
   int vtable_idx = -1;
   uintptr_t direct_code = 0;
   uintptr_t direct_method = 0;
-  // TODO: pass actual value of dex PC (instead of kDexPCNotready) needed by verifier based
-  // sharpening after LLVM re-factoring is finished.
-  bool is_fast_path = driver_->
-      ComputeInvokeInfo(callee_method_idx, art::kDexPCNotReady, dex_compilation_unit_,
-                        invoke_type, vtable_idx, direct_code, direct_method);
-
+  bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc,
+                                                 invoke_type, target_method,
+                                                 vtable_idx,
+                                                 direct_code, direct_method,
+                                                 true);
   // Load the method object
   llvm::Value* callee_method_object_addr = NULL;
 
   if (!is_fast_path) {
     callee_method_object_addr =
-        EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx, invoke_type,
+        EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index, invoke_type,
                                                  this_addr, dex_pc, is_fast_path);
   } else {
     switch (invoke_type) {
@@ -809,7 +809,7 @@
                                   irb_.getJObjectTy());
         } else {
           callee_method_object_addr =
-              EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+              EmitLoadSDCalleeMethodObjectAddr(target_method.dex_method_index);
         }
         break;
 
@@ -826,7 +826,7 @@
 
       case art::kInterface:
         callee_method_object_addr =
-            EmitCallRuntimeForCalleeMethodObjectAddr(callee_method_idx,
+            EmitCallRuntimeForCalleeMethodObjectAddr(target_method.dex_method_index,
                                                      invoke_type, this_addr,
                                                      dex_pc, is_fast_path);
         break;
@@ -844,7 +844,7 @@
 
   llvm::Value* code_addr;
   llvm::Type* func_type = GetFunctionType(call_inst.getType(),
-                                          callee_method_idx, is_static);
+                                          target_method.dex_method_index, is_static);
   if (direct_code != 0u && direct_code != static_cast<uintptr_t>(-1)) {
     code_addr =
         irb_.CreateIntToPtr(irb_.getPtrEquivInt(direct_code),
diff --git a/src/compiler/llvm/llvm_compilation_unit.h b/src/compiler/llvm/llvm_compilation_unit.h
index d96e778..857d924 100644
--- a/src/compiler/llvm/llvm_compilation_unit.h
+++ b/src/compiler/llvm/llvm_compilation_unit.h
@@ -81,10 +81,10 @@
   void SetCompilerDriver(CompilerDriver* driver) {
     driver_ = driver;
   }
-  const DexCompilationUnit* GetDexCompilationUnit() {
+  DexCompilationUnit* GetDexCompilationUnit() {
     return dex_compilation_unit_;
   }
-  void SetDexCompilationUnit(const DexCompilationUnit* dex_compilation_unit) {
+  void SetDexCompilationUnit(DexCompilationUnit* dex_compilation_unit) {
     dex_compilation_unit_ = dex_compilation_unit;
   }
 
@@ -113,7 +113,7 @@
   UniquePtr<IntrinsicHelper> intrinsic_helper_;
   UniquePtr<LLVMInfo> llvm_info_;
   CompilerDriver* driver_;
-  const DexCompilationUnit* dex_compilation_unit_;
+  DexCompilationUnit* dex_compilation_unit_;
 
   std::string bitcode_filename_;
 
diff --git a/src/compiler/llvm/runtime_support_builder.cc b/src/compiler/llvm/runtime_support_builder.cc
index b4ddb55..2be2ddf 100644
--- a/src/compiler/llvm/runtime_support_builder.cc
+++ b/src/compiler/llvm/runtime_support_builder.cc
@@ -16,7 +16,7 @@
 
 #include "runtime_support_builder.h"
 
-#include "gc/card_table.h"
+#include "gc/accounting/card_table.h"
 #include "ir_builder.h"
 #include "monitor.h"
 #include "mirror/object.h"
@@ -266,9 +266,11 @@
                                                irb_.getInt8Ty()->getPointerTo(),
                                                kTBAAConstJObject);
   Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
-  Value* card_no = irb_.CreateLShr(target_addr_int, irb_.getPtrEquivInt(CardTable::kCardShift));
+  Value* card_no = irb_.CreateLShr(target_addr_int,
+                                   irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift));
   Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
-  irb_.CreateStore(irb_.getInt8(CardTable::kCardDirty), card_table_entry, kTBAARuntimeInfo);
+  irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry,
+                   kTBAARuntimeInfo);
   irb_.CreateBr(bb_cont);
 
   irb_.SetInsertPoint(bb_cont);
diff --git a/src/compiler/llvm/runtime_support_llvm.cc b/src/compiler/llvm/runtime_support_llvm.cc
index bd6b01b..f3cfb33 100644
--- a/src/compiler/llvm/runtime_support_llvm.cc
+++ b/src/compiler/llvm/runtime_support_llvm.cc
@@ -24,6 +24,7 @@
 #include "dex_instruction.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/object.h"
 #include "mirror/object-inl.h"
@@ -435,7 +436,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint32_t));
+                            StaticPrimitiveWrite, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(field->GetDeclaringClass(), new_value);
     return 0;
@@ -451,7 +452,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveWrite, sizeof(uint64_t));
+                            StaticPrimitiveWrite, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(field->GetDeclaringClass(), new_value);
     return 0;
@@ -467,7 +468,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectWrite, sizeof(mirror::Object*));
+                            StaticObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(field->GetDeclaringClass(), new_value);
     return 0;
@@ -482,7 +483,7 @@
     return field->Get32(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint32_t));
+                            StaticPrimitiveRead, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(field->GetDeclaringClass());
   }
@@ -496,7 +497,7 @@
     return field->Get64(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticPrimitiveRead, sizeof(uint64_t));
+                            StaticPrimitiveRead, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(field->GetDeclaringClass());
   }
@@ -510,7 +511,7 @@
     return field->GetObj(field->GetDeclaringClass());
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            StaticObjectRead, sizeof(mirror::Object*));
+                            StaticObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(field->GetDeclaringClass());
   }
@@ -526,7 +527,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint32_t));
+                            InstancePrimitiveWrite, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(obj, new_value);
     return 0;
@@ -543,7 +544,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveWrite, sizeof(uint64_t));
+                            InstancePrimitiveWrite, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(obj, new_value);
     return 0;
@@ -560,7 +561,7 @@
     return 0;
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectWrite, sizeof(mirror::Object*));
+                            InstanceObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(obj, new_value);
     return 0;
@@ -575,7 +576,7 @@
     return field->Get32(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint32_t));
+                            InstancePrimitiveRead, sizeof(uint32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
   }
@@ -589,7 +590,7 @@
     return field->Get64(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstancePrimitiveRead, sizeof(uint64_t));
+                            InstancePrimitiveRead, sizeof(uint64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
   }
@@ -603,7 +604,7 @@
     return field->GetObj(obj);
   }
   field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
-                            InstanceObjectRead, sizeof(mirror::Object*));
+                            InstanceObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
   }
diff --git a/src/compiler/stubs/portable/stubs.cc b/src/compiler/stubs/portable/stubs.cc
new file mode 100644
index 0000000..db551bf
--- /dev/null
+++ b/src/compiler/stubs/portable/stubs.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/stubs/stubs.h"
+#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/mips/assembler_mips.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "stack_indirect_reference_table.h"
+#include "sirt_ref.h"
+
+#define __ assembler->
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+  RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
+
+  __ PushList(save);
+  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
+  __ mov(R3, ShifterOperand(TR));  // Pass Thread::Current() in R3
+  __ mov(R2, ShifterOperand(SP));  // Pass sp for Method** callee_addr
+  __ IncreaseFrameSize(12);         // 3 words of space for alignment
+  // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
+  __ blx(R12);
+  __ mov(R12, ShifterOperand(R0));  // Save code address returned into R12
+  __ DecreaseFrameSize(12);
+  __ PopList(save);
+  __ cmp(R12, ShifterOperand(0));
+  __ bx(R12, NE);                   // If R12 != 0 tail call method's code
+  __ bx(LR);                        // Return to caller to handle exception
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+} // namespace arm
+
+namespace mips {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+  // Build frame and save argument registers and RA.
+  __ AddConstant(SP, SP, -32);
+  __ StoreToOffset(kStoreWord, RA, SP, 28);
+  __ StoreToOffset(kStoreWord, A3, SP, 12);
+  __ StoreToOffset(kStoreWord, A2, SP, 8);
+  __ StoreToOffset(kStoreWord, A1, SP, 4);
+  __ StoreToOffset(kStoreWord, A0, SP, 0);
+
+  __ LoadFromOffset(kLoadWord, T9, S1,
+                    ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
+  __ Move(A3, S1);  // Pass Thread::Current() in A3
+  __ Move(A2, SP);  // Pass SP for Method** callee_addr
+  __ Jalr(T9); // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
+
+  // Restore frame, argument registers, and RA.
+  __ LoadFromOffset(kLoadWord, A0, SP, 0);
+  __ LoadFromOffset(kLoadWord, A1, SP, 4);
+  __ LoadFromOffset(kLoadWord, A2, SP, 8);
+  __ LoadFromOffset(kLoadWord, A3, SP, 12);
+  __ LoadFromOffset(kLoadWord, RA, SP, 28);
+  __ AddConstant(SP, SP, 32);
+
+  Label resolve_fail;
+  __ EmitBranch(V0, ZERO, &resolve_fail, true);
+  __ Jr(V0); // If V0 != 0 tail call method's code
+  __ Bind(&resolve_fail, false);
+  __ Jr(RA); // Return to caller to handle exception
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+} // namespace mips
+
+namespace x86 {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+  __ pushl(EBP);
+  __ movl(EBP, ESP);          // save ESP
+  __ subl(ESP, Immediate(8));  // Align stack
+  __ movl(EAX, Address(EBP, 8));  // Method* called
+  __ leal(EDX, Address(EBP, 8));  // Method** called_addr
+  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // pass thread
+  __ pushl(EDX);  // pass called_addr
+  __ pushl(ECX);  // pass receiver
+  __ pushl(EAX);  // pass called
+  // Call to resolve method.
+  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)),
+          X86ManagedRegister::FromCpuRegister(ECX));
+  __ leave();
+
+  Label resolve_fail;  // forward declaration
+  __ cmpl(EAX, Immediate(0));
+  __ j(kEqual, &resolve_fail);
+  __ jmp(EAX);
+  // Tail call to intended method.
+  __ Bind(&resolve_fail);
+  __ ret();
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+} // namespace x86
+
+} // namespace art
diff --git a/src/compiler/stubs/quick/stubs.cc b/src/compiler/stubs/quick/stubs.cc
new file mode 100644
index 0000000..a8e691f
--- /dev/null
+++ b/src/compiler/stubs/quick/stubs.cc
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler/stubs/stubs.h"
+#include "jni_internal.h"
+#include "oat/utils/arm/assembler_arm.h"
+#include "oat/utils/mips/assembler_mips.h"
+#include "oat/utils/x86/assembler_x86.h"
+#include "oat/runtime/oat_support_entrypoints.h"
+#include "stack_indirect_reference_table.h"
+#include "sirt_ref.h"
+
+#define __ assembler->
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+  // | Out args |
+  // | Method*  | <- SP on entry
+  // | LR       |    return address into caller
+  // | ...      |    callee saves
+  // | R3       |    possible argument
+  // | R2       |    possible argument
+  // | R1       |    possible argument
+  // | R0       |    junk on call to QuickResolutionTrampolineFromCode, holds result Method*
+  // | Method*  |    Callee save Method* set up by QuickResoltuionTrampolineFromCode
+  // Save callee saves and ready frame for exception delivery
+  RegList save = (1 << R1) | (1 << R2) | (1 << R3) | (1 << R5) | (1 << R6) | (1 << R7) | (1 << R8) |
+                 (1 << R10) | (1 << R11) | (1 << LR);
+  // TODO: enable when GetCalleeSaveMethod is available at stub generation time
+  // DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetCoreSpillMask());
+  __ PushList(save);
+  __ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
+  __ mov(R3, ShifterOperand(TR));  // Pass Thread::Current() in R3
+  __ IncreaseFrameSize(8);         // 2 words of space for alignment
+  __ mov(R2, ShifterOperand(SP));  // Pass SP
+  // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
+  __ blx(R12);
+  __ mov(R12, ShifterOperand(R0));  // Save code address returned into R12
+  // Restore registers which may have been modified by GC, "R0" will hold the Method*
+  __ DecreaseFrameSize(4);
+  __ PopList((1 << R0) | save);
+  __ bx(R12);  // Leaf call to method's code
+  __ bkpt(0);
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+
+  __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+  __ bkpt(0);
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+  UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
+
+  __ LoadFromOffset(kLoadWord, PC, R0, ENTRYPOINT_OFFSET(pInterpreterToQuickEntry));
+  __ bkpt(0);
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+} // namespace arm
+
+namespace mips {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+  // | Out args   |
+  // | Method*    | <- SP on entry
+  // | RA         |    return address into caller
+  // | ...        |    callee saves
+  // | A3         |    possible argument
+  // | A2         |    possible argument
+  // | A1         |    possible argument
+  // | A0/Method* |    Callee save Method* set up by UnresolvedDirectMethodTrampolineFromCode
+  // Save callee saves and ready frame for exception delivery
+  __ AddConstant(SP, SP, -64);
+  __ StoreToOffset(kStoreWord, RA, SP, 60);
+  __ StoreToOffset(kStoreWord, FP, SP, 56);
+  __ StoreToOffset(kStoreWord, GP, SP, 52);
+  __ StoreToOffset(kStoreWord, S7, SP, 48);
+  __ StoreToOffset(kStoreWord, S6, SP, 44);
+  __ StoreToOffset(kStoreWord, S5, SP, 40);
+  __ StoreToOffset(kStoreWord, S4, SP, 36);
+  __ StoreToOffset(kStoreWord, S3, SP, 32);
+  __ StoreToOffset(kStoreWord, S2, SP, 28);
+  __ StoreToOffset(kStoreWord, A3, SP, 12);
+  __ StoreToOffset(kStoreWord, A2, SP, 8);
+  __ StoreToOffset(kStoreWord, A1, SP, 4);
+
+  __ LoadFromOffset(kLoadWord, T9, S1, ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
+  __ Move(A3, S1);  // Pass Thread::Current() in A3
+  __ Move(A2, SP);  // Pass SP for Method** callee_addr
+  __ Jalr(T9); // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
+
+  // Restore registers which may have been modified by GC
+  __ LoadFromOffset(kLoadWord, A0, SP, 0);
+  __ LoadFromOffset(kLoadWord, A1, SP, 4);
+  __ LoadFromOffset(kLoadWord, A2, SP, 8);
+  __ LoadFromOffset(kLoadWord, A3, SP, 12);
+  __ LoadFromOffset(kLoadWord, S2, SP, 28);
+  __ LoadFromOffset(kLoadWord, S3, SP, 32);
+  __ LoadFromOffset(kLoadWord, S4, SP, 36);
+  __ LoadFromOffset(kLoadWord, S5, SP, 40);
+  __ LoadFromOffset(kLoadWord, S6, SP, 44);
+  __ LoadFromOffset(kLoadWord, S7, SP, 48);
+  __ LoadFromOffset(kLoadWord, GP, SP, 52);
+  __ LoadFromOffset(kLoadWord, FP, SP, 56);
+  __ LoadFromOffset(kLoadWord, RA, SP, 60);
+  __ AddConstant(SP, SP, 64);
+
+  __ Move(T9, V0); // Put method's code in T9
+  __ Jr(T9);  // Leaf call to method's code
+
+  __ Break();
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+
+  __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+  __ Jr(T9);
+  __ Break();
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+  UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+
+  __ LoadFromOffset(kLoadWord, T9, A0, ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
+  __ Jr(T9);
+  __ Break();
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+} // namespace mips
+
+namespace x86 {
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+  // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
+  // return address
+  __ pushl(EDI);
+  __ pushl(ESI);
+  __ pushl(EBP);
+  __ pushl(EBX);
+  __ pushl(EDX);
+  __ pushl(ECX);
+  __ pushl(EAX);  // <-- callee save Method* to go here
+  __ movl(EDX, ESP);          // save ESP
+  __ fs()->pushl(Address::Absolute(Thread::SelfOffset()));  // pass Thread*
+  __ pushl(EDX);              // pass ESP for Method*
+  __ pushl(ECX);              // pass receiver
+  __ pushl(EAX);              // pass Method*
+
+  // Call to resolve method.
+  __ Call(ThreadOffset(ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)),
+          X86ManagedRegister::FromCpuRegister(ECX));
+
+  __ movl(EDI, EAX);  // save code pointer in EDI
+  __ addl(ESP, Immediate(16));  // Pop arguments
+  __ popl(EAX);  // Restore args.
+  __ popl(ECX);
+  __ popl(EDX);
+  __ popl(EBX);
+  __ popl(EBP);  // Restore callee saves.
+  __ popl(ESI);
+  // Swap EDI callee save with code pointer
+  __ xchgl(EDI, Address(ESP, 0));
+  // Tail call to intended method.
+  __ ret();
+
+  assembler->EmitSlowPaths();
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
+  assembler->FinalizeInstructions(code);
+
+  return resolution_trampoline.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+  __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry))));
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
+  UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+
+  __ fs()->jmp(Address::Absolute(ThreadOffset(ENTRYPOINT_OFFSET(pInterpreterToQuickEntry))));
+
+  size_t cs = assembler->CodeSize();
+  UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
+  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
+  assembler->FinalizeInstructions(code);
+
+  return entry_stub.release();
+}
+} // namespace x86
+
+} // namespace art
diff --git a/src/compiler/stubs/stubs.h b/src/compiler/stubs/stubs.h
new file mode 100644
index 0000000..ebe761d
--- /dev/null
+++ b/src/compiler/stubs/stubs.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_STUBS_STUBS_H_
+#define ART_SRC_COMPILER_STUBS_STUBS_H_
+
+#include "runtime.h"
+
+namespace art {
+
+namespace arm {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+namespace mips {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+namespace x86 {
+const std::vector<uint8_t>* CreatePortableResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateQuickResolutionTrampoline()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+const std::vector<uint8_t>* CreateInterpreterToQuickEntry()
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+}
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILER_STUBS_STUBS_H_
diff --git a/src/debugger.cc b/src/debugger.cc
index d7fac43..f2a10f0 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -24,9 +24,9 @@
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
-#include "gc/card_table-inl.h"
-#include "gc/large_object_space.h"
-#include "gc/space.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
 #include "invoke_arg_array_builder.h"
 #include "jdwp/object_registry.h"
 #include "mirror/abstract_method-inl.h"
@@ -1691,6 +1691,7 @@
     case kWaitingForDebuggerSuspension:   *pThreadStatus = JDWP::TS_WAIT;     break;
     case kWaitingForDebuggerToAttach:     *pThreadStatus = JDWP::TS_WAIT;     break;
     case kWaitingForGcToComplete:         *pThreadStatus = JDWP::TS_WAIT;     break;
+    case kWaitingForCheckPointsToRun:     *pThreadStatus = JDWP::TS_WAIT;     break;
     case kWaitingForJniOnLoad:            *pThreadStatus = JDWP::TS_WAIT;     break;
     case kWaitingForSignalCatcherOutput:  *pThreadStatus = JDWP::TS_WAIT;     break;
     case kWaitingInMainDebuggerLoop:      *pThreadStatus = JDWP::TS_WAIT;     break;
@@ -3137,7 +3138,7 @@
    *     [u4]: current number of objects allocated
    */
   uint8_t heap_count = 1;
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   std::vector<uint8_t> bytes;
   JDWP::Append4BE(bytes, heap_count);
   JDWP::Append4BE(bytes, 1); // Heap id (bogus; we only have one heap).
@@ -3416,17 +3417,16 @@
   // Send a series of heap segment chunks.
   HeapChunkContext context((what == HPSG_WHAT_MERGED_OBJECTS), native);
   if (native) {
-    // TODO: enable when bionic has moved to dlmalloc 2.8.5
-    // dlmalloc_inspect_all(HeapChunkContext::HeapChunkCallback, &context);
-    UNIMPLEMENTED(WARNING) << "Native heap send heap segments";
+    dlmalloc_inspect_all(HeapChunkContext::HeapChunkCallback, &context);
   } else {
-    Heap* heap = Runtime::Current()->GetHeap();
-    const Spaces& spaces = heap->GetSpaces();
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
     Thread* self = Thread::Current();
     ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
-      if ((*cur)->IsAllocSpace()) {
-        (*cur)->AsAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+    typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+    for (It cur = spaces.begin(), end = spaces.end(); cur != end; ++cur) {
+      if ((*cur)->IsDlMallocSpace()) {
+        (*cur)->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
       }
     }
     // Walk the large objects, these are not in the AllocSpace.
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index ad751d0..b5dc319 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -30,6 +30,8 @@
 #include "class_linker.h"
 #include "compiler/driver/compiler_driver.h"
 #include "dex_file-inl.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
 #include "image_writer.h"
 #include "leb128.h"
 #include "mirror/abstract_method-inl.h"
@@ -161,18 +163,15 @@
   }
 
 
-  // Make a list of descriptors for classes to include in the image
-  std::set<std::string>* GetImageClassDescriptors(const char* image_classes_filename)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+  CompilerDriver::DescriptorSet* ReadImageClasses(const char* image_classes_filename) {
     UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
     if (image_classes_file.get() == NULL) {
       LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
       return NULL;
     }
 
-    // Load all the classes specified in the file
-    ClassLinker* class_linker = runtime_->GetClassLinker();
-    Thread* self = Thread::Current();
+    UniquePtr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
     while (image_classes_file->good()) {
       std::string dot;
       std::getline(*image_classes_file.get(), dot);
@@ -180,51 +179,9 @@
         continue;
       }
       std::string descriptor(DotToDescriptor(dot.c_str()));
-      SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
-      if (klass.get() == NULL) {
-        LOG(WARNING) << "Failed to find class " << descriptor;
-        Thread::Current()->ClearException();
-      }
+      image_classes->insert(descriptor);
     }
     image_classes_file->close();
-
-    // Resolve exception classes referenced by the loaded classes. The catch logic assumes
-    // exceptions are resolved by the verifier when there is a catch block in an interested method.
-    // Do this here so that exception classes appear to have been specified image classes.
-    std::set<std::pair<uint16_t, const DexFile*> > unresolved_exception_types;
-    SirtRef<mirror::Class> java_lang_Throwable(self,
-                                       class_linker->FindSystemClass("Ljava/lang/Throwable;"));
-    do {
-      unresolved_exception_types.clear();
-      class_linker->VisitClasses(ResolveCatchBlockExceptionsClassVisitor,
-                                 &unresolved_exception_types);
-      typedef std::set<std::pair<uint16_t, const DexFile*> >::const_iterator It;  // TODO: C++0x auto
-      for (It it = unresolved_exception_types.begin(),
-           end = unresolved_exception_types.end();
-           it != end; ++it) {
-        uint16_t exception_type_idx = it->first;
-        const DexFile* dex_file = it->second;
-        mirror::DexCache* dex_cache = class_linker->FindDexCache(*dex_file);
-        mirror:: ClassLoader* class_loader = NULL;
-        SirtRef<mirror::Class> klass(self, class_linker->ResolveType(*dex_file, exception_type_idx,
-                                                                     dex_cache, class_loader));
-        if (klass.get() == NULL) {
-          const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
-          const char* descriptor = dex_file->GetTypeDescriptor(type_id);
-          LOG(FATAL) << "Failed to resolve class " << descriptor;
-        }
-        DCHECK(java_lang_Throwable->IsAssignableFrom(klass.get()));
-      }
-      // Resolving exceptions may load classes that reference more exceptions, iterate until no
-      // more are found
-    } while (!unresolved_exception_types.empty());
-
-    // We walk the roots looking for classes so that we'll pick up the
-    // above classes plus any classes them depend on such super
-    // classes, interfaces, and the required ClassLinker roots.
-    UniquePtr<ImageWriter::DescriptorSet> image_classes(new ImageWriter::DescriptorSet);
-    class_linker->VisitClasses(RecordImageClassesVisitor, image_classes.get());
-    CHECK_NE(image_classes->size(), 0U);
     return image_classes.release();
   }
 
@@ -236,7 +193,7 @@
                                       File* oat_file,
                                       const std::string& bitcode_filename,
                                       bool image,
-                                      const ImageWriter::DescriptorSet* image_classes,
+                                      UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
                                       bool dump_stats,
                                       bool dump_timings)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -260,9 +217,9 @@
     UniquePtr<CompilerDriver> driver(new CompilerDriver(compiler_backend_,
                                                         instruction_set_,
                                                         image,
+                                                        image_classes.release(),
                                                         thread_count_,
                                                         support_debugging_,
-                                                        image_classes,
                                                         dump_stats,
                                                         dump_timings));
 
@@ -280,11 +237,11 @@
     std::string image_file_location;
     uint32_t image_file_location_oat_checksum = 0;
     uint32_t image_file_location_oat_data_begin = 0;
-    Heap* heap = Runtime::Current()->GetHeap();
-    if (heap->GetSpaces().size() > 1) {
-      ImageSpace* image_space = heap->GetImageSpace();
+    if (!driver->IsImage()) {
+      gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
       image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
-      image_file_location_oat_data_begin = reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
+      image_file_location_oat_data_begin =
+          reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin());
       image_file_location = image_space->GetImageFilename();
       if (host_prefix != NULL && StartsWith(image_file_location, host_prefix->c_str())) {
         image_file_location = image_file_location.substr(host_prefix->size());
@@ -292,6 +249,13 @@
     }
 
     std::vector<uint8_t> oat_contents;
+    // TODO: change ElfWriterQuick to not require the creation of oat_contents. The old pre-mclinker
+    //       OatWriter streamed directly to disk. The new could can be adapted to do it as follows:
+    // 1.) use first pass of OatWriter to calculate size of oat structure,
+    // 2.) call ElfWriterQuick with pointer to OatWriter instead of contents,
+    // 3.) have ElfWriterQuick call back to OatWriter to stream generate the output directly in
+    //     place in the elf file.
+    oat_contents.reserve(5 * MB);
     VectorOutputStream vector_output_stream(oat_file->GetPath(), oat_contents);
     if (!OatWriter::Create(vector_output_stream,
                            dex_files,
@@ -313,7 +277,6 @@
 
   bool CreateImageFile(const std::string& image_filename,
                        uintptr_t image_base,
-                       ImageWriter::DescriptorSet* image_classes,
                        const std::string& oat_filename,
                        const std::string& oat_location,
                        const CompilerDriver& compiler)
@@ -321,8 +284,8 @@
     uintptr_t oat_data_begin;
     {
       // ImageWriter is scoped so it can free memory before doing FixupElf
-      ImageWriter image_writer(image_classes);
-      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location, compiler)) {
+      ImageWriter image_writer(compiler);
+      if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
         LOG(ERROR) << "Failed to create image file " << image_filename;
         return false;
       }
@@ -373,72 +336,6 @@
     return true;
   }
 
-  static void ResolveExceptionsForMethod(MethodHelper* mh,
-                           std::set<std::pair<uint16_t, const DexFile*> >& exceptions_to_resolve)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile::CodeItem* code_item = mh->GetCodeItem();
-    if (code_item == NULL) {
-      return;  // native or abstract method
-    }
-    if (code_item->tries_size_ == 0) {
-      return;  // nothing to process
-    }
-    const byte* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0);
-    size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list);
-    for (size_t i = 0; i < num_encoded_catch_handlers; i++) {
-      int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list);
-      bool has_catch_all = false;
-      if (encoded_catch_handler_size <= 0) {
-        encoded_catch_handler_size = -encoded_catch_handler_size;
-        has_catch_all = true;
-      }
-      for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
-        uint16_t encoded_catch_handler_handlers_type_idx =
-            DecodeUnsignedLeb128(&encoded_catch_handler_list);
-        // Add to set of types to resolve if not already in the dex cache resolved types
-        if (!mh->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx)) {
-          exceptions_to_resolve.insert(
-              std::pair<uint16_t, const DexFile*>(encoded_catch_handler_handlers_type_idx,
-                                                  &mh->GetDexFile()));
-        }
-        // ignore address associated with catch handler
-        DecodeUnsignedLeb128(&encoded_catch_handler_list);
-      }
-      if (has_catch_all) {
-        // ignore catch all address
-        DecodeUnsignedLeb128(&encoded_catch_handler_list);
-      }
-    }
-  }
-
-  static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    std::set<std::pair<uint16_t, const DexFile*> >* exceptions_to_resolve =
-        reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg);
-    MethodHelper mh;
-    for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
-      mirror::AbstractMethod* m = c->GetVirtualMethod(i);
-      mh.ChangeMethod(m);
-      ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
-    }
-    for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
-      mirror::AbstractMethod* m = c->GetDirectMethod(i);
-      mh.ChangeMethod(m);
-      ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
-    }
-    return true;
-  }
-
-  static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ImageWriter::DescriptorSet* image_classes = reinterpret_cast<ImageWriter::DescriptorSet*>(arg);
-    if (klass->IsArrayClass() || klass->IsPrimitive()) {
-      return true;
-    }
-    image_classes->insert(ClassHelper(klass).GetDescriptor());
-    return true;
-  }
-
   // Appends to dex_files any elements of class_path that it doesn't already
   // contain. This will open those dex files as necessary.
   static void OpenClassPathFiles(const std::string& class_path, std::vector<const DexFile*>& dex_files) {
@@ -561,12 +458,14 @@
  private:
   static void* CallBack(void* arg) {
     WatchDog* self = reinterpret_cast<WatchDog*>(arg);
+    ::art::SetThreadName("dex2oat watch dog");
     self->Wait();
     return NULL;
   }
 
   static void Message(char severity, const std::string& message) {
-    // TODO: Remove when we switch to LOG when we can guarantee it won't prevent shutdown in error cases.
+    // TODO: Remove when we switch to LOG when we can guarantee it won't prevent shutdown in error
+    //       cases.
     fprintf(stderr, "dex2oat%s %c %d %d %s\n",
             kIsDebugBuild ? "d" : "",
             severity,
@@ -587,10 +486,13 @@
   void Wait() {
     bool warning = true;
     CHECK_GT(kWatchDogTimeoutSeconds, kWatchDogWarningSeconds);
+    // TODO: tune the multiplier for GC verification, the following is just to make the timeout
+    //       large.
+    int64_t multiplier = gc::kDesiredHeapVerification > gc::kVerifyAllFast ? 100 : 1;
     timespec warning_ts;
-    InitTimeSpec(true, CLOCK_REALTIME, kWatchDogWarningSeconds * 1000, 0, &warning_ts);
+    InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogWarningSeconds * 1000, 0, &warning_ts);
     timespec timeout_ts;
-    InitTimeSpec(true, CLOCK_REALTIME, kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
+    InitTimeSpec(true, CLOCK_REALTIME, multiplier * kWatchDogTimeoutSeconds * 1000, 0, &timeout_ts);
     const char* reason = "dex2oat watch dog thread waiting";
     CHECK_WATCH_DOG_PTHREAD_CALL(pthread_mutex_lock, (&mutex_), reason);
     while (!shutting_down_) {
@@ -627,12 +529,14 @@
 
   bool is_watch_dog_enabled_;
   bool shutting_down_;
-  // TODO: Switch to Mutex when we can guarantee it won't prevent shutdown in error cases
+  // TODO: Switch to Mutex when we can guarantee it won't prevent shutdown in error cases.
   pthread_mutex_t mutex_;
   pthread_cond_t cond_;
   pthread_attr_t attr_;
   pthread_t pthread_;
 };
+const unsigned int WatchDog::kWatchDogWarningSeconds;
+const unsigned int WatchDog::kWatchDogTimeoutSeconds;
 
 static int dex2oat(int argc, char** argv) {
   InitLogging(argv);
@@ -920,7 +824,7 @@
 #endif // ART_SMALL_MODE
 
   Dex2Oat* p_dex2oat;
-  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count, 
+  if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count,
                        support_debugging)) {
     LOG(ERROR) << "Failed to create dex2oat";
     return EXIT_FAILURE;
@@ -934,9 +838,9 @@
   ScopedObjectAccess soa(Thread::Current());
 
   // If --image-classes was specified, calculate the full list of classes to include in the image
-  UniquePtr<ImageWriter::DescriptorSet> image_classes(NULL);
+  UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
   if (image_classes_filename != NULL) {
-    image_classes.reset(dex2oat->GetImageClassDescriptors(image_classes_filename));
+    image_classes.reset(dex2oat->ReadImageClasses(image_classes_filename));
     if (image_classes.get() == NULL) {
       LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
       return EXIT_FAILURE;
@@ -992,7 +896,7 @@
                                                                   oat_file.get(),
                                                                   bitcode_filename,
                                                                   image,
-                                                                  image_classes.get(),
+                                                                  image_classes,
                                                                   dump_stats,
                                                                   dump_timings));
 
@@ -1057,7 +961,6 @@
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
     bool image_creation_success = dex2oat->CreateImageFile(image_filename,
                                                            image_base,
-                                                           image_classes.get(),
                                                            oat_unstripped,
                                                            oat_location,
                                                            *compiler.get());
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 0f0bed4..dad083c 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -373,10 +373,10 @@
   const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
   const uint32_t name_idx = GetIndexForStringId(name);
   const uint16_t type_idx = GetIndexForTypeId(type);
-  uint32_t lo = 0;
-  uint32_t hi = NumFieldIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumFieldIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const DexFile::FieldId& field = GetFieldId(mid);
     if (class_idx > field.class_idx_) {
       lo = mid + 1;
@@ -408,10 +408,10 @@
   const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
   const uint32_t name_idx = GetIndexForStringId(name);
   const uint16_t proto_idx = GetIndexForProtoId(signature);
-  uint32_t lo = 0;
-  uint32_t hi = NumMethodIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumMethodIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const DexFile::MethodId& method = GetMethodId(mid);
     if (class_idx > method.class_idx_) {
       lo = mid + 1;
@@ -436,15 +436,35 @@
   return NULL;
 }
 
-const DexFile::StringId* DexFile::FindStringId(const std::string& string) const {
-  uint32_t lo = 0;
-  uint32_t hi = NumStringIds() - 1;
+const DexFile::StringId* DexFile::FindStringId(const char* string) const {
+  int32_t lo = 0;
+  int32_t hi = NumStringIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     uint32_t length;
     const DexFile::StringId& str_id = GetStringId(mid);
     const char* str = GetStringDataAndLength(str_id, &length);
-    int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string.c_str(), str);
+    int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
+    if (compare > 0) {
+      lo = mid + 1;
+    } else if (compare < 0) {
+      hi = mid - 1;
+    } else {
+      return &str_id;
+    }
+  }
+  return NULL;
+}
+
+const DexFile::StringId* DexFile::FindStringId(const uint16_t* string) const {
+  int32_t lo = 0;
+  int32_t hi = NumStringIds() - 1;
+  while (hi >= lo) {
+    int32_t mid = (hi + lo) / 2;
+    uint32_t length;
+    const DexFile::StringId& str_id = GetStringId(mid);
+    const char* str = GetStringDataAndLength(str_id, &length);
+    int compare = CompareModifiedUtf8ToUtf16AsCodePointValues(str, string);
     if (compare > 0) {
       lo = mid + 1;
     } else if (compare < 0) {
@@ -457,10 +477,10 @@
 }
 
 const DexFile::TypeId* DexFile::FindTypeId(uint32_t string_idx) const {
-  uint32_t lo = 0;
-  uint32_t hi = NumTypeIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumTypeIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const TypeId& type_id = GetTypeId(mid);
     if (string_idx > type_id.descriptor_idx_) {
       lo = mid + 1;
@@ -475,10 +495,10 @@
 
 const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
                                          const std::vector<uint16_t>& signature_type_idxs) const {
-  uint32_t lo = 0;
-  uint32_t hi = NumProtoIds() - 1;
+  int32_t lo = 0;
+  int32_t hi = NumProtoIds() - 1;
   while (hi >= lo) {
-    uint32_t mid = (hi + lo) / 2;
+    int32_t mid = (hi + lo) / 2;
     const DexFile::ProtoId& proto = GetProtoId(mid);
     int compare = return_type_idx - proto.return_type_idx_;
     if (compare == 0) {
@@ -544,7 +564,7 @@
         descriptor += c;
       } while (c != ';');
     }
-    const DexFile::StringId* string_id = FindStringId(descriptor);
+    const DexFile::StringId* string_id = FindStringId(descriptor.c_str());
     if (string_id == NULL) {
       return false;
     }
diff --git a/src/dex_file.h b/src/dex_file.h
index 6e34b57..ecc985f 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -436,8 +436,11 @@
     return StringDataAndLengthByIdx(idx, &unicode_length);
   }
 
-  // Looks up a string id for a given string
-  const StringId* FindStringId(const std::string& string) const;
+  // Looks up a string id for a given modified utf8 string.
+  const StringId* FindStringId(const char* string) const;
+
+  // Looks up a string id for a given utf16 string.
+  const StringId* FindStringId(const uint16_t* string) const;
 
   // Returns the number of type identifiers in the .dex file.
   size_t NumTypeIds() const {
@@ -974,7 +977,7 @@
   bool HasNext() const {
     return pos_ < EndOfVirtualMethodsPos();
   }
-  void Next() {
+  inline void Next() {
     pos_++;
     if (pos_ < EndOfStaticFieldsPos()) {
       last_idx_ = GetMemberIndex();
diff --git a/src/dex_file_verifier.cc b/src/dex_file_verifier.cc
index b1efcaa..6df4411 100644
--- a/src/dex_file_verifier.cc
+++ b/src/dex_file_verifier.cc
@@ -369,10 +369,12 @@
   }
 
   if (expect_code && code_offset == 0) {
-    LOG(ERROR) << StringPrintf("Unexpected zero value for class_data_item method code_off with access flags %x", access_flags);
+    LOG(ERROR)<< StringPrintf("Unexpected zero value for class_data_item method code_off"
+        " with access flags %x", access_flags);
     return false;
   } else if (!expect_code && code_offset != 0) {
-    LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off with access flags %x", code_offset, access_flags);
+    LOG(ERROR) << StringPrintf("Unexpected non-zero value %x for class_data_item method code_off"
+        " with access flags %x", code_offset, access_flags);
     return false;
   }
 
@@ -544,7 +546,8 @@
     }
 
     if (last_idx >= idx && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x", last_idx, idx);
+      LOG(ERROR) << StringPrintf("Out-of-order annotation_element name_idx: %x then %x",
+          last_idx, idx);
       return false;
     }
 
@@ -651,7 +654,8 @@
   uint32_t last_addr = 0;
   while (try_items_size--) {
     if (try_items->start_addr_ < last_addr) {
-      LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_);
+      LOG(ERROR) << StringPrintf("Out-of_order try_item with start_addr: %x",
+          try_items->start_addr_);
       return false;
     }
 
@@ -933,7 +937,8 @@
   last_idx = 0;
   for (uint32_t i = 0; i < method_count; i++) {
     if (last_idx >= method_item->method_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", last_idx, method_item->method_idx_);
+      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
+          last_idx, method_item->method_idx_);
       return false;
     }
     last_idx = method_item->method_idx_;
@@ -944,14 +949,16 @@
   const DexFile::ParameterAnnotationsItem* parameter_item =
       reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
   uint32_t parameter_count = item->parameters_size_;
-  if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem), "parameter_annotations list")) {
+  if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem),
+      "parameter_annotations list")) {
     return false;
   }
 
   last_idx = 0;
   for (uint32_t i = 0; i < parameter_count; i++) {
     if (last_idx >= parameter_item->method_idx_ && i != 0) {
-      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x", last_idx, parameter_item->method_idx_);
+      LOG(ERROR) << StringPrintf("Out-of-order method_idx for annotation: %x then %x",
+          last_idx, parameter_item->method_idx_);
       return false;
     }
     last_idx = parameter_item->method_idx_;
@@ -1051,7 +1058,8 @@
         uint32_t count = list->size_;
 
         if (!CheckPointerRange(list, list + 1, "annotation_set_ref_list") ||
-            !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem), "annotation_set_ref_list size")) {
+            !CheckListSize(item, count, sizeof(DexFile::AnnotationSetRefItem),
+                "annotation_set_ref_list size")) {
           return false;
         }
         ptr_ = reinterpret_cast<const byte*>(item + count);
@@ -1257,7 +1265,8 @@
           return false;
         }
         if (section_offset != header_->map_off_) {
-          LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x", section_offset, header_->map_off_);
+          LOG(ERROR) << StringPrintf("Map not at header-defined offset: %x, expected %x",
+              section_offset, header_->map_off_);
           return false;
         }
         ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
@@ -1297,7 +1306,8 @@
     return false;
   }
   if (it->second != type) {
-    LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x", offset, type, it->second);
+    LOG(ERROR) << StringPrintf("Unexpected data map entry @ %x; expected %x, found %x",
+        offset, type, it->second);
     return false;
   }
   return true;
@@ -1380,7 +1390,8 @@
   if (previous_item_ != NULL) {
     const DexFile::TypeId* prev_item = reinterpret_cast<const DexFile::TypeId*>(previous_item_);
     if (prev_item->descriptor_idx_ >= item->descriptor_idx_) {
-      LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x", prev_item->descriptor_idx_, item->descriptor_idx_);
+      LOG(ERROR) << StringPrintf("Out-of-order type_ids: %x then %x",
+          prev_item->descriptor_idx_, item->descriptor_idx_);
       return false;
     }
   }
@@ -1757,7 +1768,8 @@
       LOG(ERROR) << "Mismatched defining class for parameter_annotation";
       return false;
     }
-    if (!CheckOffsetToTypeMap(parameter_item->annotations_off_, DexFile::kDexTypeAnnotationSetRefList)) {
+    if (!CheckOffsetToTypeMap(parameter_item->annotations_off_,
+        DexFile::kDexTypeAnnotationSetRefList)) {
       return false;
     }
     parameter_item++;
diff --git a/src/dex_instruction-inl.h b/src/dex_instruction-inl.h
index 99dab12..b426e66 100644
--- a/src/dex_instruction-inl.h
+++ b/src/dex_instruction-inl.h
@@ -21,13 +21,6 @@
 
 namespace art {
 
-inline const Instruction* Instruction::Next_51l() const {
-  DCHECK_EQ(FormatOf(Opcode()), k51l);
-  size_t current_size_in_bytes = 5 * sizeof(uint16_t);
-  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-  return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
-}
-
 //------------------------------------------------------------------------------
 // VRegA
 //------------------------------------------------------------------------------
@@ -36,6 +29,11 @@
   return static_cast<int8_t>(InstAA());
 }
 
+inline uint8_t Instruction::VRegA_10x() const {
+  DCHECK_EQ(FormatOf(Opcode()), k10x);
+  return InstAA();
+}
+
 inline uint4_t Instruction::VRegA_11n() const {
   DCHECK_EQ(FormatOf(Opcode()), k11n);
   return InstA();
diff --git a/src/dex_instruction.cc b/src/dex_instruction.cc
index 1b7d3bb..b18b4d0 100644
--- a/src/dex_instruction.cc
+++ b/src/dex_instruction.cc
@@ -299,7 +299,7 @@
         case NEW_INSTANCE:
           if (file != NULL) {
             uint32_t type_idx = VRegB_21c();
-            os << opcode << " v" << VRegA_21c() << ", " << PrettyType(type_idx, *file)
+            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file)
                << " // type@" << type_idx;
             break;
           }  // else fall-through
@@ -312,7 +312,7 @@
         case SGET_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegB_21c();
-            os << opcode << "  v" << VRegA_21c() << ", " << PrettyField(field_idx, *file, true)
+            os << opcode << "  v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
                << " // field@" << field_idx;
             break;
           }  // else fall-through
@@ -325,7 +325,7 @@
         case SPUT_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegB_21c();
-            os << opcode << " v" << VRegA_21c() << ", " << PrettyField(field_idx, *file, true)
+            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true)
                << " // field@" << field_idx;
             break;
           }  // else fall-through
@@ -350,7 +350,7 @@
         case IGET_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
             break;
           }  // else fall-through
@@ -363,21 +363,21 @@
         case IPUT_SHORT:
           if (file != NULL) {
             uint32_t field_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyField(field_idx, *file, true) << " // field@" << field_idx;
             break;
           }  // else fall-through
         case INSTANCE_OF:
           if (file != NULL) {
             uint32_t type_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyType(type_idx, *file) << " // type@" << type_idx;
             break;
           }
         case NEW_ARRAY:
           if (file != NULL) {
             uint32_t type_idx = VRegC_22c();
-            os << opcode << " v" << VRegA_22c() << ", v" << VRegB_22c() << ", "
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
                << PrettyType(type_idx, *file) << " // type@" << type_idx;
             break;
           }  // else fall-through
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 218acb6..adaada7 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -162,39 +162,45 @@
     }
   }
 
+  // Reads an instruction out of the stream at the specified address.
+  static const Instruction* At(const uint16_t* code) {
+    DCHECK(code != NULL);
+    return reinterpret_cast<const Instruction*>(code);
+  }
+
+  // Reads an instruction out of the stream from the current address plus an offset.
+  const Instruction* RelativeAt(int32_t offset) const {
+    return At(reinterpret_cast<const uint16_t*>(this) + offset);
+  }
+
   // Returns a pointer to the next instruction in the stream.
   const Instruction* Next() const {
-    size_t current_size_in_bytes = SizeInCodeUnits() * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(SizeInCodeUnits());
   }
 
   // Returns a pointer to the instruction after this 1xx instruction in the stream.
   const Instruction* Next_1xx() const {
     DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t);
-    size_t current_size_in_bytes = 1 * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(1);
   }
 
   // Returns a pointer to the instruction after this 2xx instruction in the stream.
   const Instruction* Next_2xx() const {
     DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c);
-    size_t current_size_in_bytes = 2 * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(2);
   }
 
   // Returns a pointer to the instruction after this 3xx instruction in the stream.
   const Instruction* Next_3xx() const {
     DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc);
-    size_t current_size_in_bytes = 3 * sizeof(uint16_t);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this);
-    return reinterpret_cast<const Instruction*>(ptr + current_size_in_bytes);
+    return RelativeAt(3);
   }
 
   // Returns a pointer to the instruction after this 51l instruction in the stream.
-  const Instruction* Next_51l() const;
+  const Instruction* Next_51l() const {
+    DCHECK(FormatOf(Opcode()) == k51l);
+    return RelativeAt(5);
+  }
 
   // Returns the name of this instruction's opcode.
   const char* Name() const {
@@ -208,6 +214,7 @@
 
   // VRegA
   int8_t VRegA_10t() const;
+  uint8_t VRegA_10x() const;
   uint4_t VRegA_11n() const;
   uint8_t VRegA_11x() const;
   uint4_t VRegA_12x() const;
@@ -271,12 +278,6 @@
     return static_cast<Code>(opcode);
   }
 
-  // Reads an instruction out of the stream at the specified address.
-  static const Instruction* At(const uint16_t* code) {
-    CHECK(code != NULL);
-    return reinterpret_cast<const Instruction*>(code);
-  }
-
   // Returns the format of the given opcode.
   static Format FormatOf(Code opcode) {
     return kInstructionFormats[opcode];
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index 7e75600..172bef8 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -1223,7 +1223,7 @@
         args << Rt << ", [" << Rn << ", #" << imm5 << "]";
       }
     } else if (opcode1 >= 0x34 && opcode1 <= 0x37) {  // 1101xx
-      uint32_t imm8 = instr & 0xFF;
+      int8_t imm8 = instr & 0xFF;
       uint32_t cond = (instr >> 8) & 0xF;
       opcode << "b";
       DumpCond(opcode, cond);
@@ -1260,7 +1260,7 @@
           uint16_t imm5 = (instr >> 3) & 0x1F;
           ThumbRegister Rn(instr, 0);
           opcode << (op != 0 ? "cbnz" : "cbz");
-          uint32_t imm32 = (i << 7) | (imm5 << 1);
+          uint32_t imm32 = (i << 6) | (imm5 << 1);
           args << Rn << ", ";
           DumpBranchTarget(args, instr_ptr + 4, imm32);
           break;
diff --git a/src/gc/atomic_stack.h b/src/gc/accounting/atomic_stack.h
similarity index 80%
rename from src/gc/atomic_stack.h
rename to src/gc/accounting/atomic_stack.h
index 0197bce..4e1c253 100644
--- a/src/gc/atomic_stack.h
+++ b/src/gc/accounting/atomic_stack.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_ATOMIC_STACK_H_
-#define ART_SRC_ATOMIC_STACK_H_
+#ifndef ART_SRC_GC_ACCOUNTING_ATOMIC_STACK_H_
+#define ART_SRC_GC_ACCOUNTING_ATOMIC_STACK_H_
 
 #include <string>
 
@@ -27,6 +27,8 @@
 #include "utils.h"
 
 namespace art {
+namespace gc {
+namespace accounting {
 
 template <typename T>
 class AtomicStack {
@@ -38,15 +40,14 @@
     return mark_stack.release();
   }
 
-  ~AtomicStack(){
-
-  }
+  ~AtomicStack() {}
 
   void Reset() {
     DCHECK(mem_map_.get() != NULL);
     DCHECK(begin_ != NULL);
     front_index_ = 0;
     back_index_ = 0;
+    is_sorted_ = true;
     int result = madvise(begin_, sizeof(T) * capacity_, MADV_DONTNEED);
     if (result == -1) {
       PLOG(WARNING) << "madvise failed";
@@ -58,6 +59,7 @@
   // Returns false if we overflowed the stack.
   bool AtomicPushBack(const T& value) {
     int32_t index;
+    is_sorted_ = false;
     do {
       index = back_index_;
       if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
@@ -70,6 +72,7 @@
   }
 
   void PushBack(const T& value) {
+    is_sorted_ = false;
     int32_t index = back_index_;
     DCHECK_LT(static_cast<size_t>(index), capacity_);
     back_index_ = index + 1;
@@ -100,11 +103,11 @@
     return back_index_ - front_index_;
   }
 
-  T* Begin() {
+  T* Begin() const {
     return const_cast<mirror::Object**>(begin_ + front_index_);
   }
 
-  T* End() {
+  T* End() const {
     return const_cast<mirror::Object**>(begin_ + back_index_);
   }
 
@@ -118,14 +121,33 @@
     Init();
   }
 
+  void Sort() {
+    if (!is_sorted_) {
+      int32_t start_back_index = back_index_.get();
+      int32_t start_front_index = front_index_.get();
+      is_sorted_ = true;
+      std::sort(Begin(), End());
+      CHECK_EQ(start_back_index, back_index_.get());
+      CHECK_EQ(start_front_index, front_index_.get());
+    }
+  }
+
+  bool Contains(const T& value) const {
+    if (is_sorted_) {
+      return std::binary_search(Begin(), End(), value);
+    } else {
+      return std::find(Begin(), End(), value) != End();
+    }
+  }
+
  private:
   AtomicStack(const std::string& name, const size_t capacity)
       : name_(name),
         back_index_(0),
         front_index_(0),
         begin_(NULL),
-        capacity_(capacity) {
-
+        capacity_(capacity),
+        is_sorted_(true) {
   }
 
   // Size in number of elements.
@@ -156,11 +178,15 @@
   // Maximum number of elements.
   size_t capacity_;
 
+  bool is_sorted_;
+
   DISALLOW_COPY_AND_ASSIGN(AtomicStack);
 };
 
 typedef AtomicStack<mirror::Object*> ObjectStack;
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
 
-#endif  // ART_SRC_MARK_STACK_H_
+#endif  // ART_SRC_GC_ACCOUNTING_ATOMIC_STACK_H_
diff --git a/src/gc/card_table-inl.h b/src/gc/accounting/card_table-inl.h
similarity index 98%
rename from src/gc/card_table-inl.h
rename to src/gc/accounting/card_table-inl.h
index 13590b7..1e75290 100644
--- a/src/gc/card_table-inl.h
+++ b/src/gc/accounting/card_table-inl.h
@@ -24,6 +24,8 @@
 #include "utils.h"
 
 namespace art {
+namespace gc {
+namespace accounting {
 
 static inline bool byte_cas(byte old_value, byte new_value, byte* address) {
   // Little endian means most significant byte is on the left.
@@ -204,6 +206,8 @@
       << " end: " << reinterpret_cast<void*>(mem_map_->End());
 }
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
 
 #endif  // ART_SRC_GC_CARDTABLE_INL_H_
diff --git a/src/gc/card_table.cc b/src/gc/accounting/card_table.cc
similarity index 95%
rename from src/gc/card_table.cc
rename to src/gc/accounting/card_table.cc
index 57824e9..4f2ae26 100644
--- a/src/gc/card_table.cc
+++ b/src/gc/accounting/card_table.cc
@@ -17,14 +17,17 @@
 #include "card_table.h"
 
 #include "base/logging.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "card_table-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
 #include "heap_bitmap.h"
 #include "runtime.h"
-#include "space.h"
 #include "utils.h"
 
 namespace art {
+namespace gc {
+namespace accounting {
+
 /*
  * Maintain a card table from the write barrier. All writes of
  * non-NULL values to heap addresses should go through an entry in
@@ -82,7 +85,7 @@
   byte* __attribute__((unused)) end = mem_map_->End();
 }
 
-void CardTable::ClearSpaceCards(ContinuousSpace* space) {
+void CardTable::ClearSpaceCards(space::ContinuousSpace* space) {
   // TODO: clear just the range of the table that has been modified
   byte* card_start = CardFromAddr(space->Begin());
   byte* card_end = CardFromAddr(space->End()); // Make sure to round up.
@@ -116,4 +119,6 @@
   UNIMPLEMENTED(WARNING) << "Card table verification";
 }
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/card_table.h b/src/gc/accounting/card_table.h
similarity index 95%
rename from src/gc/card_table.h
rename to src/gc/accounting/card_table.h
index 842fcc3..cf85d15 100644
--- a/src/gc/card_table.h
+++ b/src/gc/accounting/card_table.h
@@ -23,11 +23,21 @@
 #include "UniquePtr.h"
 
 namespace art {
+
 namespace mirror {
-class Object;
+  class Object;
 }  // namespace mirror
+
+namespace gc {
+
+namespace space {
+  class ContinuousSpace;
+}  // namespace space
+
 class Heap;
-class ContinuousSpace;
+
+namespace accounting {
+
 class SpaceBitmap;
 
 // Maintain a card table from the the write barrier. All writes of
@@ -105,7 +115,7 @@
   void ClearCardTable();
 
   // Resets all of the bytes in the card table which do not map to the image space.
-  void ClearSpaceCards(ContinuousSpace* space);
+  void ClearSpaceCards(space::ContinuousSpace* space);
 
   // Returns the first address in the heap which maps to this card.
   void* AddrFromCard(const byte *card_addr) const;
@@ -139,5 +149,8 @@
   const size_t offset_;
 };
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
+
 #endif  // ART_SRC_GC_CARDTABLE_H_
diff --git a/src/gc/accounting/heap_bitmap-inl.h b/src/gc/accounting/heap_bitmap-inl.h
new file mode 100644
index 0000000..8e3123b
--- /dev/null
+++ b/src/gc/accounting/heap_bitmap-inl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_INL_H_
+#define ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_INL_H_
+
+#include "heap_bitmap.h"
+
+namespace art {
+namespace gc {
+namespace accounting {
+
+template <typename Visitor>
+inline void HeapBitmap::Visit(const Visitor& visitor) {
+  // TODO: C++0x auto
+  typedef std::vector<SpaceBitmap*>::iterator It;
+  for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+      it != end; ++it) {
+    SpaceBitmap* bitmap = *it;
+    bitmap->VisitMarkedRange(bitmap->HeapBegin(), bitmap->HeapLimit(), visitor, VoidFunctor());
+  }
+  // TODO: C++0x auto
+  typedef std::vector<SpaceSetMap*>::iterator It2;
+  DCHECK(discontinuous_space_sets_.begin() !=  discontinuous_space_sets_.end());
+  for (It2 it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+      it != end; ++it) {
+    SpaceSetMap* set = *it;
+    set->Visit(visitor);
+  }
+
+}
+
+}  // namespace accounting
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_INL_H_
diff --git a/src/gc/accounting/heap_bitmap.cc b/src/gc/accounting/heap_bitmap.cc
new file mode 100644
index 0000000..1bdc978
--- /dev/null
+++ b/src/gc/accounting/heap_bitmap.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "heap_bitmap.h"
+
+#include "gc/space/space.h"
+
+namespace art {
+namespace gc {
+namespace accounting {
+
+void HeapBitmap::ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap) {
+  // TODO: C++0x auto
+  typedef std::vector<SpaceBitmap*>::iterator It;
+  for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+      it != end; ++it) {
+    if (*it == old_bitmap) {
+      *it = new_bitmap;
+      return;
+    }
+  }
+  LOG(FATAL) << "bitmap " << static_cast<const void*>(old_bitmap) << " not found";
+}
+
+void HeapBitmap::ReplaceObjectSet(SpaceSetMap* old_set, SpaceSetMap* new_set) {
+  // TODO: C++0x auto
+  typedef std::vector<SpaceSetMap*>::iterator It;
+  for (It it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+      it != end; ++it) {
+    if (*it == old_set) {
+      *it = new_set;
+      return;
+    }
+  }
+  LOG(FATAL) << "object set " << static_cast<const void*>(old_set) << " not found";
+}
+
+void HeapBitmap::AddContinuousSpaceBitmap(accounting::SpaceBitmap* bitmap) {
+  DCHECK(bitmap != NULL);
+
+  // Check for interval overlap.
+  typedef std::vector<SpaceBitmap*>::iterator It;
+  for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+      it != end; ++it) {
+    SpaceBitmap* bitmap = *it;
+    SpaceBitmap* cur_bitmap = *it;
+    CHECK(bitmap->HeapBegin() < cur_bitmap->HeapLimit() &&
+          bitmap->HeapLimit() > cur_bitmap->HeapBegin())
+        << "Bitmap " << bitmap->Dump() << " overlaps with existing bitmap " << cur_bitmap->Dump();
+  }
+  continuous_space_bitmaps_.push_back(bitmap);
+}
+
+void HeapBitmap::AddDiscontinuousObjectSet(SpaceSetMap* set) {
+  DCHECK(set != NULL);
+  discontinuous_space_sets_.push_back(set);
+}
+
+void HeapBitmap::Walk(SpaceBitmap::Callback* callback, void* arg) {
+  // TODO: C++0x auto
+  typedef std::vector<SpaceBitmap*>::iterator It;
+  for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+      it != end; ++it) {
+    SpaceBitmap* bitmap = *it;
+    bitmap->Walk(callback, arg);
+  }
+  // TODO: C++0x auto
+  typedef std::vector<SpaceSetMap*>::iterator It2;
+  DCHECK(discontinuous_space_sets_.begin() !=  discontinuous_space_sets_.end());
+  for (It2 it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+      it != end; ++it) {
+    SpaceSetMap* set = *it;
+    set->Walk(callback, arg);
+  }
+}
+
+}  // namespace accounting
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/accounting/heap_bitmap.h b/src/gc/accounting/heap_bitmap.h
new file mode 100644
index 0000000..5ff40c6
--- /dev/null
+++ b/src/gc/accounting/heap_bitmap.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_H_
+#define ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_H_
+
+#include "base/logging.h"
+#include "locks.h"
+#include "space_bitmap.h"
+
+namespace art {
+namespace gc {
+
+class Heap;
+
+namespace accounting {
+
+class HeapBitmap {
+ public:
+  bool Test(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
+    if (LIKELY(bitmap != NULL)) {
+      return bitmap->Test(obj);
+    } else {
+      return GetDiscontinuousSpaceObjectSet(obj) != NULL;
+    }
+  }
+
+  void Clear(const mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
+    if (LIKELY(bitmap != NULL)) {
+      bitmap->Clear(obj);
+    } else {
+      SpaceSetMap* set = GetDiscontinuousSpaceObjectSet(obj);
+      DCHECK(set != NULL);
+      set->Clear(obj);
+    }
+  }
+
+  void Set(const mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    SpaceBitmap* bitmap = GetContinuousSpaceBitmap(obj);
+    if (LIKELY(bitmap != NULL)) {
+      bitmap->Set(obj);
+    } else {
+      SpaceSetMap* set = GetDiscontinuousSpaceObjectSet(obj);
+      DCHECK(set != NULL);
+      set->Set(obj);
+    }
+  }
+
+  SpaceBitmap* GetContinuousSpaceBitmap(const mirror::Object* obj) {
+    // TODO: C++0x auto
+    typedef std::vector<SpaceBitmap*>::iterator It;
+    for (It it = continuous_space_bitmaps_.begin(), end = continuous_space_bitmaps_.end();
+        it != end; ++it) {
+      SpaceBitmap* bitmap = *it;
+      if (bitmap->HasAddress(obj)) {
+        return bitmap;
+      }
+    }
+    return NULL;
+  }
+
+  SpaceSetMap* GetDiscontinuousSpaceObjectSet(const mirror::Object* obj) {
+    // TODO: C++0x auto
+    typedef std::vector<SpaceSetMap*>::iterator It;
+    for (It it = discontinuous_space_sets_.begin(), end = discontinuous_space_sets_.end();
+        it != end; ++it) {
+      SpaceSetMap* set = *it;
+      if (set->Test(obj)) {
+        return set;
+      }
+    }
+    return NULL;
+  }
+
+  void Walk(SpaceBitmap::Callback* callback, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  template <typename Visitor>
+  void Visit(const Visitor& visitor)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Find and replace a bitmap pointer, this is used by for the bitmap swapping in the GC.
+  void ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  // Find and replace a object set pointer, this is used by for the bitmap swapping in the GC.
+  void ReplaceObjectSet(SpaceSetMap* old_set, SpaceSetMap* new_set)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  HeapBitmap(Heap* heap) : heap_(heap) {
+  }
+
+ private:
+
+  const Heap* const heap_;
+
+  void AddContinuousSpaceBitmap(SpaceBitmap* bitmap);
+  void AddDiscontinuousObjectSet(SpaceSetMap* set);
+
+  // Bitmaps covering continuous spaces.
+  std::vector<SpaceBitmap*> continuous_space_bitmaps_;
+
+  // Sets covering discontinuous spaces.
+  std::vector<SpaceSetMap*> discontinuous_space_sets_;
+
+  friend class art::gc::Heap;
+};
+
+}  // namespace accounting
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_ACCOUNTING_HEAP_BITMAP_H_
diff --git a/src/gc/accounting/mod_union_table-inl.h b/src/gc/accounting/mod_union_table-inl.h
new file mode 100644
index 0000000..656af94
--- /dev/null
+++ b/src/gc/accounting/mod_union_table-inl.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_MOD_UNION_TABLE_INL_H_
+#define ART_SRC_GC_MOD_UNION_TABLE_INL_H_
+
+#include "mod_union_table.h"
+
+#include "gc/space/space.h"
+
+namespace art {
+namespace gc {
+namespace accounting {
+
+// A mod-union table to record image references to the Zygote and alloc space.
+class ModUnionTableToZygoteAllocspace : public ModUnionTableReferenceCache {
+public:
+  ModUnionTableToZygoteAllocspace(Heap* heap) : ModUnionTableReferenceCache(heap) {
+  }
+
+  bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
+    const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+    typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+    for (It it = spaces.begin(); it != spaces.end(); ++it) {
+      if ((*it)->Contains(ref)) {
+        return (*it)->IsDlMallocSpace();
+      }
+    }
+    // Assume it points to a large object.
+    // TODO: Check.
+    return true;
+  }
+};
+
+// A mod-union table to record Zygote references to the alloc space.
+class ModUnionTableToAllocspace : public ModUnionTableReferenceCache {
+ public:
+  ModUnionTableToAllocspace(Heap* heap) : ModUnionTableReferenceCache(heap) {
+  }
+
+  bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
+    const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+    typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+    for (It it = spaces.begin(); it != spaces.end(); ++it) {
+      space::ContinuousSpace* space = *it;
+      if (space->Contains(ref)) {
+        // The allocation space is always considered for collection whereas the Zygote space is
+        //
+        return space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect;
+      }
+    }
+    // Assume it points to a large object.
+    // TODO: Check.
+    return true;
+  }
+};
+
+}  // namespace accounting
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_MOD_UNION_TABLE_INL_H_
diff --git a/src/gc/accounting/mod_union_table.cc b/src/gc/accounting/mod_union_table.cc
new file mode 100644
index 0000000..05b68c4
--- /dev/null
+++ b/src/gc/accounting/mod_union_table.cc
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mod_union_table.h"
+
+#include "base/stl_util.h"
+#include "card_table-inl.h"
+#include "heap_bitmap.h"
+#include "gc/collector/mark_sweep-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
+#include "mirror/object-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/field-inl.h"
+#include "mirror/object_array-inl.h"
+#include "space_bitmap-inl.h"
+#include "thread.h"
+#include "UniquePtr.h"
+
+using namespace art::mirror;
+
+namespace art {
+namespace gc {
+namespace accounting {
+
+class MarkIfReachesAllocspaceVisitor {
+ public:
+  explicit MarkIfReachesAllocspaceVisitor(Heap* const heap, accounting::SpaceBitmap* bitmap)
+    : heap_(heap),
+      bitmap_(bitmap) {
+  }
+
+  // Extra parameters are required since we use this same visitor signature for checking objects.
+  void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
+                   bool /* is_static */) const {
+    // TODO: Optimize?
+    // TODO: C++0x auto
+    const std::vector<space::ContinuousSpace*>& spaces = heap_->GetContinuousSpaces();
+    typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+    for (It cur = spaces.begin(); cur != spaces.end(); ++cur) {
+      if ((*cur)->IsDlMallocSpace() && (*cur)->Contains(ref)) {
+        bitmap_->Set(obj);
+        break;
+      }
+    }
+  }
+
+ private:
+  Heap* const heap_;
+  accounting::SpaceBitmap* const bitmap_;
+};
+
+class ModUnionVisitor {
+ public:
+  explicit ModUnionVisitor(Heap* const heap, accounting::SpaceBitmap* bitmap)
+    : heap_(heap),
+      bitmap_(bitmap) {
+  }
+
+  void operator ()(const Object* obj) const
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
+                            Locks::mutator_lock_) {
+    DCHECK(obj != NULL);
+    // We don't have an early exit since we use the visitor pattern, an early exit should
+    // significantly speed this up.
+    MarkIfReachesAllocspaceVisitor visitor(heap_, bitmap_);
+    collector::MarkSweep::VisitObjectReferences(obj, visitor);
+  }
+ private:
+  Heap* const heap_;
+  accounting::SpaceBitmap* const bitmap_;
+};
+
+class ModUnionClearCardSetVisitor {
+ public:
+  explicit ModUnionClearCardSetVisitor(std::set<byte*>* const cleared_cards)
+    : cleared_cards_(cleared_cards) {
+  }
+
+  inline void operator ()(byte* card, byte expected_value, byte new_value) const {
+    if (expected_value == CardTable::kCardDirty) {
+      cleared_cards_->insert(card);
+    }
+  }
+
+ private:
+  std::set<byte*>* const cleared_cards_;
+};
+
+class ModUnionClearCardVisitor {
+ public:
+  explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
+    : cleared_cards_(cleared_cards) {
+  }
+
+  void operator ()(byte* card, byte expected_card, byte new_card) const {
+    if (expected_card == CardTable::kCardDirty) {
+      cleared_cards_->push_back(card);
+    }
+  }
+ private:
+  std::vector<byte*>* const cleared_cards_;
+};
+
+class ModUnionScanImageRootVisitor {
+ public:
+  ModUnionScanImageRootVisitor(collector::MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
+  }
+
+  void operator ()(const Object* root) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(root != NULL);
+    mark_sweep_->ScanRoot(root);
+  }
+
+ private:
+  collector::MarkSweep* const mark_sweep_;
+};
+
+void ModUnionTableReferenceCache::ClearCards(space::ContinuousSpace* space) {
+  CardTable* card_table = GetHeap()->GetCardTable();
+  ModUnionClearCardSetVisitor visitor(&cleared_cards_);
+  // Clear dirty cards in the this space and update the corresponding mod-union bits.
+  card_table->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), visitor);
+}
+
+class AddToReferenceArrayVisitor {
+ public:
+  explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
+                                      std::vector<const mirror::Object*>* references)
+    : mod_union_table_(mod_union_table),
+      references_(references) {
+  }
+
+  // Extra parameters are required since we use this same visitor signature for checking objects.
+  void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
+                     bool /* is_static */) const {
+    // Only add the reference if it is non null and fits our criteria.
+    if (ref != NULL && mod_union_table_->AddReference(obj, ref)) {
+      references_->push_back(ref);
+    }
+  }
+
+ private:
+  ModUnionTableReferenceCache* const mod_union_table_;
+  std::vector<const mirror::Object*>* const references_;
+};
+
+class ModUnionReferenceVisitor {
+ public:
+  explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
+                                    std::vector<const mirror::Object*>* references)
+    : mod_union_table_(mod_union_table),
+      references_(references) {
+  }
+
+  void operator ()(const Object* obj) const
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
+    DCHECK(obj != NULL);
+    // We don't have an early exit since we use the visitor pattern, an early
+    // exit should significantly speed this up.
+    AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
+    collector::MarkSweep::VisitObjectReferences(obj, visitor);
+  }
+ private:
+  ModUnionTableReferenceCache* const mod_union_table_;
+  std::vector<const mirror::Object*>* const references_;
+};
+
+class CheckReferenceVisitor {
+ public:
+  explicit CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
+                                 const std::set<const Object*>& references)
+    : mod_union_table_(mod_union_table),
+      references_(references) {
+  }
+
+  // Extra parameters are required since we use this same visitor signature for checking objects.
+  // TODO: Fixme when anotatalysis works with visitors.
+  void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
+                   bool /* is_static */) const
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
+    Heap* heap = mod_union_table_->GetHeap();
+    if (ref != NULL && mod_union_table_->AddReference(obj, ref) &&
+        references_.find(ref) == references_.end()) {
+      space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
+      space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
+      LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj) << ")"
+                << "References " << reinterpret_cast<const void*>(ref)
+                << "(" << PrettyTypeOf(ref) << ") without being in mod-union table";
+      LOG(INFO) << "FromSpace " << from_space->GetName() << " type " << from_space->GetGcRetentionPolicy();
+      LOG(INFO) << "ToSpace " << to_space->GetName() << " type " << to_space->GetGcRetentionPolicy();
+      mod_union_table_->GetHeap()->DumpSpaces();
+      LOG(FATAL) << "FATAL ERROR";
+    }
+  }
+
+ private:
+  ModUnionTableReferenceCache* const mod_union_table_;
+  const std::set<const Object*>& references_;
+};
+
+class ModUnionCheckReferences {
+ public:
+  explicit ModUnionCheckReferences (ModUnionTableReferenceCache* mod_union_table,
+                                    const std::set<const Object*>& references)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      : mod_union_table_(mod_union_table), references_(references) {
+  }
+
+  void operator ()(const Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
+    Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
+    DCHECK(obj != NULL);
+    CheckReferenceVisitor visitor(mod_union_table_, references_);
+    collector::MarkSweep::VisitObjectReferences(obj, visitor);
+  }
+
+ private:
+  ModUnionTableReferenceCache* const mod_union_table_;
+  const std::set<const Object*>& references_;
+};
+
+void ModUnionTableReferenceCache::Verify() {
+  // Start by checking that everything in the mod union table is marked.
+  Heap* heap = GetHeap();
+  typedef SafeMap<const byte*, std::vector<const mirror::Object*> >::const_iterator It;
+  typedef std::vector<const mirror::Object*>::const_iterator It2;
+  for (It it = references_.begin(), end = references_.end(); it != end; ++it) {
+    for (It2 it_ref = it->second.begin(), end_ref = it->second.end(); it_ref != end_ref;
+        ++it_ref ) {
+      CHECK(heap->IsLiveObjectLocked(*it_ref));
+    }
+  }
+
+  // Check the references of each clean card which is also in the mod union table.
+  CardTable* card_table = heap->GetCardTable();
+  for (It it = references_.begin(); it != references_.end(); ++it) {
+    const byte* card = &*it->first;
+    if (*card == CardTable::kCardClean) {
+      std::set<const Object*> reference_set;
+      for (It2 itr = it->second.begin(); itr != it->second.end();++itr) {
+        reference_set.insert(*itr);
+      }
+      ModUnionCheckReferences visitor(this, reference_set);
+      uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+      uintptr_t end = start + CardTable::kCardSize;
+      space::ContinuousSpace* space =
+          heap->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
+      SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+      live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+    }
+  }
+}
+
+void ModUnionTableReferenceCache::Dump(std::ostream& os) {
+  CardTable* card_table = heap_->GetCardTable();
+  typedef std::set<byte*>::const_iterator It;
+  os << "ModUnionTable cleared cards: [";
+  for (It it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
+    byte* card = *it;
+    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+    uintptr_t end = start + CardTable::kCardSize;
+    os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
+  }
+  os << "]\nModUnionTable references: [";
+  typedef SafeMap<const byte*, std::vector<const mirror::Object*> >::const_iterator It2;
+  for (It2 it = references_.begin(); it != references_.end(); ++it) {
+    const byte* card = &*it->first;
+    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+    uintptr_t end = start + CardTable::kCardSize;
+    os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
+    typedef std::vector<const mirror::Object*>::const_iterator It3;
+    for (It3 itr = it->second.begin(); itr != it->second.end();++itr) {
+      os << reinterpret_cast<const void*>(*itr) << ",";
+    }
+    os << "},";
+  }
+}
+
+void ModUnionTableReferenceCache::Update() {
+  Heap* heap = GetHeap();
+  CardTable* card_table = heap->GetCardTable();
+
+  std::vector<const mirror::Object*> cards_references;
+  ModUnionReferenceVisitor visitor(this, &cards_references);
+
+  typedef std::set<byte*>::iterator It;
+  for (It it = cleared_cards_.begin(), cc_end = cleared_cards_.end(); it != cc_end; ++it) {
+    byte* card = *it;
+    // Clear and re-compute alloc space references associated with this card.
+    cards_references.clear();
+    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+    uintptr_t end = start + CardTable::kCardSize;
+    SpaceBitmap* live_bitmap =
+        heap->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false)->GetLiveBitmap();
+    live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+
+    // Update the corresponding references for the card.
+    // TODO: C++0x auto
+    SafeMap<const byte*, std::vector<const mirror::Object*> >::iterator
+        found = references_.find(card);
+    if (found == references_.end()) {
+      if (cards_references.empty()) {
+        // No reason to add empty array.
+        continue;
+      }
+      references_.Put(card, cards_references);
+    } else {
+      found->second = cards_references;
+    }
+  }
+  cleared_cards_.clear();
+}
+
+void ModUnionTableReferenceCache::MarkReferences(collector::MarkSweep* mark_sweep) {
+  // TODO: C++0x auto
+  size_t count = 0;
+
+  typedef SafeMap<const byte*, std::vector<const mirror::Object*> >::const_iterator It;
+  for (It it = references_.begin(); it != references_.end(); ++it) {
+    typedef std::vector<const mirror::Object*>::const_iterator It2;
+    for (It2 it_ref = it->second.begin(); it_ref != it->second.end(); ++it_ref ) {
+      mark_sweep->MarkRoot(*it_ref);
+      ++count;
+    }
+  }
+  if (VLOG_IS_ON(heap)) {
+    VLOG(gc) << "Marked " << count << " references in mod union table";
+  }
+}
+
+void ModUnionTableCardCache::ClearCards(space::ContinuousSpace* space) {
+  CardTable* card_table = GetHeap()->GetCardTable();
+  ModUnionClearCardSetVisitor visitor(&cleared_cards_);
+  // Clear dirty cards in the this space and update the corresponding mod-union bits.
+  card_table->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), visitor);
+}
+
+// Mark all references to the alloc space(s).
+void ModUnionTableCardCache::MarkReferences(collector::MarkSweep* mark_sweep) {
+  CardTable* card_table = heap_->GetCardTable();
+  ModUnionScanImageRootVisitor visitor(mark_sweep);
+  typedef std::set<byte*>::const_iterator It;
+  It it = cleared_cards_.begin();
+  It cc_end = cleared_cards_.end();
+  if (it != cc_end) {
+    byte* card = *it;
+    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+    uintptr_t end = start + CardTable::kCardSize;
+    space::ContinuousSpace* cur_space =
+        heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
+    accounting::SpaceBitmap* cur_live_bitmap = cur_space->GetLiveBitmap();
+    cur_live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+    for (++it; it != cc_end; ++it) {
+      card = *it;
+      start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+      end = start + CardTable::kCardSize;
+      if (UNLIKELY(!cur_space->Contains(reinterpret_cast<Object*>(start)))) {
+        cur_space = heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
+        cur_live_bitmap = cur_space->GetLiveBitmap();
+      }
+      cur_live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
+    }
+  }
+}
+
+void ModUnionTableCardCache::Dump(std::ostream& os) {
+  CardTable* card_table = heap_->GetCardTable();
+  typedef std::set<byte*>::const_iterator It;
+  os << "ModUnionTable dirty cards: [";
+  for (It it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
+    byte* card = *it;
+    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
+    uintptr_t end = start + CardTable::kCardSize;
+    os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
+  }
+  os << "]";
+}
+
+}  // namespace accounting
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/accounting/mod_union_table.h b/src/gc/accounting/mod_union_table.h
new file mode 100644
index 0000000..5d25e05
--- /dev/null
+++ b/src/gc/accounting/mod_union_table.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_ACCOUNTING_MOD_UNION_TABLE_H_
+#define ART_SRC_GC_ACCOUNTING_MOD_UNION_TABLE_H_
+
+#include "globals.h"
+#include "safe_map.h"
+
+#include <set>
+#include <vector>
+
+namespace art {
+namespace mirror {
+  class Object;
+}  // namespace mirror
+
+namespace gc {
+
+namespace collector {
+  class MarkSweep;
+}  // namespace collector
+namespace space {
+  class ContinuousSpace;
+  class Space;
+}  // namespace space
+
+class Heap;
+
+namespace accounting {
+
+class SpaceBitmap;
+class HeapBitmap;
+
+// The mod-union table is the union of modified cards. It is used to allow the card table to be
+// cleared between GC phases, reducing the number of dirty cards that need to be scanned.
+class ModUnionTable {
+ public:
+  ModUnionTable(Heap* heap) : heap_(heap) {
+  }
+
+  virtual ~ModUnionTable() {
+  }
+
+  // Clear cards which map to a memory range of a space. This doesn't immediately update the
+  // mod-union table, as updating the mod-union table may have an associated cost, such as
+  // determining references to track.
+  virtual void ClearCards(space::ContinuousSpace* space) = 0;
+
+  // Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards
+  // before a call to update, for example, back-to-back sticky GCs.
+  virtual void Update() = 0;
+
+  // Mark the bitmaps for all references which are stored in the mod-union table.
+  virtual void MarkReferences(collector::MarkSweep* mark_sweep) = 0;
+
+  // Verification, sanity checks that we don't have clean cards which conflict with out cached data
+  // for said cards. Exclusive lock is required since verify sometimes uses
+  // SpaceBitmap::VisitMarkedRange and VisitMarkedRange can't know if the callback will modify the
+  // bitmap or not.
+  virtual void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) = 0;
+
+  virtual void Dump(std::ostream& os) = 0;
+
+  Heap* GetHeap() const {
+    return heap_;
+  }
+
+ protected:
+  Heap* const heap_;
+};
+
+// Reference caching implementation. Caches references pointing to alloc space(s) for each card.
+class ModUnionTableReferenceCache : public ModUnionTable {
+ public:
+  ModUnionTableReferenceCache(Heap* heap) : ModUnionTable(heap) {}
+  virtual ~ModUnionTableReferenceCache() {}
+
+  // Clear and store cards for a space.
+  void ClearCards(space::ContinuousSpace* space);
+
+  // Update table based on cleared cards.
+  void Update()
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Mark all references to the alloc space(s).
+  void MarkReferences(collector::MarkSweep* mark_sweep)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  // Exclusive lock is required since verify uses SpaceBitmap::VisitMarkedRange and
+  // VisitMarkedRange can't know if the callback will modify the bitmap or not.
+  void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  // Function that tells whether or not to add a reference to the table.
+  virtual bool AddReference(const mirror::Object* obj, const mirror::Object* ref) = 0;
+
+  void Dump(std::ostream& os);
+
+ protected:
+  // Cleared card array, used to update the mod-union table.
+  std::set<byte*> cleared_cards_;
+
+  // Maps from dirty cards to their corresponding alloc space references.
+  SafeMap<const byte*, std::vector<const mirror::Object*> > references_;
+};
+
+// Card caching implementation. Keeps track of which cards we cleared and only this information.
+class ModUnionTableCardCache : public ModUnionTable {
+ public:
+  ModUnionTableCardCache(Heap* heap) : ModUnionTable(heap) {}
+  virtual ~ModUnionTableCardCache() {}
+
+  // Clear and store cards for a space.
+  void ClearCards(space::ContinuousSpace* space);
+
+  // Nothing to update as all dirty cards were placed into cleared cards during clearing.
+  void Update() {}
+
+  // Mark all references to the alloc space(s).
+  void MarkReferences(collector::MarkSweep* mark_sweep)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Nothing to verify.
+  void Verify() {}
+
+  void Dump(std::ostream& os);
+
+ protected:
+  // Cleared card array, used to update the mod-union table.
+  std::set<byte*> cleared_cards_;
+};
+
+}  // namespace accounting
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_ACCOUNTING_MOD_UNION_TABLE_H_
diff --git a/src/gc/space_bitmap-inl.h b/src/gc/accounting/space_bitmap-inl.h
similarity index 94%
rename from src/gc/space_bitmap-inl.h
rename to src/gc/accounting/space_bitmap-inl.h
index dd91403..a4fd330 100644
--- a/src/gc/space_bitmap-inl.h
+++ b/src/gc/accounting/space_bitmap-inl.h
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_GC_SPACE_BITMAP_INL_H_
-#define ART_SRC_GC_SPACE_BITMAP_INL_H_
+#ifndef ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_INL_H_
+#define ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_INL_H_
 
 #include "base/logging.h"
 #include "cutils/atomic-inline.h"
+#include "utils.h"
 
 namespace art {
+namespace gc {
+namespace accounting {
 
 inline bool SpaceBitmap::AtomicTestAndSet(const mirror::Object* obj) {
   uintptr_t addr = reinterpret_cast<uintptr_t>(obj);
@@ -136,6 +139,9 @@
   }
   return (old_word & mask) != 0;
 }
+
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
 
-#endif  // ART_SRC_GC_SPACE_BITMAP_INL_H_
+#endif  // ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_INL_H_
diff --git a/src/gc/space_bitmap.cc b/src/gc/accounting/space_bitmap.cc
similarity index 96%
rename from src/gc/space_bitmap.cc
rename to src/gc/accounting/space_bitmap.cc
index 773aa1e..19f1128 100644
--- a/src/gc/space_bitmap.cc
+++ b/src/gc/accounting/space_bitmap.cc
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-#include "heap_bitmap.h"
-
 #include "base/logging.h"
 #include "dex_file-inl.h"
+#include "heap_bitmap.h"
 #include "mirror/class-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
+#include "object_utils.h"
 #include "space_bitmap-inl.h"
 #include "UniquePtr.h"
 #include "utils.h"
 
 namespace art {
+namespace gc {
+namespace accounting {
 
 std::string SpaceBitmap::GetName() const {
   return name_;
@@ -36,6 +38,12 @@
   name_ = name;
 }
 
+std::string SpaceBitmap::Dump() const {
+  return StringPrintf("%s: %p-%p", name_.c_str(),
+                      reinterpret_cast<void*>(HeapBegin()),
+                      reinterpret_cast<void*>(HeapLimit()));
+}
+
 void SpaceSetMap::Walk(SpaceBitmap::Callback* callback, void* arg) {
   for (Objects::iterator it = contained_.begin(); it != contained_.end(); ++it) {
     callback(const_cast<mirror::Object*>(*it), arg);
@@ -72,8 +80,6 @@
   // mem_map_->Trim(reinterpret_cast<byte*>(heap_begin_ + bitmap_size_));
 }
 
-// Fill the bitmap with zeroes.  Returns the bitmap's memory to the
-// system as a side-effect.
 void SpaceBitmap::Clear() {
   if (bitmap_begin_ != NULL) {
     // This returns the memory to the system.  Successive page faults
@@ -164,14 +170,6 @@
   }
 }
 
-}  // namespace art
-
-// Support needed for in order traversal
-#include "mirror/object.h"
-#include "object_utils.h"
-
-namespace art {
-
 static void WalkFieldsInOrder(SpaceBitmap* visited, SpaceBitmap::Callback* callback, mirror::Object* obj,
                               void* arg);
 
@@ -273,10 +271,6 @@
   name_ = name;
 }
 
-SpaceSetMap::SpaceSetMap(const std::string& name) : name_(name) {
-
-}
-
 void SpaceSetMap::CopyFrom(const SpaceSetMap& space_set) {
   contained_ = space_set.contained_;
 }
@@ -287,6 +281,8 @@
     << "begin=" << reinterpret_cast<const void*>(bitmap.HeapBegin())
     << ",end=" << reinterpret_cast<const void*>(bitmap.HeapLimit())
     << "]";
-  }
+}
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/space_bitmap.h b/src/gc/accounting/space_bitmap.h
similarity index 92%
rename from src/gc/space_bitmap.h
rename to src/gc/accounting/space_bitmap.h
index 6bc06d6..bb487d8 100644
--- a/src/gc/space_bitmap.h
+++ b/src/gc/accounting/space_bitmap.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_GC_SPACE_BITMAP_H_
-#define ART_SRC_GC_SPACE_BITMAP_H_
+#ifndef ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_H_
+#define ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_H_
 
 #include "locks.h"
 #include "globals.h"
@@ -28,12 +28,17 @@
 #include <vector>
 
 namespace art {
+
 namespace mirror {
-class Object;
+  class Object;
 }  // namespace mirror
 
+namespace gc {
+namespace accounting {
+
 class SpaceBitmap {
  public:
+  // Alignment of objects within spaces.
   static const size_t kAlignment = 8;
 
   typedef void Callback(mirror::Object* obj, void* arg);
@@ -52,7 +57,7 @@
   // <index> is the index of .bits that contains the bit representing
   //         <offset>.
   static size_t OffsetToIndex(size_t offset) {
-      return offset / kAlignment / kBitsPerWord;
+    return offset / kAlignment / kBitsPerWord;
   }
 
   static uintptr_t IndexToOffset(size_t index) {
@@ -75,6 +80,7 @@
   // Returns true if the object was previously marked.
   bool AtomicTestAndSet(const mirror::Object* obj);
 
+  // Fill the bitmap with zeroes.  Returns the bitmap's memory to the system as a side-effect.
   void Clear();
 
   bool Test(const mirror::Object* obj) const;
@@ -160,6 +166,8 @@
   std::string GetName() const;
   void SetName(const std::string& name);
 
+  std::string Dump() const;
+
   const void* GetObjectWordAddress(const mirror::Object* obj) const {
     uintptr_t addr = reinterpret_cast<uintptr_t>(obj);
     const uintptr_t offset = addr - heap_begin_;
@@ -236,7 +244,8 @@
     }
   }
 
-  SpaceSetMap(const std::string& name);
+  SpaceSetMap(const std::string& name) : name_(name) {}
+  ~SpaceSetMap() {}
 
   Objects& GetObjects() {
     return contained_;
@@ -249,6 +258,8 @@
 
 std::ostream& operator << (std::ostream& stream, const SpaceBitmap& bitmap);
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
 
-#endif  // ART_SRC_GC_SPACE_BITMAP_H_
+#endif  // ART_SRC_GC_ACCOUNTING_SPACE_BITMAP_H_
diff --git a/src/gc/space_bitmap_test.cc b/src/gc/accounting/space_bitmap_test.cc
similarity index 96%
rename from src/gc/space_bitmap_test.cc
rename to src/gc/accounting/space_bitmap_test.cc
index 4645659..d00d7c2 100644
--- a/src/gc/space_bitmap_test.cc
+++ b/src/gc/accounting/space_bitmap_test.cc
@@ -17,7 +17,6 @@
 #include "space_bitmap.h"
 
 #include "common_test.h"
-#include "dlmalloc.h"
 #include "globals.h"
 #include "space_bitmap-inl.h"
 #include "UniquePtr.h"
@@ -25,6 +24,8 @@
 #include <stdint.h>
 
 namespace art {
+namespace gc {
+namespace accounting {
 
 class SpaceBitmapTest : public CommonTest {
  public:
@@ -87,4 +88,6 @@
   }
 }
 
+}  // namespace accounting
+}  // namespace gc
 }  // namespace art
diff --git a/src/dlmalloc.cc b/src/gc/allocator/dlmalloc.cc
similarity index 68%
rename from src/dlmalloc.cc
rename to src/gc/allocator/dlmalloc.cc
index 1d62d20..7584b6e 100644
--- a/src/dlmalloc.cc
+++ b/src/gc/allocator/dlmalloc.cc
@@ -45,3 +45,28 @@
 static void art_heap_usage_error(const char* function, void* p) {
   LOG(FATAL) << "Incorrect use of function '" << function << "' argument " << p << " not expected";
 }
+
+#include "globals.h"
+#include "utils.h"
+#include <sys/mman.h>
+
+using namespace art;
+extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) {
+  // Is this chunk in use?
+  if (used_bytes != 0) {
+    return;
+  }
+  // Do we have any whole pages to give back?
+  start = reinterpret_cast<void*>(RoundUp(reinterpret_cast<uintptr_t>(start), kPageSize));
+  end = reinterpret_cast<void*>(RoundDown(reinterpret_cast<uintptr_t>(end), kPageSize));
+  if (end > start) {
+    size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
+    int rc = madvise(start, length, MADV_DONTNEED);
+    if (UNLIKELY(rc != 0)) {
+      errno = rc;
+      PLOG(FATAL) << "madvise failed during heap trimming";
+    }
+    size_t* reclaimed = reinterpret_cast<size_t*>(arg);
+    *reclaimed += length;
+  }
+}
diff --git a/src/dlmalloc.h b/src/gc/allocator/dlmalloc.h
similarity index 76%
rename from src/dlmalloc.h
rename to src/gc/allocator/dlmalloc.h
index b6759a0..6b02a44 100644
--- a/src/dlmalloc.h
+++ b/src/gc/allocator/dlmalloc.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_DLMALLOC_H_
-#define ART_SRC_DLMALLOC_H_
+#ifndef ART_SRC_GC_ALLOCATOR_DLMALLOC_H_
+#define ART_SRC_GC_ALLOCATOR_DLMALLOC_H_
 
 // Configure dlmalloc for mspaces.
 #define HAVE_MMAP 0
@@ -33,4 +33,8 @@
 extern "C" void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), void* arg);
 extern "C" int  dlmalloc_trim(size_t);
 
-#endif  // ART_SRC_DLMALLOC_H_
+// Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
+// pages back to the kernel.
+extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/);
+
+#endif  // ART_SRC_GC_ALLOCATOR_DLMALLOC_H_
diff --git a/src/gc/collector/garbage_collector.cc b/src/gc/collector/garbage_collector.cc
new file mode 100644
index 0000000..7412835
--- /dev/null
+++ b/src/gc/collector/garbage_collector.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "garbage_collector.h"
+
+#include "base/logging.h"
+#include "base/mutex-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
+#include "thread.h"
+#include "thread_list.h"
+
+namespace art {
+namespace gc {
+namespace collector {
+
+GarbageCollector::GarbageCollector(Heap* heap, const std::string& name)
+    : heap_(heap),
+      name_(name),
+      verbose_(VLOG_IS_ON(heap)),
+      duration_ns_(0),
+      timings_(name_.c_str(), true, verbose_),
+      cumulative_timings_(name) {
+  ResetCumulativeStatistics();
+}
+
+bool GarbageCollector::HandleDirtyObjectsPhase() {
+  DCHECK(IsConcurrent());
+  return true;
+}
+
+void GarbageCollector::RegisterPause(uint64_t nano_length) {
+  pause_times_.push_back(nano_length);
+}
+
+void GarbageCollector::ResetCumulativeStatistics() {
+  cumulative_timings_.Reset();
+  total_time_ns_ = 0;
+  total_paused_time_ns_ = 0;
+  total_freed_objects_ = 0;
+  total_freed_bytes_ = 0;
+}
+
+void GarbageCollector::Run() {
+  Thread* self = Thread::Current();
+  ThreadList* thread_list = Runtime::Current()->GetThreadList();
+
+  uint64_t start_time = NanoTime();
+  pause_times_.clear();
+  duration_ns_ = 0;
+
+  InitializePhase();
+
+  if (!IsConcurrent()) {
+    // Pause is the entire length of the GC.
+    uint64_t pause_start = NanoTime();
+    thread_list->SuspendAll();
+    MarkingPhase();
+    ReclaimPhase();
+    thread_list->ResumeAll();
+    uint64_t pause_end = NanoTime();
+    pause_times_.push_back(pause_end - pause_start);
+  } else {
+    {
+      ReaderMutexLock mu(self, *Locks::mutator_lock_);
+      MarkingPhase();
+    }
+    bool done = false;
+    while (!done) {
+      uint64_t pause_start = NanoTime();
+      thread_list->SuspendAll();
+      done = HandleDirtyObjectsPhase();
+      thread_list->ResumeAll();
+      uint64_t pause_end = NanoTime();
+      pause_times_.push_back(pause_end - pause_start);
+    }
+    {
+      ReaderMutexLock mu(self, *Locks::mutator_lock_);
+      ReclaimPhase();
+    }
+  }
+
+  uint64_t end_time = NanoTime();
+  duration_ns_ = end_time - start_time;
+
+  FinishPhase();
+}
+
+void GarbageCollector::SwapBitmaps() {
+  // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps
+  // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live
+  // bits of dead objects in the live bitmap.
+  const GcType gc_type = GetGcType();
+  const std::vector<space::ContinuousSpace*>& cont_spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = cont_spaces.begin(), end = cont_spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    // We never allocate into zygote spaces.
+    if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect ||
+        (gc_type == kGcTypeFull &&
+         space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) {
+      accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+      accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+      if (live_bitmap != mark_bitmap) {
+        heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap);
+        heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
+        space->AsDlMallocSpace()->SwapBitmaps();
+      }
+    }
+  }
+  const std::vector<space::DiscontinuousSpace*>& disc_spaces = GetHeap()->GetDiscontinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::DiscontinuousSpace*>::const_iterator It2;
+  for (It2 it = disc_spaces.begin(), end = disc_spaces.end(); it != end; ++it) {
+    space::LargeObjectSpace* space = down_cast<space::LargeObjectSpace*>(*it);
+    accounting::SpaceSetMap* live_set = space->GetLiveObjects();
+    accounting::SpaceSetMap* mark_set = space->GetMarkObjects();
+    heap_->GetLiveBitmap()->ReplaceObjectSet(live_set, mark_set);
+    heap_->GetMarkBitmap()->ReplaceObjectSet(mark_set, live_set);
+    space->SwapBitmaps();
+  }
+}
+
+}  // namespace collector
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/garbage_collector.h b/src/gc/collector/garbage_collector.h
similarity index 61%
rename from src/gc/garbage_collector.h
rename to src/gc/collector/garbage_collector.h
index a1014c2..1ab3957 100644
--- a/src/gc/garbage_collector.h
+++ b/src/gc/collector/garbage_collector.h
@@ -17,28 +17,38 @@
 #ifndef ART_SRC_GC_GARBAGE_COLLECTOR_H_
 #define ART_SRC_GC_GARBAGE_COLLECTOR_H_
 
+#include "gc_type.h"
 #include "locks.h"
+#include "base/timing_logger.h"
 
 #include <stdint.h>
 #include <vector>
 
 namespace art {
+namespace gc {
 
 class Heap;
 
+namespace collector {
+
 class GarbageCollector {
  public:
   // Returns true iff the garbage collector is concurrent.
   virtual bool IsConcurrent() const = 0;
 
-  GarbageCollector(Heap* heap);
+  GarbageCollector(Heap* heap, const std::string& name);
+  virtual ~GarbageCollector() { }
 
-  virtual ~GarbageCollector();
+  const char* GetName() const {
+    return name_.c_str();
+  }
+
+  virtual GcType GetGcType() const = 0;
 
   // Run the garbage collector.
   void Run();
 
-  Heap* GetHeap() {
+  Heap* GetHeap() const {
     return heap_;
   }
 
@@ -48,16 +58,28 @@
   }
 
   // Returns how long the GC took to complete in nanoseconds.
-  uint64_t GetDuration() const {
-    return duration_;
+  uint64_t GetDurationNs() const {
+    return duration_ns_;
   }
 
-
-  virtual std::string GetName() const = 0;
-
   void RegisterPause(uint64_t nano_length);
 
+  base::NewTimingLogger& GetTimings() {
+    return timings_;
+  }
+
+  CumulativeLogger& GetCumulativeTimings() {
+    return cumulative_timings_;
+  }
+
+  void ResetCumulativeStatistics();
+
+  // Swap the live and mark bitmaps of spaces that are active for the collector. For partial GC,
+  // this is the allocation space, for full GC then we swap the zygote bitmaps too.
+  void SwapBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
  protected:
+
   // The initial phase. Done without mutators paused.
   virtual void InitializePhase() = 0;
 
@@ -73,11 +95,28 @@
   // Called after the GC is finished. Done without mutators paused.
   virtual void FinishPhase() = 0;
 
-  Heap* heap_;
+  Heap* const heap_;
+
+  std::string name_;
+
+  const bool verbose_;
+
+  uint64_t duration_ns_;
+  base::NewTimingLogger timings_;
+
+  // Cumulative statistics.
+  uint64_t total_time_ns_;
+  uint64_t total_paused_time_ns_;
+  uint64_t total_freed_objects_;
+  uint64_t total_freed_bytes_;
+
+  CumulativeLogger cumulative_timings_;
+
   std::vector<uint64_t> pause_times_;
-  uint64_t duration_;
 };
 
+}  // namespace collector
+}  // namespace gc
 }  // namespace art
 
 #endif  // ART_SRC_GC_GARBAGE_COLLECTOR_H_
diff --git a/src/gc/collector/gc_type.cc b/src/gc/collector/gc_type.cc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/gc/collector/gc_type.cc
diff --git a/src/gc/collector/gc_type.h b/src/gc/collector/gc_type.h
new file mode 100644
index 0000000..bb25bb9
--- /dev/null
+++ b/src/gc/collector/gc_type.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_COLLECTOR_GC_TYPE_H_
+#define ART_SRC_GC_COLLECTOR_GC_TYPE_H_
+
+#include <ostream>
+
+namespace art {
+namespace gc {
+namespace collector {
+
+// The type of collection to be performed. The ordering of the enum matters, it is used to
+// determine which GCs are run first.
+enum GcType {
+  // Placeholder for when no GC has been performed.
+  kGcTypeNone,
+  // Sticky mark bits GC that attempts to only free objects allocated since the last GC.
+  kGcTypeSticky,
+  // Partial GC that marks the application heap but not the Zygote.
+  kGcTypePartial,
+  // Full GC that marks and frees in both the application and Zygote heap.
+  kGcTypeFull,
+  // Number of different GC types.
+  kGcTypeMax,
+};
+std::ostream& operator<<(std::ostream& os, const GcType& policy);
+
+}  // namespace collector
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_COLLECTOR_GC_TYPE_H_
diff --git a/src/gc/mark_sweep-inl.h b/src/gc/collector/mark_sweep-inl.h
similarity index 97%
rename from src/gc/mark_sweep-inl.h
rename to src/gc/collector/mark_sweep-inl.h
index 7265023..ea9fced 100644
--- a/src/gc/mark_sweep-inl.h
+++ b/src/gc/collector/mark_sweep-inl.h
@@ -17,12 +17,16 @@
 #ifndef ART_SRC_GC_MARK_SWEEP_INL_H_
 #define ART_SRC_GC_MARK_SWEEP_INL_H_
 
-#include "heap.h"
+#include "gc/collector/mark_sweep.h"
+
+#include "gc/heap.h"
 #include "mirror/class.h"
 #include "mirror/field.h"
 #include "mirror/object_array.h"
 
 namespace art {
+namespace gc {
+namespace collector {
 
 template <typename MarkVisitor>
 inline void MarkSweep::ScanObjectVisit(const mirror::Object* obj, const MarkVisitor& visitor) {
@@ -154,6 +158,8 @@
   }
 }
 
+}  // namespace collector
+}  // namespace gc
 }  // namespace art
 
 #endif  // ART_SRC_GC_MARK_SWEEP_INL_H_
diff --git a/src/gc/mark_sweep.cc b/src/gc/collector/mark_sweep.cc
similarity index 76%
rename from src/gc/mark_sweep.cc
rename to src/gc/collector/mark_sweep.cc
index 25b4b78..d54fec6 100644
--- a/src/gc/mark_sweep.cc
+++ b/src/gc/collector/mark_sweep.cc
@@ -25,13 +25,16 @@
 #include "base/macros.h"
 #include "base/mutex-inl.h"
 #include "base/timing_logger.h"
-#include "card_table.h"
-#include "card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/accounting/space_bitmap-inl.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
 #include "indirect_reference_table.h"
 #include "intern_table.h"
 #include "jni_internal.h"
-#include "large_object_space.h"
 #include "monitor.h"
 #include "mark_sweep-inl.h"
 #include "mirror/class-inl.h"
@@ -43,15 +46,15 @@
 #include "mirror/object_array.h"
 #include "mirror/object_array-inl.h"
 #include "runtime.h"
-#include "space.h"
-#include "space_bitmap-inl.h"
-#include "thread.h"
+#include "thread-inl.h"
 #include "thread_list.h"
 #include "verifier/method_verifier.h"
 
 using namespace art::mirror;
 
 namespace art {
+namespace gc {
+namespace collector {
 
 // Performance options.
 static const bool kParallelMarkStack = true;
@@ -68,7 +71,6 @@
 class SetFingerVisitor {
  public:
   SetFingerVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
-
   }
 
   void operator ()(void* finger) const {
@@ -79,13 +81,7 @@
   MarkSweep* const mark_sweep_;
 };
 
-std::string MarkSweep::GetName() const {
-  std::ostringstream ss;
-  ss << (IsConcurrent() ? "Concurrent" : "") << GetGcType();
-  return ss.str();
-}
-
-void MarkSweep::ImmuneSpace(ContinuousSpace* space) {
+void MarkSweep::ImmuneSpace(space::ContinuousSpace* space) {
   // Bind live to mark bitmap if necessary.
   if (space->GetLiveBitmap() != space->GetMarkBitmap()) {
     BindLiveToMarkBitmap(space);
@@ -97,54 +93,68 @@
     SetImmuneRange(reinterpret_cast<Object*>(space->Begin()),
                    reinterpret_cast<Object*>(space->End()));
   } else {
-      const Spaces& spaces = GetHeap()->GetSpaces();
-      const ContinuousSpace* prev_space = NULL;
-      // Find out if the previous space is immune.
-      // TODO: C++0x
-      for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-        if (*it == space) {
-          break;
-        }
-        prev_space = *it;
+    const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+    const space::ContinuousSpace* prev_space = NULL;
+    // Find out if the previous space is immune.
+    // TODO: C++0x
+    typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+    for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+      if (*it == space) {
+        break;
       }
+      prev_space = *it;
+    }
 
-      // If previous space was immune, then extend the immune region.
-      if (prev_space != NULL &&
-          immune_begin_ <= reinterpret_cast<Object*>(prev_space->Begin()) &&
-          immune_end_ >= reinterpret_cast<Object*>(prev_space->End())) {
+    // If previous space was immune, then extend the immune region. Relies on continuous spaces
+    // being sorted by Heap::AddContinuousSpace.
+    if (prev_space != NULL &&
+        immune_begin_ <= reinterpret_cast<Object*>(prev_space->Begin()) &&
+        immune_end_ >= reinterpret_cast<Object*>(prev_space->End())) {
       immune_begin_ = std::min(reinterpret_cast<Object*>(space->Begin()), immune_begin_);
       immune_end_ = std::max(reinterpret_cast<Object*>(space->End()), immune_end_);
     }
   }
 }
 
-// Bind the live bits to the mark bits of bitmaps based on the gc type.
 void MarkSweep::BindBitmaps() {
-  Spaces& spaces = GetHeap()->GetSpaces();
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
 
   // Mark all of the spaces we never collect as immune.
-  for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
-    if (space->GetGcRetentionPolicy() == kGcRetentionPolicyNeverCollect) {
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect) {
       ImmuneSpace(space);
     }
   }
 }
 
-MarkSweep::MarkSweep(Heap* heap, bool is_concurrent)
-    : GarbageCollector(heap),
+MarkSweep::MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
+    : GarbageCollector(heap,
+                       name_prefix + (name_prefix.empty() ? "" : " ") +
+                       (is_concurrent ? "concurrent mark sweep": "mark sweep")),
+      current_mark_bitmap_(NULL),
+      java_lang_Class_(NULL),
+      mark_stack_(NULL),
+      finger_(NULL),
+      immune_begin_(NULL),
+      immune_end_(NULL),
+      soft_reference_list_(NULL),
+      weak_reference_list_(NULL),
+      finalizer_reference_list_(NULL),
+      phantom_reference_list_(NULL),
+      cleared_reference_list_(NULL),
       gc_barrier_(new Barrier(0)),
       large_object_lock_("mark sweep large object lock", kMarkSweepLargeObjectLock),
       mark_stack_expand_lock_("mark sweep mark stack expand lock"),
       is_concurrent_(is_concurrent),
-      timings_(GetName(), true),
-      cumulative_timings_(GetName()) {
-  cumulative_timings_.SetName(GetName());
-  ResetCumulativeStatistics();
+      clear_soft_references_(false) {
 }
 
 void MarkSweep::InitializePhase() {
+  timings_.Reset();
+  timings_.StartSplit("InitializePhase");
   mark_stack_ = GetHeap()->mark_stack_.get();
   DCHECK(mark_stack_ != NULL);
   finger_ = NULL;
@@ -169,34 +179,31 @@
   java_lang_Class_ = Class::GetJavaLangClass();
   CHECK(java_lang_Class_ != NULL);
   FindDefaultMarkBitmap();
-  // Mark any concurrent roots as dirty since we need to scan them at least once during this GC.
-  Runtime::Current()->DirtyRoots();
-  timings_.Reset();
   // Do any pre GC verification.
   heap_->PreGcVerification(this);
 }
 
 void MarkSweep::ProcessReferences(Thread* self) {
+  timings_.NewSplit("ProcessReferences");
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   ProcessReferences(&soft_reference_list_, clear_soft_references_, &weak_reference_list_,
                     &finalizer_reference_list_, &phantom_reference_list_);
-  timings_.AddSplit("ProcessReferences");
 }
 
 bool MarkSweep::HandleDirtyObjectsPhase() {
   Thread* self = Thread::Current();
-  ObjectStack* allocation_stack = GetHeap()->allocation_stack_.get();
+  accounting::ObjectStack* allocation_stack = GetHeap()->allocation_stack_.get();
   Locks::mutator_lock_->AssertExclusiveHeld(self);
 
   {
+    timings_.NewSplit("ReMarkRoots");
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
 
     // Re-mark root set.
     ReMarkRoots();
-    timings_.AddSplit("ReMarkRoots");
 
     // Scan dirty objects, this is only required if we are not doing concurrent GC.
-    RecursiveMarkDirtyObjects(CardTable::kCardDirty);
+    RecursiveMarkDirtyObjects(accounting::CardTable::kCardDirty);
   }
 
   ProcessReferences(self);
@@ -206,15 +213,17 @@
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
     // This second sweep makes sure that we don't have any objects in the live stack which point to
     // freed objects. These cause problems since their references may be previously freed objects.
-    SweepArray(timings_, allocation_stack, false);
+    SweepArray(allocation_stack, false);
   } else {
+    timings_.NewSplit("UnMarkAllocStack");
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    // We only sweep over the live stack, and the live stack should not intersect with the
-    // allocation stack, so it should be safe to UnMark anything in the allocation stack as live.
+    // The allocation stack contains things allocated since the start of the GC. These may have been
+    // marked during this GC meaning they won't be eligible for reclaiming in the next sticky GC.
+    // Remove these objects from the mark bitmaps so that they will be eligible for sticky
+    // collection.
     heap_->UnMarkAllocStack(GetHeap()->alloc_space_->GetMarkBitmap(),
-                           GetHeap()->large_object_space_->GetMarkObjects(),
-                           allocation_stack);
-    timings_.AddSplit("UnMarkAllocStack");
+                            GetHeap()->large_object_space_->GetMarkObjects(),
+                            allocation_stack);
   }
   return true;
 }
@@ -227,31 +236,30 @@
   Heap* heap = GetHeap();
   Thread* self = Thread::Current();
 
+  timings_.NewSplit("BindBitmaps");
   BindBitmaps();
   FindDefaultMarkBitmap();
-  timings_.AddSplit("BindBitmaps");
-
   // Process dirty cards and add dirty cards to mod union tables.
   heap->ProcessCards(timings_);
 
   // Need to do this before the checkpoint since we don't want any threads to add references to
   // the live stack during the recursive mark.
+  timings_.NewSplit("SwapStacks");
   heap->SwapStacks();
-  timings_.AddSplit("SwapStacks");
 
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
     // If we exclusively hold the mutator lock, all threads must be suspended.
+    timings_.NewSplit("MarkRoots");
     MarkRoots();
-    timings_.AddSplit("MarkConcurrentRoots");
   } else {
-    MarkRootsCheckpoint();
-    timings_.AddSplit("MarkRootsCheckpoint");
+    timings_.NewSplit("MarkRootsCheckpoint");
+    MarkRootsCheckpoint(self);
+    timings_.NewSplit("MarkNonThreadRoots");
     MarkNonThreadRoots();
-    timings_.AddSplit("MarkNonThreadRoots");
   }
+  timings_.NewSplit("MarkConcurrentRoots");
   MarkConcurrentRoots();
-  timings_.AddSplit("MarkConcurrentRoots");
 
   heap->UpdateAndMarkModUnion(this, timings_, GetGcType());
   MarkReachableObjects();
@@ -260,12 +268,12 @@
 void MarkSweep::MarkReachableObjects() {
   // Mark everything allocated since the last as GC live so that we can sweep concurrently,
   // knowing that new allocations won't be marked as live.
-  ObjectStack* live_stack = heap_->GetLiveStack();
+  timings_.NewSplit("MarkStackAsLive");
+  accounting::ObjectStack* live_stack = heap_->GetLiveStack();
   heap_->MarkAllocStack(heap_->alloc_space_->GetLiveBitmap(),
                        heap_->large_object_space_->GetLiveObjects(),
                        live_stack);
   live_stack->Reset();
-  timings_.AddSplit("MarkStackAsLive");
   // Recursively mark all the non-image bits set in the mark bitmap.
   RecursiveMark();
   DisableFinger();
@@ -289,60 +297,31 @@
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
 
     // Reclaim unmarked objects.
-    Sweep(timings_, false);
+    Sweep(false);
 
     // Swap the live and mark bitmaps for each space which we modified space. This is an
     // optimization that enables us to not clear live bits inside of the sweep. Only swaps unbound
     // bitmaps.
+    timings_.NewSplit("SwapBitmaps");
     SwapBitmaps();
-    timings_.AddSplit("SwapBitmaps");
 
     // Unbind the live and mark bitmaps.
     UnBindBitmaps();
   }
 }
 
-void MarkSweep::SwapBitmaps() {
-  // Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps
-  // these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live
-  // bits of dead objects in the live bitmap.
-  const GcType gc_type = GetGcType();
-  // TODO: C++0x
-  Spaces& spaces = heap_->GetSpaces();
-  for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
-    // We never allocate into zygote spaces.
-    if (space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect ||
-        (gc_type == kGcTypeFull &&
-            space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect)) {
-      SpaceBitmap* live_bitmap = space->GetLiveBitmap();
-      SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
-      if (live_bitmap != mark_bitmap) {
-        heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap);
-        heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
-        space->AsAllocSpace()->SwapBitmaps();
-      }
-    }
-  }
-  SwapLargeObjects();
-}
-
-void MarkSweep::SwapLargeObjects() {
-  LargeObjectSpace* large_object_space = heap_->GetLargeObjectsSpace();
-  large_object_space->SwapBitmaps();
-  heap_->GetLiveBitmap()->SetLargeObjects(large_object_space->GetLiveObjects());
-  heap_->GetMarkBitmap()->SetLargeObjects(large_object_space->GetMarkObjects());
-}
-
 void MarkSweep::SetImmuneRange(Object* begin, Object* end) {
   immune_begin_ = begin;
   immune_end_ = end;
 }
 
 void MarkSweep::FindDefaultMarkBitmap() {
-  const Spaces& spaces = heap_->GetSpaces();
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    if ((*it)->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) {
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) {
       current_mark_bitmap_ = (*it)->GetMarkBitmap();
       CHECK(current_mark_bitmap_ != NULL);
       return;
@@ -389,10 +368,10 @@
 
   // Try to take advantage of locality of references within a space, failing this find the space
   // the hard way.
-  SpaceBitmap* object_bitmap = current_mark_bitmap_;
+  accounting::SpaceBitmap* object_bitmap = current_mark_bitmap_;
   if (UNLIKELY(!object_bitmap->HasAddress(obj))) {
-    SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetSpaceBitmap(obj);
-    if (new_bitmap != NULL) {
+    accounting::SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetContinuousSpaceBitmap(obj);
+    if (LIKELY(new_bitmap != NULL)) {
       object_bitmap = new_bitmap;
     } else {
       MarkLargeObject(obj);
@@ -416,13 +395,16 @@
 
 // Rare case, probably not worth inlining since it will increase instruction cache miss rate.
 bool MarkSweep::MarkLargeObject(const Object* obj) {
-  LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
-  SpaceSetMap* large_objects = large_object_space->GetMarkObjects();
+  // TODO: support >1 discontinuous space.
+  space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+  accounting::SpaceSetMap* large_objects = large_object_space->GetMarkObjects();
   if (kProfileLargeObjects) {
     ++large_object_test_;
   }
   if (UNLIKELY(!large_objects->Test(obj))) {
-    if (!large_object_space->Contains(obj)) {
+    // TODO: mark may be called holding the JNI global references lock, Contains will hold the
+    // large object space lock causing a lock level violation. Bug: 9414652;
+    if (!kDebugLocking && !large_object_space->Contains(obj)) {
       LOG(ERROR) << "Tried to mark " << obj << " not contained by any spaces";
       LOG(ERROR) << "Attempting see if it's a bad root";
       VerifyRoots();
@@ -448,9 +430,9 @@
 
   // Try to take advantage of locality of references within a space, failing this find the space
   // the hard way.
-  SpaceBitmap* object_bitmap = current_mark_bitmap_;
+  accounting::SpaceBitmap* object_bitmap = current_mark_bitmap_;
   if (UNLIKELY(!object_bitmap->HasAddress(obj))) {
-    SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetSpaceBitmap(obj);
+    accounting::SpaceBitmap* new_bitmap = heap_->GetMarkBitmap()->GetContinuousSpaceBitmap(obj);
     if (new_bitmap != NULL) {
       object_bitmap = new_bitmap;
     } else {
@@ -510,8 +492,8 @@
 
 void MarkSweep::VerifyRoot(const Object* root, size_t vreg, const StackVisitor* visitor) {
   // See if the root is on any space bitmap.
-  if (GetHeap()->GetLiveBitmap()->GetSpaceBitmap(root) == NULL) {
-    LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+  if (GetHeap()->GetLiveBitmap()->GetContinuousSpaceBitmap(root) == NULL) {
+    space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
     if (!large_object_space->Contains(root)) {
       LOG(ERROR) << "Found invalid root: " << root;
       if (visitor != NULL) {
@@ -535,7 +517,8 @@
 }
 
 void MarkSweep::MarkConcurrentRoots() {
-  Runtime::Current()->VisitConcurrentRoots(MarkObjectCallback, this);
+  // Visit all runtime roots and clear dirty flags.
+  Runtime::Current()->VisitConcurrentRoots(MarkObjectCallback, this, false, true);
 }
 
 class CheckObjectVisitor {
@@ -571,11 +554,11 @@
   mark_sweep->CheckObject(root);
 }
 
-void MarkSweep::BindLiveToMarkBitmap(ContinuousSpace* space) {
-  CHECK(space->IsAllocSpace());
-  DlMallocSpace* alloc_space = space->AsAllocSpace();
-  SpaceBitmap* live_bitmap = space->GetLiveBitmap();
-  SpaceBitmap* mark_bitmap = alloc_space->mark_bitmap_.release();
+void MarkSweep::BindLiveToMarkBitmap(space::ContinuousSpace* space) {
+  CHECK(space->IsDlMallocSpace());
+  space::DlMallocSpace* alloc_space = space->AsDlMallocSpace();
+  accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+  accounting::SpaceBitmap* mark_bitmap = alloc_space->mark_bitmap_.release();
   GetHeap()->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
   alloc_space->temp_bitmap_.reset(mark_bitmap);
   alloc_space->mark_bitmap_.reset(live_bitmap);
@@ -584,7 +567,6 @@
 class ScanObjectVisitor {
  public:
   ScanObjectVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
-
   }
 
   // TODO: Fixme when anotatalysis works with visitors.
@@ -601,29 +583,39 @@
 };
 
 void MarkSweep::ScanGrayObjects(byte minimum_age) {
-  const Spaces& spaces = heap_->GetSpaces();
-  CardTable* card_table = heap_->GetCardTable();
+  accounting::CardTable* card_table = GetHeap()->GetCardTable();
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
   ScanObjectVisitor visitor(this);
   SetFingerVisitor finger_visitor(this);
-  // TODO: C++ 0x auto
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), space_end = spaces.end(); it != space_end; ++it) {
+    space::ContinuousSpace* space = *it;
+    switch (space->GetGcRetentionPolicy()) {
+      case space::kGcRetentionPolicyNeverCollect:
+        timings_.NewSplit("ScanGrayImageSpaceObjects");
+        break;
+      case space::kGcRetentionPolicyFullCollect:
+        timings_.NewSplit("ScanGrayZygoteSpaceObjects");
+        break;
+      case space::kGcRetentionPolicyAlwaysCollect:
+        timings_.NewSplit("ScanGrayAllocSpaceObjects");
+        break;
+    }
     byte* begin = space->Begin();
     byte* end = space->End();
     // Image spaces are handled properly since live == marked for them.
-    SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
-    card_table->Scan(mark_bitmap, begin, end, visitor, VoidFunctor(), minimum_age);
+    accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+    card_table->Scan(mark_bitmap, begin, end, visitor, finger_visitor, minimum_age);
   }
 }
 
 class CheckBitmapVisitor {
  public:
   CheckBitmapVisitor(MarkSweep* mark_sweep) : mark_sweep_(mark_sweep) {
-
   }
 
-  void operator ()(const Object* obj) const
-      NO_THREAD_SAFETY_ANALYSIS {
+  void operator ()(const Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
     if (kDebugLocking) {
       Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
     }
@@ -640,13 +632,15 @@
   // objects which are either in the image space or marked objects in the alloc
   // space
   CheckBitmapVisitor visitor(this);
-  const Spaces& spaces = heap_->GetSpaces();
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
     if ((*it)->IsImageSpace()) {
-      ImageSpace* space = (*it)->AsImageSpace();
+      space::ImageSpace* space = (*it)->AsImageSpace();
       uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
       uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
-      SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+      accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
       DCHECK(live_bitmap != NULL);
       live_bitmap->VisitMarkedRange(begin, end, visitor, VoidFunctor());
     }
@@ -656,6 +650,7 @@
 // Populates the mark stack based on the set of marked objects and
 // recursively marks until the mark stack is emptied.
 void MarkSweep::RecursiveMark() {
+  timings_.NewSplit("RecursiveMark");
   // RecursiveMark will build the lists of known instances of the Reference classes.
   // See DelayReferenceReferent for details.
   CHECK(soft_reference_list_ == NULL);
@@ -665,16 +660,17 @@
   CHECK(cleared_reference_list_ == NULL);
 
   const bool partial = GetGcType() == kGcTypePartial;
-  const Spaces& spaces = heap_->GetSpaces();
   SetFingerVisitor set_finger_visitor(this);
   ScanObjectVisitor scan_visitor(this);
   if (!kDisableFinger) {
     finger_ = NULL;
-    for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-      ContinuousSpace* space = *it;
-      if ((space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) ||
-          (!partial && space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect)
-          ) {
+    const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+    // TODO: C++0x
+    typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+    for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+      space::ContinuousSpace* space = *it;
+      if ((space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) ||
+          (!partial && space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) {
         current_mark_bitmap_ = space->GetMarkBitmap();
         if (current_mark_bitmap_ == NULL) {
           GetHeap()->DumpSpaces();
@@ -688,9 +684,8 @@
     }
   }
   DisableFinger();
-  timings_.AddSplit("RecursiveMark");
+  timings_.NewSplit("ProcessMarkStack");
   ProcessMarkStack();
-  timings_.AddSplit("ProcessMarkStack");
 }
 
 bool MarkSweep::IsMarkedCallback(const Object* object, void* arg) {
@@ -701,13 +696,12 @@
 
 void MarkSweep::RecursiveMarkDirtyObjects(byte minimum_age) {
   ScanGrayObjects(minimum_age);
-  timings_.AddSplit("ScanGrayObjects");
+  timings_.NewSplit("ProcessMarkStack");
   ProcessMarkStack();
-  timings_.AddSplit("ProcessMarkStack");
 }
 
 void MarkSweep::ReMarkRoots() {
-  Runtime::Current()->VisitRoots(ReMarkObjectVisitor, this);
+  Runtime::Current()->VisitRoots(ReMarkObjectVisitor, this, true, true);
 }
 
 void MarkSweep::SweepJniWeakGlobals(IsMarkedTester is_marked, void* arg) {
@@ -724,7 +718,7 @@
 }
 
 struct ArrayMarkedCheck {
-  ObjectStack* live_stack;
+  accounting::ObjectStack* live_stack;
   MarkSweep* mark_sweep;
 };
 
@@ -734,11 +728,11 @@
   if (array_check->mark_sweep->IsMarked(object)) {
     return true;
   }
-  ObjectStack* live_stack = array_check->live_stack;
+  accounting::ObjectStack* live_stack = array_check->live_stack;
   return std::find(live_stack->Begin(), live_stack->End(), object) == live_stack->End();
 }
 
-void MarkSweep::SweepSystemWeaksArray(ObjectStack* allocations) {
+void MarkSweep::SweepSystemWeaksArray(accounting::ObjectStack* allocations) {
   Runtime* runtime = Runtime::Current();
   // The callbacks check
   // !is_marked where is_marked is the callback but we want
@@ -775,7 +769,7 @@
 void MarkSweep::VerifyIsLive(const Object* obj) {
   Heap* heap = GetHeap();
   if (!heap->GetLiveBitmap()->Test(obj)) {
-    LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+    space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
     if (!large_object_space->GetLiveObjects()->Test(obj)) {
       if (std::find(heap->allocation_stack_->Begin(), heap->allocation_stack_->End(), obj) ==
           heap->allocation_stack_->End()) {
@@ -805,7 +799,7 @@
 
 struct SweepCallbackContext {
   MarkSweep* mark_sweep;
-  AllocSpace* space;
+  space::AllocSpace* space;
   Thread* self;
 };
 
@@ -828,28 +822,29 @@
   MarkSweep* mark_sweep_;
 };
 
-void MarkSweep::ResetCumulativeStatistics() {
-  cumulative_timings_.Reset();
-  total_time_ = 0;
-  total_paused_time_ = 0;
-  total_freed_objects_ = 0;
-  total_freed_bytes_ = 0;
-}
-
-void MarkSweep::MarkRootsCheckpoint() {
+void MarkSweep::MarkRootsCheckpoint(Thread* self) {
   CheckpointMarkThreadRoots check_point(this);
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
-  // Increment the count of the barrier. If all of the checkpoints have already been finished then
-  // will hit 0 and continue. Otherwise we are still waiting for some checkpoints, so the counter
-  // will go positive and we will unblock when it hits zero.
-  gc_barrier_->Increment(Thread::Current(), thread_list->RunCheckpoint(&check_point));
+  // Request the check point is run on all threads returning a count of the threads that must
+  // run through the barrier including self.
+  size_t barrier_count = thread_list->RunCheckpoint(&check_point);
+  // Release locks then wait for all mutator threads to pass the barrier.
+  // TODO: optimize to not release locks when there are no threads to wait for.
+  Locks::heap_bitmap_lock_->ExclusiveUnlock(self);
+  Locks::mutator_lock_->SharedUnlock(self);
+  ThreadState old_state = self->SetState(kWaitingForCheckPointsToRun);
+  CHECK_EQ(old_state, kWaitingPerformingGc);
+  gc_barrier_->Increment(self, barrier_count);
+  self->SetState(kWaitingPerformingGc);
+  Locks::mutator_lock_->SharedLock(self);
+  Locks::heap_bitmap_lock_->ExclusiveLock(self);
 }
 
 void MarkSweep::SweepCallback(size_t num_ptrs, Object** ptrs, void* arg) {
   SweepCallbackContext* context = static_cast<SweepCallbackContext*>(arg);
   MarkSweep* mark_sweep = context->mark_sweep;
   Heap* heap = mark_sweep->GetHeap();
-  AllocSpace* space = context->space;
+  space::AllocSpace* space = context->space;
   Thread* self = context->self;
   Locks::heap_bitmap_lock_->AssertExclusiveHeld(self);
   // Use a bulk free, that merges consecutive objects before freeing or free per object?
@@ -875,22 +870,23 @@
   }
 }
 
-void MarkSweep::SweepArray(TimingLogger& logger, ObjectStack* allocations, bool swap_bitmaps) {
+void MarkSweep::SweepArray(accounting::ObjectStack* allocations, bool swap_bitmaps) {
   size_t freed_bytes = 0;
-  DlMallocSpace* space = heap_->GetAllocSpace();
+  space::DlMallocSpace* space = heap_->GetAllocSpace();
 
   // If we don't swap bitmaps then newly allocated Weaks go into the live bitmap but not mark
   // bitmap, resulting in occasional frees of Weaks which are still in use.
+  timings_.NewSplit("SweepSystemWeaks");
   SweepSystemWeaksArray(allocations);
-  logger.AddSplit("SweepSystemWeaks");
 
+  timings_.NewSplit("Process allocation stack");
   // Newly allocated objects MUST be in the alloc space and those are the only objects which we are
   // going to free.
-  SpaceBitmap* live_bitmap = space->GetLiveBitmap();
-  SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
-  LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
-  SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
-  SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
+  accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+  accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+  space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+  accounting::SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
+  accounting::SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
   if (swap_bitmaps) {
     std::swap(live_bitmap, mark_bitmap);
     std::swap(large_live_objects, large_mark_objects);
@@ -916,7 +912,8 @@
       freed_bytes += large_object_space->Free(self, obj);
     }
   }
-  logger.AddSplit("Process allocation stack");
+  CHECK_EQ(count, allocations->Size());
+  timings_.NewSplit("FreeList");
 
   size_t freed_objects = out - objects;
   freed_bytes += space->FreeList(self, freed_objects, objects);
@@ -925,71 +922,78 @@
   heap_->RecordFree(freed_objects + freed_large_objects, freed_bytes);
   freed_objects_ += freed_objects;
   freed_bytes_ += freed_bytes;
-  logger.AddSplit("FreeList");
+
+  timings_.NewSplit("ResetStack");
   allocations->Reset();
-  logger.AddSplit("ResetStack");
 }
 
-void MarkSweep::Sweep(TimingLogger& timings, bool swap_bitmaps) {
+void MarkSweep::Sweep(bool swap_bitmaps) {
   DCHECK(mark_stack_->IsEmpty());
 
   // If we don't swap bitmaps then newly allocated Weaks go into the live bitmap but not mark
   // bitmap, resulting in occasional frees of Weaks which are still in use.
+  timings_.NewSplit("SweepSystemWeaks");
   SweepSystemWeaks();
-  timings.AddSplit("SweepSystemWeaks");
 
-  const bool partial = GetGcType() == kGcTypePartial;
-  const Spaces& spaces = heap_->GetSpaces();
+  const bool partial = (GetGcType() == kGcTypePartial);
   SweepCallbackContext scc;
   scc.mark_sweep = this;
   scc.self = Thread::Current();
-  // TODO: C++0x auto
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
-    if (
-        space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect ||
-        (!partial && space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect)
-        ) {
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    // We always sweep always collect spaces.
+    bool sweep_space = (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect);
+    if (!partial && !sweep_space) {
+      // We sweep full collect spaces when the GC isn't a partial GC (ie its full).
+      sweep_space = (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect);
+    }
+    if (sweep_space) {
       uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
       uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
-      scc.space = space->AsAllocSpace();
-      SpaceBitmap* live_bitmap = space->GetLiveBitmap();
-      SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+      scc.space = space->AsDlMallocSpace();
+      accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+      accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
       if (swap_bitmaps) {
         std::swap(live_bitmap, mark_bitmap);
       }
-      if (space->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) {
+      if (!space->IsZygoteSpace()) {
+        timings_.NewSplit("SweepAllocSpace");
         // Bitmaps are pre-swapped for optimization which enables sweeping with the heap unlocked.
-        SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
-                               &SweepCallback, reinterpret_cast<void*>(&scc));
+        accounting::SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
+                                           &SweepCallback, reinterpret_cast<void*>(&scc));
       } else {
-        // Zygote sweep takes care of dirtying cards and clearing live bits, does not free actual memory.
-        SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
-                               &ZygoteSweepCallback, reinterpret_cast<void*>(&scc));
+        timings_.NewSplit("SweepZygote");
+        // Zygote sweep takes care of dirtying cards and clearing live bits, does not free actual
+        // memory.
+        accounting::SpaceBitmap::SweepWalk(*live_bitmap, *mark_bitmap, begin, end,
+                                           &ZygoteSweepCallback, reinterpret_cast<void*>(&scc));
       }
     }
   }
-  timings.AddSplit("Sweep");
 
+  timings_.NewSplit("SweepLargeObjects");
   SweepLargeObjects(swap_bitmaps);
-  timings.AddSplit("SweepLargeObjects");
 }
 
 void MarkSweep::SweepLargeObjects(bool swap_bitmaps) {
   // Sweep large objects
-  LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
-  SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
-  SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
+  space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
+  accounting::SpaceSetMap* large_live_objects = large_object_space->GetLiveObjects();
+  accounting::SpaceSetMap* large_mark_objects = large_object_space->GetMarkObjects();
   if (swap_bitmaps) {
     std::swap(large_live_objects, large_mark_objects);
   }
-  SpaceSetMap::Objects& live_objects = large_live_objects->GetObjects();
+  accounting::SpaceSetMap::Objects& live_objects = large_live_objects->GetObjects();
   // O(n*log(n)) but hopefully there are not too many large objects.
   size_t freed_objects = 0;
   size_t freed_bytes = 0;
-  // TODO: C++0x
   Thread* self = Thread::Current();
-  for (SpaceSetMap::Objects::iterator it = live_objects.begin(); it != live_objects.end(); ++it) {
+  // TODO: C++0x
+  typedef accounting::SpaceSetMap::Objects::iterator It;
+  for (It it = live_objects.begin(), end = live_objects.end(); it != end; ++it) {
     if (!large_mark_objects->Test(*it)) {
       freed_bytes += large_object_space->Free(self, const_cast<Object*>(*it));
       ++freed_objects;
@@ -997,20 +1001,21 @@
   }
   freed_objects_ += freed_objects;
   freed_bytes_ += freed_bytes;
-  // Large objects don't count towards bytes_allocated.
   GetHeap()->RecordFree(freed_objects, freed_bytes);
 }
 
 void MarkSweep::CheckReference(const Object* obj, const Object* ref, MemberOffset offset, bool is_static) {
-  const Spaces& spaces = heap_->GetSpaces();
-  // TODO: C++0x auto
-  for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
-    if ((*cur)->IsAllocSpace() && (*cur)->Contains(ref)) {
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->IsDlMallocSpace() && space->Contains(ref)) {
       DCHECK(IsMarked(obj));
 
       bool is_marked = IsMarked(ref);
       if (!is_marked) {
-        LOG(INFO) << **cur;
+        LOG(INFO) << *space;
         LOG(WARNING) << (is_static ? "Static ref'" : "Instance ref'") << PrettyTypeOf(ref)
                      << "' (" << reinterpret_cast<const void*>(ref) << ") in '" << PrettyTypeOf(obj)
                      << "' (" << reinterpret_cast<const void*>(obj) << ") at offset "
@@ -1107,7 +1112,7 @@
 }
 
 class MarkStackChunk : public Task {
-public:
+ public:
   MarkStackChunk(ThreadPool* thread_pool, MarkSweep* mark_sweep, Object** begin, Object** end)
       : mark_sweep_(mark_sweep),
         thread_pool_(thread_pool),
@@ -1169,6 +1174,7 @@
   // Don't need to use atomic ++ since we only one thread is writing to an output block at any
   // given time.
   void Push(Object* obj) {
+    CHECK(obj != NULL);
     data_[length_++] = obj;
   }
 
@@ -1176,7 +1182,7 @@
     if (static_cast<size_t>(length_) < max_size) {
       Push(const_cast<Object*>(obj));
     } else {
-      // Internal buffer is full, push to a new buffer instead.
+      // Internal (thread-local) buffer is full, push to a new buffer instead.
       if (UNLIKELY(output_ == NULL)) {
         AllocateOutputChunk();
       } else if (UNLIKELY(static_cast<size_t>(output_->length_) == max_size)) {
@@ -1255,8 +1261,8 @@
     thread_pool->AddTask(self, new MarkStackChunk(thread_pool, this, begin, end));
   }
   thread_pool->StartWorkers(self);
+  thread_pool->Wait(self, true, true);
   mark_stack_->Reset();
-  thread_pool->Wait(self, true);
   //LOG(INFO) << "Idle wait time " << PrettyDuration(thread_pool->GetWaitTime());
   CHECK_EQ(work_chunks_created_, work_chunks_deleted_) << " some of the work chunks were leaked";
 }
@@ -1443,15 +1449,16 @@
 }
 
 void MarkSweep::UnBindBitmaps() {
-  const Spaces& spaces = heap_->GetSpaces();
-  // TODO: C++0x auto
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    Space* space = *it;
-    if (space->IsAllocSpace()) {
-      DlMallocSpace* alloc_space = space->AsAllocSpace();
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->IsDlMallocSpace()) {
+      space::DlMallocSpace* alloc_space = space->AsDlMallocSpace();
       if (alloc_space->temp_bitmap_.get() != NULL) {
         // At this point, the temp_bitmap holds our old mark bitmap.
-        SpaceBitmap* new_bitmap = alloc_space->temp_bitmap_.release();
+        accounting::SpaceBitmap* new_bitmap = alloc_space->temp_bitmap_.release();
         GetHeap()->GetMarkBitmap()->ReplaceBitmap(alloc_space->mark_bitmap_.get(), new_bitmap);
         CHECK_EQ(alloc_space->mark_bitmap_.release(), alloc_space->live_bitmap_.get());
         alloc_space->mark_bitmap_.reset(new_bitmap);
@@ -1464,20 +1471,21 @@
 void MarkSweep::FinishPhase() {
   // Can't enqueue referneces if we hold the mutator lock.
   Object* cleared_references = GetClearedReferences();
-  heap_->EnqueueClearedReferences(&cleared_references);
+  Heap* heap = GetHeap();
+  heap->EnqueueClearedReferences(&cleared_references);
 
-  heap_->PostGcVerification(this);
+  heap->PostGcVerification(this);
 
-  heap_->GrowForUtilization(GetDuration());
-  timings_.AddSplit("GrowForUtilization");
+  timings_.NewSplit("GrowForUtilization");
+  heap->GrowForUtilization(GetDurationNs());
 
-  heap_->RequestHeapTrim();
-  timings_.AddSplit("RequestHeapTrim");
+  timings_.NewSplit("RequestHeapTrim");
+  heap->RequestHeapTrim();
 
   // Update the cumulative statistics
-  total_time_ += GetDuration();
-  total_paused_time_ += std::accumulate(GetPauseTimes().begin(), GetPauseTimes().end(), 0,
-                                        std::plus<uint64_t>());
+  total_time_ns_ += GetDurationNs();
+  total_paused_time_ns_ += std::accumulate(GetPauseTimes().begin(), GetPauseTimes().end(), 0,
+                                           std::plus<uint64_t>());
   total_freed_objects_ += GetFreedObjects();
   total_freed_bytes_ += GetFreedBytes();
 
@@ -1511,27 +1519,26 @@
 
   // Update the cumulative loggers.
   cumulative_timings_.Start();
-  cumulative_timings_.AddLogger(timings_);
+  cumulative_timings_.AddNewLogger(timings_);
   cumulative_timings_.End();
 
   // Clear all of the spaces' mark bitmaps.
-  const Spaces& spaces = heap_->GetSpaces();
-  // TODO: C++0x auto
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
-    if (space->GetGcRetentionPolicy() != kGcRetentionPolicyNeverCollect) {
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->GetGcRetentionPolicy() != space::kGcRetentionPolicyNeverCollect) {
       space->GetMarkBitmap()->Clear();
     }
   }
   mark_stack_->Reset();
 
   // Reset the marked large objects.
-  LargeObjectSpace* large_objects = GetHeap()->GetLargeObjectsSpace();
+  space::LargeObjectSpace* large_objects = GetHeap()->GetLargeObjectsSpace();
   large_objects->GetMarkObjects()->Clear();
 }
 
-MarkSweep::~MarkSweep() {
-
-}
-
+}  // namespace collector
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/mark_sweep.h b/src/gc/collector/mark_sweep.h
similarity index 86%
rename from src/gc/mark_sweep.h
rename to src/gc/collector/mark_sweep.h
index 11ce32f..9df3c19 100644
--- a/src/gc/mark_sweep.h
+++ b/src/gc/collector/mark_sweep.h
@@ -21,40 +21,50 @@
 #include "barrier.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "base/timing_logger.h"
 #include "garbage_collector.h"
-#include "gc_type.h"
 #include "offsets.h"
 #include "root_visitor.h"
 #include "UniquePtr.h"
 
 namespace art {
+
 namespace mirror {
-class Class;
-class Object;
-template<class T> class ObjectArray;
-}
-template <typename T> class AtomicStack;
-class CheckObjectVisitor;
-class ContinuousSpace;
-class Heap;
-class MarkIfReachesAllocspaceVisitor;
-class ModUnionClearCardVisitor;
-class ModUnionVisitor;
-class ModUnionTableBitmap;
-typedef AtomicStack<mirror::Object*> ObjectStack;
-class SpaceBitmap;
+  class Class;
+  class Object;
+  template<class T> class ObjectArray;
+}  // namespace mirror
+
 class StackVisitor;
 class Thread;
-class MarkStackChunk;
+
+namespace gc {
+
+namespace accounting {
+  template <typename T> class AtomicStack;
+  class MarkIfReachesAllocspaceVisitor;
+  class ModUnionClearCardVisitor;
+  class ModUnionVisitor;
+  class ModUnionTableBitmap;
+  class MarkStackChunk;
+  typedef AtomicStack<mirror::Object*> ObjectStack;
+  class SpaceBitmap;
+}  // namespace accounting
+
+namespace space {
+  class ContinuousSpace;
+}  // namespace space
+
+class CheckObjectVisitor;
+class Heap;
+
+namespace collector {
 
 class MarkSweep : public GarbageCollector {
  public:
-  explicit MarkSweep(Heap* heap, bool is_concurrent);
+  explicit MarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
 
-  ~MarkSweep();
+  ~MarkSweep() {}
 
-  virtual std::string GetName() const;
   virtual void InitializePhase();
   virtual bool IsConcurrent() const;
   virtual bool HandleDirtyObjectsPhase() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -85,8 +95,9 @@
   void MarkConcurrentRoots();
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  void MarkRootsCheckpoint();
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  void MarkRootsCheckpoint(Thread* self)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Verify that image roots point to only marked objects within the alloc space.
   void VerifyImageRoots()
@@ -98,16 +109,17 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Make a space immune, immune spaces are assumed to have all live objects marked.
-  void ImmuneSpace(ContinuousSpace* space)
+  // Make a space immune, immune spaces have all live objects marked - that is the mark and
+  // live bitmaps are bound together.
+  void ImmuneSpace(space::ContinuousSpace* space)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Bind the live bits to the mark bits of bitmaps based on the gc type.
-  virtual void BindBitmaps()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Bind the live bits to the mark bits of bitmaps for spaces that are never collected, ie
+  // the image. Mark that portion of the heap as immune.
+  virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void BindLiveToMarkBitmap(ContinuousSpace* space)
+  void BindLiveToMarkBitmap(space::ContinuousSpace* space)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   void UnBindBitmaps()
@@ -127,21 +139,15 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Sweeps unmarked objects to complete the garbage collection.
-  virtual void Sweep(TimingLogger& timings, bool swap_bitmaps)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  virtual void Sweep(bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Sweeps unmarked objects to complete the garbage collection.
-  void SweepLargeObjects(bool swap_bitmaps)
-      EXCLUSIVE_LOCKS_REQUIRED(GlobalSynchronization::heap_bitmap_lock_);
+  void SweepLargeObjects(bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Sweep only pointers within an array. WARNING: Trashes objects.
-  void SweepArray(TimingLogger& logger, ObjectStack* allocation_stack_, bool swap_bitmaps)
+  void SweepArray(accounting::ObjectStack* allocation_stack_, bool swap_bitmaps)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  // Swap bitmaps (if we are a full Gc then we swap the zygote bitmap too).
-  virtual void SwapBitmaps() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-  void SwapLargeObjects() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
   mirror::Object* GetClearedReferences() {
     return cleared_reference_list_;
   }
@@ -177,12 +183,12 @@
     return freed_objects_;
   }
 
-  uint64_t GetTotalTime() const {
-    return total_time_;
+  uint64_t GetTotalTimeNs() const {
+    return total_time_ns_;
   }
 
-  uint64_t GetTotalPausedTime() const {
-    return total_paused_time_;
+  uint64_t GetTotalPausedTimeNs() const {
+    return total_paused_time_ns_;
   }
 
   uint64_t GetTotalFreedObjects() const {
@@ -200,7 +206,7 @@
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Only sweep the weaks which are inside of an allocation stack.
-  void SweepSystemWeaksArray(ObjectStack* allocations)
+  void SweepSystemWeaksArray(accounting::ObjectStack* allocations)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   static bool VerifyIsLiveCallback(const mirror::Object* obj, void* arg)
@@ -237,16 +243,6 @@
     return *gc_barrier_;
   }
 
-  TimingLogger& GetTimings() {
-    return timings_;
-  }
-
-  CumulativeLogger& GetCumulativeTimings() {
-    return cumulative_timings_;
-  }
-
-  void ResetCumulativeStatistics();
-
  protected:
   // Returns true if the object has its bit set in the mark bitmap.
   bool IsMarked(const mirror::Object* object) const;
@@ -381,13 +377,14 @@
   // Whether or not we count how many of each type of object were scanned.
   static const bool kCountScannedTypes = false;
 
-  // Current space, we check this space first to avoid searching for the appropriate space for an object.
-  SpaceBitmap* current_mark_bitmap_;
+  // Current space, we check this space first to avoid searching for the appropriate space for an
+  // object.
+  accounting::SpaceBitmap* current_mark_bitmap_;
 
   // Cache java.lang.Class for optimization.
   mirror::Class* java_lang_Class_;
 
-  ObjectStack* mark_stack_;
+  accounting::ObjectStack* mark_stack_;
 
   mirror::Object* finger_;
 
@@ -401,10 +398,15 @@
   mirror::Object* phantom_reference_list_;
   mirror::Object* cleared_reference_list_;
 
+  // Number of bytes freed in this collection.
   AtomicInteger freed_bytes_;
+  // Number of objects freed in this collection.
   AtomicInteger freed_objects_;
+  // Number of classes scanned, if kCountScannedTypes.
   AtomicInteger class_count_;
+  // Number of arrays scanned, if kCountScannedTypes.
   AtomicInteger array_count_;
+  // Number of non-class/arrays scanned, if kCountScannedTypes.
   AtomicInteger other_count_;
   AtomicInteger large_object_test_;
   AtomicInteger large_object_mark_;
@@ -414,28 +416,19 @@
   AtomicInteger work_chunks_deleted_;
   AtomicInteger reference_count_;
 
-  // Cumulative statistics.
-  uint64_t total_time_;
-  uint64_t total_paused_time_;
-  uint64_t total_freed_objects_;
-  uint64_t total_freed_bytes_;
-
   UniquePtr<Barrier> gc_barrier_;
   Mutex large_object_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   Mutex mark_stack_expand_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
 
   const bool is_concurrent_;
 
-  TimingLogger timings_;
-  CumulativeLogger cumulative_timings_;
-
   bool clear_soft_references_;
 
   friend class AddIfReachesAllocSpaceVisitor; // Used by mod-union table.
   friend class CheckBitmapVisitor;
   friend class CheckObjectVisitor;
   friend class CheckReferenceVisitor;
-  friend class Heap;
+  friend class art::gc::Heap;
   friend class InternTableEntryIsUnmarked;
   friend class MarkIfReachesAllocspaceVisitor;
   friend class ModUnionCheckReferences;
@@ -453,6 +446,8 @@
   DISALLOW_COPY_AND_ASSIGN(MarkSweep);
 };
 
+}  // namespace collector
+}  // namespace gc
 }  // namespace art
 
 #endif  // ART_SRC_GC_MARK_SWEEP_H_
diff --git a/src/gc/partial_mark_sweep.cc b/src/gc/collector/partial_mark_sweep.cc
similarity index 63%
rename from src/gc/partial_mark_sweep.cc
rename to src/gc/collector/partial_mark_sweep.cc
index f9c1787..ef893c5 100644
--- a/src/gc/partial_mark_sweep.cc
+++ b/src/gc/collector/partial_mark_sweep.cc
@@ -16,36 +16,38 @@
 
 #include "partial_mark_sweep.h"
 
-#include "heap.h"
-#include "large_object_space.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
 #include "partial_mark_sweep.h"
-#include "space.h"
 #include "thread.h"
 
 namespace art {
+namespace gc {
+namespace collector {
 
-PartialMarkSweep::PartialMarkSweep(Heap* heap, bool is_concurrent)
-    : MarkSweep(heap, is_concurrent) {
+PartialMarkSweep::PartialMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
+    : MarkSweep(heap, is_concurrent, name_prefix + (name_prefix.empty() ? "" : " ") + "partial") {
   cumulative_timings_.SetName(GetName());
 }
 
-PartialMarkSweep::~PartialMarkSweep() {
-
-}
-
 void PartialMarkSweep::BindBitmaps() {
   MarkSweep::BindBitmaps();
 
-  Spaces& spaces = GetHeap()->GetSpaces();
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   // For partial GCs we need to bind the bitmap of the zygote space so that all objects in the
   // zygote space are viewed as marked.
-  for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
-    if (space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) {
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect) {
+      CHECK(space->IsZygoteSpace());
       ImmuneSpace(space);
     }
   }
 }
 
+}  // namespace collector
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/collector/partial_mark_sweep.h b/src/gc/collector/partial_mark_sweep.h
new file mode 100644
index 0000000..bd4a580
--- /dev/null
+++ b/src/gc/collector/partial_mark_sweep.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_COLLECTOR_PARTIAL_MARK_SWEEP_H_
+#define ART_SRC_GC_COLLECTOR_PARTIAL_MARK_SWEEP_H_
+
+#include "locks.h"
+#include "mark_sweep.h"
+
+namespace art {
+namespace gc {
+namespace collector {
+
+class PartialMarkSweep : public MarkSweep {
+ public:
+  virtual GcType GetGcType() const {
+    return kGcTypePartial;
+  }
+
+  explicit PartialMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
+  ~PartialMarkSweep() {}
+
+protected:
+  // Bind the live bits to the mark bits of bitmaps for spaces that aren't collected for partial
+  // collections, ie the Zygote space. Also mark this space is immune.
+  virtual void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  DISALLOW_COPY_AND_ASSIGN(PartialMarkSweep);
+};
+
+}  // namespace collector
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_COLLECTOR_PARTIAL_MARK_SWEEP_H_
diff --git a/src/gc/collector/sticky_mark_sweep.cc b/src/gc/collector/sticky_mark_sweep.cc
new file mode 100644
index 0000000..71e580d
--- /dev/null
+++ b/src/gc/collector/sticky_mark_sweep.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gc/heap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space.h"
+#include "sticky_mark_sweep.h"
+#include "thread.h"
+
+namespace art {
+namespace gc {
+namespace collector {
+
+StickyMarkSweep::StickyMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix)
+    : PartialMarkSweep(heap, is_concurrent,
+                       name_prefix + (name_prefix.empty() ? "" : " ") + "sticky") {
+  cumulative_timings_.SetName(GetName());
+}
+
+void StickyMarkSweep::BindBitmaps() {
+  PartialMarkSweep::BindBitmaps();
+
+  const std::vector<space::ContinuousSpace*>& spaces = GetHeap()->GetContinuousSpaces();
+  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+  // For sticky GC, we want to bind the bitmaps of all spaces as the allocation stack lets us
+  // know what was allocated since the last GC. A side-effect of binding the allocation space mark
+  // and live bitmap is that marking the objects will place them in the live bitmap.
+  // TODO: C++0x
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    space::ContinuousSpace* space = *it;
+    if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect) {
+      BindLiveToMarkBitmap(space);
+    }
+  }
+
+  GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked();
+}
+
+void StickyMarkSweep::MarkReachableObjects() {
+  DisableFinger();
+  RecursiveMarkDirtyObjects(accounting::CardTable::kCardDirty - 1);
+}
+
+void StickyMarkSweep::Sweep(bool swap_bitmaps) {
+  timings_.NewSplit("SweepArray");
+  accounting::ObjectStack* live_stack = GetHeap()->GetLiveStack();
+  SweepArray(live_stack, false);
+}
+
+}  // namespace collector
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/sticky_mark_sweep.h b/src/gc/collector/sticky_mark_sweep.h
similarity index 67%
rename from src/gc/sticky_mark_sweep.h
rename to src/gc/collector/sticky_mark_sweep.h
index 41ab0cc..b16cfc1 100644
--- a/src/gc/sticky_mark_sweep.h
+++ b/src/gc/collector/sticky_mark_sweep.h
@@ -22,29 +22,34 @@
 #include "partial_mark_sweep.h"
 
 namespace art {
+namespace gc {
+namespace collector {
 
 class StickyMarkSweep : public PartialMarkSweep {
  public:
-  virtual GcType GetGcType() const {
+  GcType GetGcType() const {
     return kGcTypeSticky;
   }
 
-  explicit StickyMarkSweep(Heap* heap, bool is_concurrent);
-  ~StickyMarkSweep();
-protected:
-  virtual void BindBitmaps()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  explicit StickyMarkSweep(Heap* heap, bool is_concurrent, const std::string& name_prefix = "");
+  ~StickyMarkSweep() {}
 
-  virtual void MarkReachableObjects()
+protected:
+  // Bind the live bits to the mark bits of bitmaps for all spaces, all spaces other than the
+  // alloc space will be marked as immune.
+  void BindBitmaps() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void MarkReachableObjects()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  virtual void Sweep(TimingLogger& timings, bool swap_bitmaps)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  void Sweep(bool swap_bitmaps) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   DISALLOW_COPY_AND_ASSIGN(StickyMarkSweep);
 };
 
+}  // namespace collector
+}  // namespace gc
 }  // namespace art
 
 #endif  // ART_SRC_GC_STICKY_MARK_SWEEP_H_
diff --git a/src/gc/garbage_collector.cc b/src/gc/garbage_collector.cc
deleted file mode 100644
index 94daec7..0000000
--- a/src/gc/garbage_collector.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "garbage_collector.h"
-
-#include "base/mutex-inl.h"
-#include "thread.h"
-#include "thread_list.h"
-
-namespace art {
-  GarbageCollector::GarbageCollector(Heap* heap)
-      : heap_(heap),
-        duration_(0) {
-
-  }
-
-  bool GarbageCollector::HandleDirtyObjectsPhase() {
-    DCHECK(IsConcurrent());
-    return true;
-  }
-
-  void GarbageCollector::RegisterPause(uint64_t nano_length) {
-    pause_times_.push_back(nano_length);
-  }
-
-  void GarbageCollector::Run() {
-    Thread* self = Thread::Current();
-    ThreadList* thread_list = Runtime::Current()->GetThreadList();
-
-    uint64_t start_time = NanoTime();
-    pause_times_.clear();
-    duration_ = 0;
-
-    InitializePhase();
-
-    if (!IsConcurrent()) {
-      // Pause is the entire length of the GC.
-      uint64_t pause_start = NanoTime();
-      thread_list->SuspendAll();
-      MarkingPhase();
-      ReclaimPhase();
-      thread_list->ResumeAll();
-      uint64_t pause_end = NanoTime();
-      pause_times_.push_back(pause_end - pause_start);
-    } else {
-      {
-        ReaderMutexLock mu(self, *Locks::mutator_lock_);
-        MarkingPhase();
-      }
-      bool done = false;
-      while (!done) {
-        uint64_t pause_start = NanoTime();
-        thread_list->SuspendAll();
-        done = HandleDirtyObjectsPhase();
-        thread_list->ResumeAll();
-        uint64_t pause_end = NanoTime();
-        pause_times_.push_back(pause_end - pause_start);
-      }
-      {
-        ReaderMutexLock mu(self, *Locks::mutator_lock_);
-        ReclaimPhase();
-      }
-    }
-
-    uint64_t end_time = NanoTime();
-    duration_ = end_time - start_time;
-
-    FinishPhase();
-  }
-
-  GarbageCollector::~GarbageCollector() {
-
-  }
-}  // namespace art
diff --git a/src/gc/gc_type.h b/src/gc/gc_type.h
deleted file mode 100644
index 908f038..0000000
--- a/src/gc/gc_type.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_GC_TYPE_H_
-#define ART_SRC_GC_GC_TYPE_H_
-
-namespace art {
-
-// The ordering of the enum matters, it is used to determine which GCs are run first.
-enum GcType {
-  // No Gc
-  kGcTypeNone,
-  // Sticky mark bits "generational" GC.
-  kGcTypeSticky,
-  // Partial GC, over only the alloc space.
-  kGcTypePartial,
-  // Full GC
-  kGcTypeFull,
-  // Number of different Gc types.
-  kGcTypeMax,
-};
-std::ostream& operator<<(std::ostream& os, const GcType& policy);
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_GC_TYPE_H_
diff --git a/src/heap.cc b/src/gc/heap.cc
similarity index 70%
rename from src/heap.cc
rename to src/gc/heap.cc
index f39c26e..34c0b5c 100644
--- a/src/heap.cc
+++ b/src/gc/heap.cc
@@ -25,20 +25,17 @@
 #include "base/stl_util.h"
 #include "cutils/sched_policy.h"
 #include "debugger.h"
-#include "gc/atomic_stack.h"
-#include "gc/card_table.h"
-#include "gc/card_table-inl.h"
-#include "gc/heap_bitmap.h"
-#include "gc/heap_bitmap-inl.h"
-#include "gc/large_object_space.h"
-#include "gc/mark_sweep.h"
-#include "gc/mark_sweep-inl.h"
-#include "gc/partial_mark_sweep.h"
-#include "gc/space_bitmap-inl.h"
-#include "gc/sticky_mark_sweep.h"
-#include "gc/mod_union_table.h"
-#include "gc/mod_union_table-inl.h"
-#include "gc/space.h"
+#include "gc/accounting/atomic_stack.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap-inl.h"
+#include "gc/accounting/mod_union_table-inl.h"
+#include "gc/accounting/space_bitmap-inl.h"
+#include "gc/collector/mark_sweep-inl.h"
+#include "gc/collector/partial_mark_sweep.h"
+#include "gc/collector/sticky_mark_sweep.h"
+#include "gc/space/image_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
 #include "image.h"
 #include "invoke_arg_array_builder.h"
 #include "mirror/class-inl.h"
@@ -56,10 +53,15 @@
 #include "well_known_classes.h"
 
 namespace art {
+namespace gc {
 
+// When to create a log message about a slow GC, 100ms.
 static const uint64_t kSlowGcThreshold = MsToNs(100);
+// When to create a log message about a slow pause, 5ms.
 static const uint64_t kLongGcPauseThreshold = MsToNs(5);
 static const bool kDumpGcPerformanceOnShutdown = false;
+// Minimum amount of remaining bytes before a concurrent GC is triggered.
+static const size_t kMinConcurrentRemainingBytes = 128 * KB;
 const double Heap::kDefaultTargetUtilization = 0.5;
 
 static bool GenerateImage(const std::string& image_file_name) {
@@ -156,19 +158,18 @@
       card_table_(NULL),
       concurrent_gc_(concurrent_gc),
       have_zygote_space_(false),
+      reference_queue_lock_(NULL),
       is_gc_running_(false),
-      last_gc_type_(kGcTypeNone),
-      enforce_heap_growth_rate_(false),
+      last_gc_type_(collector::kGcTypeNone),
       capacity_(capacity),
       growth_limit_(growth_limit),
       max_allowed_footprint_(initial_size),
-      concurrent_start_size_(128 * KB),
-      concurrent_min_free_(256 * KB),
-      concurrent_start_bytes_(concurrent_gc ? initial_size - concurrent_start_size_ :
-          std::numeric_limits<size_t>::max()),
+      concurrent_start_bytes_(concurrent_gc ? initial_size - (kMinConcurrentRemainingBytes)
+                                            :  std::numeric_limits<size_t>::max()),
       sticky_gc_count_(0),
-      total_bytes_freed_(0),
-      total_objects_freed_(0),
+      sticky_to_partial_gc_ratio_(10),
+      total_bytes_freed_ever_(0),
+      total_objects_freed_ever_(0),
       large_object_threshold_(3 * kPageSize),
       num_bytes_allocated_(0),
       verify_missing_card_marks_(false),
@@ -176,12 +177,11 @@
       verify_pre_gc_heap_(false),
       verify_post_gc_heap_(false),
       verify_mod_union_table_(false),
-      partial_gc_frequency_(10),
       min_alloc_space_size_for_sticky_gc_(2 * MB),
       min_remaining_space_for_sticky_gc_(1 * MB),
-      last_trim_time_(0),
+      last_trim_time_ms_(0),
       allocation_rate_(0),
-      max_allocation_stack_size_(MB),
+      max_allocation_stack_size_(kDesiredHeapVerification > kNoHeapVerification? KB : MB),
       reference_referent_offset_(0),
       reference_queue_offset_(0),
       reference_queueNext_offset_(0),
@@ -198,34 +198,34 @@
     LOG(INFO) << "Heap() entering";
   }
 
-  live_bitmap_.reset(new HeapBitmap(this));
-  mark_bitmap_.reset(new HeapBitmap(this));
+  live_bitmap_.reset(new accounting::HeapBitmap(this));
+  mark_bitmap_.reset(new accounting::HeapBitmap(this));
 
   // Requested begin for the alloc space, to follow the mapped image and oat files
   byte* requested_begin = NULL;
   std::string image_file_name(original_image_file_name);
   if (!image_file_name.empty()) {
-    ImageSpace* image_space = NULL;
+    space::ImageSpace* image_space = NULL;
 
     if (OS::FileExists(image_file_name.c_str())) {
       // If the /system file exists, it should be up-to-date, don't try to generate
-      image_space = ImageSpace::Create(image_file_name);
+      image_space = space::ImageSpace::Create(image_file_name);
     } else {
       // If the /system file didn't exist, we need to use one from the dalvik-cache.
       // If the cache file exists, try to open, but if it fails, regenerate.
       // If it does not exist, generate.
       image_file_name = GetDalvikCacheFilenameOrDie(image_file_name);
       if (OS::FileExists(image_file_name.c_str())) {
-        image_space = ImageSpace::Create(image_file_name);
+        image_space = space::ImageSpace::Create(image_file_name);
       }
       if (image_space == NULL) {
         CHECK(GenerateImage(image_file_name)) << "Failed to generate image: " << image_file_name;
-        image_space = ImageSpace::Create(image_file_name);
+        image_space = space::ImageSpace::Create(image_file_name);
       }
     }
 
     CHECK(image_space != NULL) << "Failed to create space from " << image_file_name;
-    AddSpace(image_space);
+    AddContinuousSpace(image_space);
     // Oat files referenced by image files immediately follow them in memory, ensure alloc space
     // isn't going to get in the middle
     byte* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
@@ -247,46 +247,47 @@
   // Allocate the large object space.
   const bool kUseFreeListSpaceForLOS  = false;
   if (kUseFreeListSpaceForLOS) {
-    large_object_space_.reset(FreeListSpace::Create("large object space", NULL, capacity));
+    large_object_space_ = space::FreeListSpace::Create("large object space", NULL, capacity);
   } else {
-    large_object_space_.reset(LargeObjectMapSpace::Create("large object space"));
+    large_object_space_ = space::LargeObjectMapSpace::Create("large object space");
   }
-  live_bitmap_->SetLargeObjects(large_object_space_->GetLiveObjects());
-  mark_bitmap_->SetLargeObjects(large_object_space_->GetMarkObjects());
+  CHECK(large_object_space_ != NULL) << "Failed to create large object space";
+  AddDiscontinuousSpace(large_object_space_);
 
-  UniquePtr<DlMallocSpace> alloc_space(DlMallocSpace::Create("alloc space", initial_size,
-                                                             growth_limit, capacity,
-                                                             requested_begin));
-  alloc_space_ = alloc_space.release();
+  alloc_space_ = space::DlMallocSpace::Create("alloc space",
+                                              initial_size,
+                                              growth_limit, capacity,
+                                              requested_begin);
   CHECK(alloc_space_ != NULL) << "Failed to create alloc space";
   alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
-  AddSpace(alloc_space_);
+  AddContinuousSpace(alloc_space_);
 
-  // Spaces are sorted in order of Begin().
-  byte* heap_begin = spaces_.front()->Begin();
-  size_t heap_capacity = spaces_.back()->End() - spaces_.front()->Begin();
-  if (spaces_.back()->IsAllocSpace()) {
-    heap_capacity += spaces_.back()->AsAllocSpace()->NonGrowthLimitCapacity();
+  // Compute heap capacity. Continuous spaces are sorted in order of Begin().
+  byte* heap_begin = continuous_spaces_.front()->Begin();
+  size_t heap_capacity = continuous_spaces_.back()->End() - continuous_spaces_.front()->Begin();
+  if (continuous_spaces_.back()->IsDlMallocSpace()) {
+    heap_capacity += continuous_spaces_.back()->AsDlMallocSpace()->NonGrowthLimitCapacity();
   }
 
   // Mark image objects in the live bitmap
   // TODO: C++0x
-  for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    Space* space = *it;
+  typedef std::vector<space::ContinuousSpace*>::iterator It;
+  for (It it = continuous_spaces_.begin(); it != continuous_spaces_.end(); ++it) {
+    space::ContinuousSpace* space = *it;
     if (space->IsImageSpace()) {
-      ImageSpace* image_space = space->AsImageSpace();
+      space::ImageSpace* image_space = space->AsImageSpace();
       image_space->RecordImageAllocations(image_space->GetLiveBitmap());
     }
   }
 
   // Allocate the card table.
-  card_table_.reset(CardTable::Create(heap_begin, heap_capacity));
+  card_table_.reset(accounting::CardTable::Create(heap_begin, heap_capacity));
   CHECK(card_table_.get() != NULL) << "Failed to create card table";
 
-  mod_union_table_.reset(new ModUnionTableToZygoteAllocspace<ModUnionTableReferenceCache>(this));
-  CHECK(mod_union_table_.get() != NULL) << "Failed to create mod-union table";
+  image_mod_union_table_.reset(new accounting::ModUnionTableToZygoteAllocspace(this));
+  CHECK(image_mod_union_table_.get() != NULL) << "Failed to create image mod-union table";
 
-  zygote_mod_union_table_.reset(new ModUnionTableCardCache(this));
+  zygote_mod_union_table_.reset(new accounting::ModUnionTableCardCache(this));
   CHECK(zygote_mod_union_table_.get() != NULL) << "Failed to create Zygote mod-union table";
 
   // TODO: Count objects in the image space here.
@@ -294,11 +295,11 @@
 
   // Default mark stack size in bytes.
   static const size_t default_mark_stack_size = 64 * KB;
-  mark_stack_.reset(ObjectStack::Create("mark stack", default_mark_stack_size));
-  allocation_stack_.reset(ObjectStack::Create("allocation stack",
-                                              max_allocation_stack_size_));
-  live_stack_.reset(ObjectStack::Create("live stack",
-                                      max_allocation_stack_size_));
+  mark_stack_.reset(accounting::ObjectStack::Create("mark stack", default_mark_stack_size));
+  allocation_stack_.reset(accounting::ObjectStack::Create("allocation stack",
+                                                          max_allocation_stack_size_));
+  live_stack_.reset(accounting::ObjectStack::Create("live stack",
+                                                    max_allocation_stack_size_));
 
   // It's still too early to take a lock because there are no threads yet, but we can create locks
   // now. We don't create it earlier to make it clear that you can't use locks during heap
@@ -308,17 +309,17 @@
                                                 *gc_complete_lock_));
 
   // Create the reference queue lock, this is required so for parrallel object scanning in the GC.
-  reference_queue_lock_.reset(new Mutex("reference queue lock"));
+  reference_queue_lock_ = new Mutex("reference queue lock");
 
-  last_gc_time_ = NanoTime();
+  last_gc_time_ns_ = NanoTime();
   last_gc_size_ = GetBytesAllocated();
 
   // Create our garbage collectors.
   for (size_t i = 0; i < 2; ++i) {
     const bool concurrent = i != 0;
-    mark_sweep_collectors_.push_back(new MarkSweep(this, concurrent));
-    mark_sweep_collectors_.push_back(new PartialMarkSweep(this, concurrent));
-    mark_sweep_collectors_.push_back(new StickyMarkSweep(this, concurrent));
+    mark_sweep_collectors_.push_back(new collector::MarkSweep(this, concurrent));
+    mark_sweep_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));
+    mark_sweep_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));
   }
 
   CHECK(max_allowed_footprint_ != 0);
@@ -331,7 +332,7 @@
   // TODO: Make sysconf(_SC_NPROCESSORS_CONF) be a helper function?
   // Use the number of processors - 1 since the thread doing the GC does work while its waiting for
   // workers to complete.
-  thread_pool_.reset(new ThreadPool(sysconf(_SC_NPROCESSORS_CONF) - 1));
+  thread_pool_.reset(new ThreadPool(1)); // new ThreadPool(sysconf(_SC_NPROCESSORS_CONF) - 1));
 }
 
 void Heap::DeleteThreadPool() {
@@ -339,44 +340,55 @@
 }
 
 // Sort spaces based on begin address
-struct SpaceSorter {
-  bool operator ()(const ContinuousSpace* a, const ContinuousSpace* b) const {
+struct ContinuousSpaceSorter {
+  bool operator ()(const space::ContinuousSpace* a, const space::ContinuousSpace* b) const {
     return a->Begin() < b->Begin();
   }
 };
 
-void Heap::AddSpace(ContinuousSpace* space) {
+void Heap::AddContinuousSpace(space::ContinuousSpace* space) {
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   DCHECK(space != NULL);
   DCHECK(space->GetLiveBitmap() != NULL);
-  live_bitmap_->AddSpaceBitmap(space->GetLiveBitmap());
+  live_bitmap_->AddContinuousSpaceBitmap(space->GetLiveBitmap());
   DCHECK(space->GetMarkBitmap() != NULL);
-  mark_bitmap_->AddSpaceBitmap(space->GetMarkBitmap());
-  spaces_.push_back(space);
-  if (space->IsAllocSpace()) {
-    alloc_space_ = space->AsAllocSpace();
+  mark_bitmap_->AddContinuousSpaceBitmap(space->GetMarkBitmap());
+  continuous_spaces_.push_back(space);
+  if (space->IsDlMallocSpace() && !space->IsLargeObjectSpace()) {
+    alloc_space_ = space->AsDlMallocSpace();
   }
 
   // Ensure that spaces remain sorted in increasing order of start address (required for CMS finger)
-  std::sort(spaces_.begin(), spaces_.end(), SpaceSorter());
+  std::sort(continuous_spaces_.begin(), continuous_spaces_.end(), ContinuousSpaceSorter());
 
   // Ensure that ImageSpaces < ZygoteSpaces < AllocSpaces so that we can do address based checks to
   // avoid redundant marking.
   bool seen_zygote = false, seen_alloc = false;
-  for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    Space* space = *it;
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = continuous_spaces_.begin(); it != continuous_spaces_.end(); ++it) {
+    space::ContinuousSpace* space = *it;
     if (space->IsImageSpace()) {
       DCHECK(!seen_zygote);
       DCHECK(!seen_alloc);
     } else if (space->IsZygoteSpace()) {
       DCHECK(!seen_alloc);
       seen_zygote = true;
-    } else if (space->IsAllocSpace()) {
+    } else if (space->IsDlMallocSpace()) {
       seen_alloc = true;
     }
   }
 }
 
+void Heap::AddDiscontinuousSpace(space::DiscontinuousSpace* space) {
+  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
+  DCHECK(space != NULL);
+  DCHECK(space->GetLiveObjects() != NULL);
+  live_bitmap_->AddDiscontinuousObjectSet(space->GetLiveObjects());
+  DCHECK(space->GetMarkObjects() != NULL);
+  mark_bitmap_->AddDiscontinuousObjectSet(space->GetMarkObjects());
+  discontinuous_spaces_.push_back(space);
+}
+
 void Heap::DumpGcPerformanceInfo(std::ostream& os) {
   // Dump cumulative timings.
   os << "Dumping cumulative Gc timings\n";
@@ -385,14 +397,15 @@
   // Dump cumulative loggers for each GC type.
   // TODO: C++0x
   uint64_t total_paused_time = 0;
-  for (Collectors::const_iterator it = mark_sweep_collectors_.begin();
+  typedef std::vector<collector::MarkSweep*>::const_iterator It;
+  for (It it = mark_sweep_collectors_.begin();
        it != mark_sweep_collectors_.end(); ++it) {
-    MarkSweep* collector = *it;
+    collector::MarkSweep* collector = *it;
     CumulativeLogger& logger = collector->GetCumulativeTimings();
     if (logger.GetTotalNs() != 0) {
       os << Dumpable<CumulativeLogger>(logger);
       const uint64_t total_ns = logger.GetTotalNs();
-      const uint64_t total_pause_ns = (*it)->GetTotalPausedTime();
+      const uint64_t total_pause_ns = (*it)->GetTotalPausedTimeNs();
       double seconds = NsToMs(logger.GetTotalNs()) / 1000.0;
       const uint64_t freed_bytes = collector->GetTotalFreedBytes();
       const uint64_t freed_objects = collector->GetTotalFreedObjects();
@@ -407,15 +420,15 @@
     }
   }
   uint64_t allocation_time = static_cast<uint64_t>(total_allocation_time_) * kTimeAdjust;
-  size_t total_objects_allocated = GetTotalObjectsAllocated();
-  size_t total_bytes_allocated = GetTotalBytesAllocated();
+  size_t total_objects_allocated = GetObjectsAllocatedEver();
+  size_t total_bytes_allocated = GetBytesAllocatedEver();
   if (total_duration != 0) {
     const double total_seconds = double(total_duration / 1000) / 1000000.0;
     os << "Total time spent in GC: " << PrettyDuration(total_duration) << "\n";
     os << "Mean GC size throughput: "
-       << PrettySize(GetTotalBytesFreed() / total_seconds) << "/s\n";
+       << PrettySize(GetBytesFreedEver() / total_seconds) << "/s\n";
     os << "Mean GC object throughput: "
-       << (GetTotalObjectsFreed() / total_seconds) << " objects/s\n";
+       << (GetObjectsFreedEver() / total_seconds) << " objects/s\n";
   }
   os << "Total number of allocations: " << total_objects_allocated << "\n";
   os << "Total bytes allocated " << PrettySize(total_bytes_allocated) << "\n";
@@ -444,24 +457,54 @@
   // heap lock held. We know though that no non-daemon threads are executing, and we know that
   // all daemon threads are suspended, and we also know that the threads list have been deleted, so
   // those threads can't resume. We're the only running thread, and we can do whatever we like...
-  STLDeleteElements(&spaces_);
+  STLDeleteElements(&continuous_spaces_);
+  STLDeleteElements(&discontinuous_spaces_);
   delete gc_complete_lock_;
+  delete reference_queue_lock_;
 }
 
-ContinuousSpace* Heap::FindSpaceFromObject(const mirror::Object* obj) const {
+space::ContinuousSpace* Heap::FindContinuousSpaceFromObject(const mirror::Object* obj,
+                                                            bool fail_ok) const {
   // TODO: C++0x auto
-  for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
     if ((*it)->Contains(obj)) {
       return *it;
     }
   }
-  LOG(FATAL) << "object " << reinterpret_cast<const void*>(obj) << " not inside any spaces!";
+  if (!fail_ok) {
+    LOG(FATAL) << "object " << reinterpret_cast<const void*>(obj) << " not inside any spaces!";
+  }
   return NULL;
 }
 
-ImageSpace* Heap::GetImageSpace() {
+space::DiscontinuousSpace* Heap::FindDiscontinuousSpaceFromObject(const mirror::Object* obj,
+                                                                  bool fail_ok) const {
   // TODO: C++0x auto
-  for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
+  typedef std::vector<space::DiscontinuousSpace*>::const_iterator It;
+  for (It it = discontinuous_spaces_.begin(), end = discontinuous_spaces_.end(); it != end; ++it) {
+    if ((*it)->Contains(obj)) {
+      return *it;
+    }
+  }
+  if (!fail_ok) {
+    LOG(FATAL) << "object " << reinterpret_cast<const void*>(obj) << " not inside any spaces!";
+  }
+  return NULL;
+}
+
+space::Space* Heap::FindSpaceFromObject(const mirror::Object* obj, bool fail_ok) const {
+  space::Space* result = FindContinuousSpaceFromObject(obj, true);
+  if (result != NULL) {
+    return result;
+  }
+  return FindDiscontinuousSpaceFromObject(obj, true);
+}
+
+space::ImageSpace* Heap::GetImageSpace() const {
+  // TODO: C++0x auto
+  typedef std::vector<space::ContinuousSpace*>::const_iterator It;
+  for (It it = continuous_spaces_.begin(), end = continuous_spaces_.end(); it != end; ++it) {
     if ((*it)->IsImageSpace()) {
       return (*it)->AsImageSpace();
     }
@@ -469,10 +512,6 @@
   return NULL;
 }
 
-DlMallocSpace* Heap::GetAllocSpace() {
-  return alloc_space_;
-}
-
 static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
   size_t chunk_size = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start);
   if (used_bytes < chunk_size) {
@@ -501,17 +540,17 @@
   // range. This also means that we rely on SetClass not dirtying the object's card.
   if (byte_count >= large_object_threshold_ && have_zygote_space_ && c->IsPrimitiveArray()) {
     size = RoundUp(byte_count, kPageSize);
-    obj = Allocate(self, large_object_space_.get(), size);
+    obj = Allocate(self, large_object_space_, size);
     // Make sure that our large object didn't get placed anywhere within the space interval or else
     // it breaks the immune range.
     DCHECK(obj == NULL ||
-           reinterpret_cast<byte*>(obj) < spaces_.front()->Begin() ||
-           reinterpret_cast<byte*>(obj) >= spaces_.back()->End());
+           reinterpret_cast<byte*>(obj) < continuous_spaces_.front()->Begin() ||
+           reinterpret_cast<byte*>(obj) >= continuous_spaces_.back()->End());
   } else {
     obj = Allocate(self, alloc_space_, byte_count);
 
     // Ensure that we did not allocate into a zygote space.
-    DCHECK(obj == NULL || !have_zygote_space_ || !FindSpaceFromObject(obj)->IsZygoteSpace());
+    DCHECK(obj == NULL || !have_zygote_space_ || !FindSpaceFromObject(obj, false)->IsZygoteSpace());
     size = alloc_space_->AllocationSize(obj);
   }
 
@@ -543,8 +582,8 @@
   }
   std::ostringstream oss;
   int64_t total_bytes_free = GetFreeMemory();
-  uint64_t alloc_space_size = alloc_space_->GetNumBytesAllocated();
-  uint64_t large_object_size = large_object_space_->GetNumObjectsAllocated();
+  uint64_t alloc_space_size = alloc_space_->GetBytesAllocated();
+  uint64_t large_object_size = large_object_space_->GetObjectsAllocated();
   oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
       << " free bytes; allocation space size " << alloc_space_size
       << "; large object space size " << large_object_size;
@@ -552,9 +591,11 @@
   if (total_bytes_free >= byte_count) {
     size_t max_contiguous_allocation = 0;
     // TODO: C++0x auto
-    for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-      if ((*it)->IsAllocSpace()) {
-        (*it)->AsAllocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
+    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->IsDlMallocSpace()) {
+        space->AsDlMallocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
       }
     }
     oss << "; failed due to fragmentation (largest possible contiguous allocation "
@@ -570,20 +611,41 @@
   if (obj == NULL) {
     return true;
   }
-  if (!IsAligned<kObjectAlignment>(obj)) {
+  if (UNLIKELY(!IsAligned<kObjectAlignment>(obj))) {
     return false;
   }
-  for (size_t i = 0; i < spaces_.size(); ++i) {
-    if (spaces_[i]->Contains(obj)) {
-      return true;
-    }
-  }
-  return large_object_space_->Contains(obj);
+  return FindSpaceFromObject(obj, true) != NULL;
 }
 
 bool Heap::IsLiveObjectLocked(const mirror::Object* obj) {
-  Locks::heap_bitmap_lock_->AssertReaderHeld(Thread::Current());
-  return IsHeapAddress(obj) && GetLiveBitmap()->Test(obj);
+  //Locks::heap_bitmap_lock_->AssertReaderHeld(Thread::Current());
+  if (obj == NULL) {
+    return false;
+  }
+  if (UNLIKELY(!IsAligned<kObjectAlignment>(obj))) {
+    return false;
+  }
+  space::ContinuousSpace* cont_space = FindContinuousSpaceFromObject(obj, true);
+  if (cont_space != NULL) {
+    if (cont_space->GetLiveBitmap()->Test(obj)) {
+      return true;
+    }
+  } else {
+    space::DiscontinuousSpace* disc_space = FindDiscontinuousSpaceFromObject(obj, true);
+    if (disc_space != NULL) {
+      if (disc_space->GetLiveObjects()->Test(obj)) {
+        return true;
+      }
+    }
+  }
+  for (size_t i = 0; i < 5; ++i) {
+    if (allocation_stack_->Contains(const_cast<mirror::Object*>(obj)) ||
+        live_stack_->Contains(const_cast<mirror::Object*>(obj))) {
+      return true;
+    }
+    NanoSleep(MsToNs(10));
+  }
+  return false;
 }
 
 void Heap::VerifyObjectImpl(const mirror::Object* obj) {
@@ -596,16 +658,19 @@
 
 void Heap::DumpSpaces() {
   // TODO: C++0x auto
-  for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    ContinuousSpace* space = *it;
-    SpaceBitmap* live_bitmap = space->GetLiveBitmap();
-    SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
+  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;
+    accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
+    accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
     LOG(INFO) << space << " " << *space << "\n"
               << live_bitmap << " " << *live_bitmap << "\n"
               << mark_bitmap << " " << *mark_bitmap;
   }
-  if (large_object_space_.get() != NULL) {
-    large_object_space_->Dump(LOG(INFO));
+  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;
+    LOG(INFO) << space << " " << *space << "\n";
   }
 }
 
@@ -636,18 +701,11 @@
   if (verify_object_mode_ != kVerifyAllFast) {
     // TODO: the bitmap tests below are racy if VerifyObjectBody is called without the
     //       heap_bitmap_lock_.
-    if (!GetLiveBitmap()->Test(obj)) {
-      // Check the allocation stack / live stack.
-      if (!std::binary_search(live_stack_->Begin(), live_stack_->End(), obj) &&
-          std::find(allocation_stack_->Begin(), allocation_stack_->End(), obj) ==
-              allocation_stack_->End()) {
-        if (large_object_space_->GetLiveObjects()->Test(obj)) {
-          DumpSpaces();
-          LOG(FATAL) << "Object is dead: " << obj;
-        }
-      }
+    if (!IsLiveObjectLocked(obj)) {
+      DumpSpaces();
+      LOG(FATAL) << "Object is dead: " << obj;
     }
-    if (!GetLiveBitmap()->Test(c)) {
+    if (!IsLiveObjectLocked(c)) {
       LOG(FATAL) << "Class of object is dead: " << c << " in object: " << obj;
     }
   }
@@ -682,7 +740,7 @@
   // This is safe to do since the GC will never free objects which are neither in the allocation
   // stack or the live bitmap.
   while (!allocation_stack_->AtomicPushBack(obj)) {
-    CollectGarbageInternal(kGcTypeSticky, kGcCauseForAlloc, false);
+    CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
   }
 }
 
@@ -702,7 +760,8 @@
   }
 }
 
-mirror::Object* Heap::TryToAllocate(Thread* self, AllocSpace* space, size_t alloc_size, bool grow) {
+mirror::Object* Heap::TryToAllocate(Thread* self, space::AllocSpace* space, size_t alloc_size,
+                                    bool grow) {
   // Should we try to use a CAS here and fix up num_bytes_allocated_ later with AllocationSize?
   if (num_bytes_allocated_ + alloc_size > max_allowed_footprint_) {
     // max_allowed_footprint_ <= growth_limit_ so it is safe to check in here.
@@ -710,23 +769,12 @@
       // Completely out of memory.
       return NULL;
     }
-
-    if (enforce_heap_growth_rate_) {
-      if (grow) {
-        // Grow the heap by alloc_size extra bytes.
-        max_allowed_footprint_ = std::min(max_allowed_footprint_ + alloc_size, growth_limit_);
-        VLOG(gc) << "Grow heap to " << PrettySize(max_allowed_footprint_)
-                 << " for a " << PrettySize(alloc_size) << " allocation";
-      } else {
-        return NULL;
-      }
-    }
   }
 
   return space->Alloc(self, alloc_size);
 }
 
-mirror::Object* Heap::Allocate(Thread* self, AllocSpace* space, size_t alloc_size) {
+mirror::Object* Heap::Allocate(Thread* self, space::AllocSpace* space, size_t alloc_size) {
   // Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
   // done in the runnable state where suspension is expected.
   DCHECK_EQ(self->GetState(), kRunnable);
@@ -739,8 +787,8 @@
 
   // The allocation failed. If the GC is running, block until it completes, and then retry the
   // allocation.
-  GcType last_gc = WaitForConcurrentGcToComplete(self);
-  if (last_gc != kGcTypeNone) {
+  collector::GcType last_gc = WaitForConcurrentGcToComplete(self);
+  if (last_gc != collector::kGcTypeNone) {
     // A GC was in progress and we blocked, retry allocation now that memory has been freed.
     ptr = TryToAllocate(self, space, alloc_size, false);
     if (ptr != NULL) {
@@ -749,20 +797,21 @@
   }
 
   // Loop through our different Gc types and try to Gc until we get enough free memory.
-  for (size_t i = static_cast<size_t>(last_gc) + 1; i < static_cast<size_t>(kGcTypeMax); ++i) {
+  for (size_t i = static_cast<size_t>(last_gc) + 1;
+      i < static_cast<size_t>(collector::kGcTypeMax); ++i) {
     bool run_gc = false;
-    GcType gc_type = static_cast<GcType>(i);
+    collector::GcType gc_type = static_cast<collector::GcType>(i);
     switch (gc_type) {
-      case kGcTypeSticky: {
+      case collector::kGcTypeSticky: {
           const size_t alloc_space_size = alloc_space_->Size();
           run_gc = alloc_space_size > min_alloc_space_size_for_sticky_gc_ &&
               alloc_space_->Capacity() - alloc_space_size >= min_remaining_space_for_sticky_gc_;
           break;
         }
-      case kGcTypePartial:
+      case collector::kGcTypePartial:
         run_gc = have_zygote_space_;
         break;
-      case kGcTypeFull:
+      case collector::kGcTypeFull:
         run_gc = true;
         break;
       default:
@@ -771,7 +820,7 @@
 
     if (run_gc) {
       // If we actually ran a different type of Gc than requested, we can skip the index forwards.
-      GcType gc_type_ran = CollectGarbageInternal(gc_type, kGcCauseForAlloc, false);
+      collector::GcType gc_type_ran = CollectGarbageInternal(gc_type, kGcCauseForAlloc, false);
       DCHECK_GE(static_cast<size_t>(gc_type_ran), i);
       i = static_cast<size_t>(gc_type_ran);
 
@@ -799,7 +848,7 @@
            << " allocation";
 
   // We don't need a WaitForConcurrentGcToComplete here either.
-  CollectGarbageInternal(kGcTypeFull, kGcCauseForAlloc, true);
+  CollectGarbageInternal(collector::kGcTypeFull, kGcCauseForAlloc, true);
   return TryToAllocate(self, space, alloc_size, true);
 }
 
@@ -809,45 +858,54 @@
   target_utilization_ = target;
 }
 
-int64_t Heap::GetMaxMemory() const {
-  return growth_limit_;
-}
-
-int64_t Heap::GetTotalMemory() const {
-  return GetMaxMemory();
-}
-
-int64_t Heap::GetFreeMemory() const {
-  return GetMaxMemory() - num_bytes_allocated_;
-}
-
-size_t Heap::GetTotalBytesFreed() const {
-  return total_bytes_freed_;
-}
-
-size_t Heap::GetTotalObjectsFreed() const {
-  return total_objects_freed_;
-}
-
-size_t Heap::GetTotalObjectsAllocated() const {
-  size_t total = large_object_space_->GetTotalObjectsAllocated();
-  for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    Space* space = *it;
-    if (space->IsAllocSpace()) {
-      total += space->AsAllocSpace()->GetTotalObjectsAllocated();
+size_t Heap::GetObjectsAllocated() const {
+  size_t total = 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->IsDlMallocSpace()) {
+      total += space->AsDlMallocSpace()->GetObjectsAllocated();
     }
   }
+  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;
+    total += space->AsLargeObjectSpace()->GetObjectsAllocated();
+  }
   return total;
 }
 
-size_t Heap::GetTotalBytesAllocated() const {
-  size_t total = large_object_space_->GetTotalBytesAllocated();
-  for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    Space* space = *it;
-    if (space->IsAllocSpace()) {
-      total += space->AsAllocSpace()->GetTotalBytesAllocated();
+size_t Heap::GetObjectsAllocatedEver() const {
+  size_t total = 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->IsDlMallocSpace()) {
+      total += space->AsDlMallocSpace()->GetTotalObjectsAllocated();
     }
   }
+  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;
+    total += space->AsLargeObjectSpace()->GetTotalObjectsAllocated();
+  }
+  return total;
+}
+
+size_t Heap::GetBytesAllocatedEver() const {
+  size_t total = 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->IsDlMallocSpace()) {
+      total += space->AsDlMallocSpace()->GetTotalBytesAllocated();
+    }
+  }
+  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;
+    total += space->AsLargeObjectSpace()->GetTotalBytesAllocated();
+  }
   return total;
 }
 
@@ -945,7 +1003,7 @@
   // TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for
   // annotalysis on visitors.
   void operator()(const mirror::Object* o) const NO_THREAD_SAFETY_ANALYSIS {
-    MarkSweep::VisitObjectReferences(o, *this);
+    collector::MarkSweep::VisitObjectReferences(o, *this);
   }
 
   // For MarkSweep::VisitObjectReferences.
@@ -983,7 +1041,7 @@
   // last GC will not have necessarily been cleared.
   Thread* self = Thread::Current();
   WaitForConcurrentGcToComplete(self);
-  CollectGarbageInternal(kGcTypeFull, kGcCauseExplicit, clear_soft_references);
+  CollectGarbageInternal(collector::kGcTypeFull, kGcCauseExplicit, clear_soft_references);
 }
 
 void Heap::PreZygoteFork() {
@@ -1006,29 +1064,22 @@
     FlushAllocStack();
   }
 
-  // Replace the first alloc space we find with a zygote space.
-  // TODO: C++0x auto
-  for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    if ((*it)->IsAllocSpace()) {
-      DlMallocSpace* zygote_space = (*it)->AsAllocSpace();
+  // 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_->SetFootprintLimit(alloc_space_->Capacity());
 
-      // Turns the current alloc space into a Zygote space and obtain the new alloc space composed
-      // of the remaining available heap memory.
-      alloc_space_ = zygote_space->CreateZygoteSpace();
-      alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
-
-      // Change the GC retention policy of the zygote space to only collect when full.
-      zygote_space->SetGcRetentionPolicy(kGcRetentionPolicyFullCollect);
-      AddSpace(alloc_space_);
-      have_zygote_space_ = true;
-      break;
-    }
-  }
+  // Change the GC retention policy of the zygote space to only collect when full.
+  zygote_space->SetGcRetentionPolicy(space::kGcRetentionPolicyFullCollect);
+  AddContinuousSpace(alloc_space_);
+  have_zygote_space_ = true;
 
   // Reset the cumulative loggers since we now have a few additional timing phases.
   // TODO: C++0x
-  for (Collectors::const_iterator it = mark_sweep_collectors_.begin();
-        it != mark_sweep_collectors_.end(); ++it) {
+  typedef std::vector<collector::MarkSweep*>::const_iterator It;
+  for (It it = mark_sweep_collectors_.begin(), end = mark_sweep_collectors_.end();
+      it != end; ++it) {
     (*it)->ResetCumulativeStatistics();
   }
 }
@@ -1039,11 +1090,8 @@
   allocation_stack_->Reset();
 }
 
-size_t Heap::GetUsedMemorySize() const {
-  return num_bytes_allocated_;
-}
-
-void Heap::MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) {
+void Heap::MarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+                          accounting::ObjectStack* stack) {
   mirror::Object** limit = stack->End();
   for (mirror::Object** it = stack->Begin(); it != limit; ++it) {
     const mirror::Object* obj = *it;
@@ -1056,7 +1104,8 @@
   }
 }
 
-void Heap::UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack) {
+void Heap::UnMarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+                            accounting::ObjectStack* stack) {
   mirror::Object** limit = stack->End();
   for (mirror::Object** it = stack->Begin(); it != limit; ++it) {
     const mirror::Object* obj = *it;
@@ -1069,7 +1118,8 @@
   }
 }
 
-GcType Heap::CollectGarbageInternal(GcType gc_type, GcCause gc_cause, bool clear_soft_references) {
+collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCause gc_cause,
+                                               bool clear_soft_references) {
   Thread* self = Thread::Current();
   ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
   Locks::mutator_lock_->AssertNotHeld(self);
@@ -1103,31 +1153,37 @@
 
   // We need to do partial GCs every now and then to avoid the heap growing too much and
   // fragmenting.
-  if (gc_type == kGcTypeSticky && ++sticky_gc_count_ > partial_gc_frequency_) {
-    gc_type = have_zygote_space_ ? kGcTypePartial : kGcTypeFull;
-  }
-  if (gc_type != kGcTypeSticky) {
+  // TODO: if sticky GCs are failing to free memory then we should lower the
+  // sticky_to_partial_gc_ratio_, if they are successful we can increase it.
+  if (gc_type == collector::kGcTypeSticky) {
+    ++sticky_gc_count_;
+    if (sticky_gc_count_ >= sticky_to_partial_gc_ratio_) {
+      gc_type = have_zygote_space_ ? collector::kGcTypePartial : collector::kGcTypeFull;
+      sticky_gc_count_ = 0;
+    }
+  } else {
     sticky_gc_count_ = 0;
   }
 
-  uint64_t gc_start_time = NanoTime();
+  uint64_t gc_start_time_ns = NanoTime();
   uint64_t gc_start_size = GetBytesAllocated();
   // Approximate allocation rate in bytes / second.
-  if (UNLIKELY(gc_start_time == last_gc_time_)) {
+  if (UNLIKELY(gc_start_time_ns == last_gc_time_ns_)) {
     LOG(WARNING) << "Timers are broken (gc_start_time == last_gc_time_).";
   }
-  uint64_t ms_delta = NsToMs(gc_start_time - last_gc_time_);
+  uint64_t ms_delta = NsToMs(gc_start_time_ns - last_gc_time_ns_);
   if (ms_delta != 0) {
-    allocation_rate_ = (gc_start_size - last_gc_size_) * 1000 / ms_delta;
+    allocation_rate_ = ((gc_start_size - last_gc_size_) * 1000) / ms_delta;
     VLOG(heap) << "Allocation rate: " << PrettySize(allocation_rate_) << "/s";
   }
 
-  DCHECK_LT(gc_type, kGcTypeMax);
-  DCHECK_NE(gc_type, kGcTypeNone);
-  MarkSweep* collector = NULL;
-  for (Collectors::iterator it = mark_sweep_collectors_.begin();
-      it != mark_sweep_collectors_.end(); ++it) {
-    MarkSweep* cur_collector = *it;
+  DCHECK_LT(gc_type, collector::kGcTypeMax);
+  DCHECK_NE(gc_type, collector::kGcTypeNone);
+  collector::MarkSweep* collector = NULL;
+  typedef std::vector<collector::MarkSweep*>::iterator It;
+  for (It it = mark_sweep_collectors_.begin(), end = mark_sweep_collectors_.end();
+      it != end; ++it) {
+    collector::MarkSweep* cur_collector = *it;
     if (cur_collector->IsConcurrent() == concurrent_gc_ && cur_collector->GetGcType() == gc_type) {
       collector = cur_collector;
       break;
@@ -1138,10 +1194,10 @@
       << " and type=" << gc_type;
   collector->clear_soft_references_ = clear_soft_references;
   collector->Run();
-  total_objects_freed_ += collector->GetFreedObjects();
-  total_bytes_freed_ += collector->GetFreedBytes();
+  total_objects_freed_ever_ += collector->GetFreedObjects();
+  total_bytes_freed_ever_ += collector->GetFreedBytes();
 
-  const size_t duration = collector->GetDuration();
+  const size_t duration = collector->GetDurationNs();
   std::vector<uint64_t> pauses = collector->GetPauseTimes();
   bool was_slow = duration > kSlowGcThreshold ||
       (gc_cause == kGcCauseForAlloc && duration > kLongGcPauseThreshold);
@@ -1153,7 +1209,7 @@
 
   if (was_slow) {
     const size_t percent_free = GetPercentFree();
-    const size_t current_heap_size = GetUsedMemorySize();
+    const size_t current_heap_size = GetBytesAllocated();
     const size_t total_memory = GetTotalMemory();
     std::ostringstream pause_string;
     for (size_t i = 0; i < pauses.size(); ++i) {
@@ -1166,7 +1222,7 @@
               << PrettySize(total_memory) << ", " << "paused " << pause_string.str()
               << " total " << PrettyDuration((duration / 1000) * 1000);
     if (VLOG_IS_ON(heap)) {
-      LOG(INFO) << Dumpable<TimingLogger>(collector->GetTimings());
+      LOG(INFO) << Dumpable<base::NewTimingLogger>(collector->GetTimings());
     }
   }
 
@@ -1182,32 +1238,33 @@
   return gc_type;
 }
 
-void Heap::UpdateAndMarkModUnion(MarkSweep* mark_sweep, TimingLogger& timings, GcType gc_type) {
-  if (gc_type == kGcTypeSticky) {
+void Heap::UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& 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
     // cards.
     return;
   }
 
   // Update zygote mod union table.
-  if (gc_type == kGcTypePartial) {
+  if (gc_type == collector::kGcTypePartial) {
+    timings.NewSplit("UpdateZygoteModUnionTable");
     zygote_mod_union_table_->Update();
-    timings.AddSplit("UpdateZygoteModUnionTable");
 
+    timings.NewSplit("ZygoteMarkReferences");
     zygote_mod_union_table_->MarkReferences(mark_sweep);
-    timings.AddSplit("ZygoteMarkReferences");
   }
 
   // Processes the cards we cleared earlier and adds their objects into the mod-union table.
-  mod_union_table_->Update();
-  timings.AddSplit("UpdateModUnionTable");
+  timings.NewSplit("UpdateModUnionTable");
+  image_mod_union_table_->Update();
 
   // Scans all objects in the mod-union table.
-  mod_union_table_->MarkReferences(mark_sweep);
-  timings.AddSplit("MarkImageToAllocSpaceReferences");
+  timings.NewSplit("MarkImageToAllocSpaceReferences");
+  image_mod_union_table_->MarkReferences(mark_sweep);
 }
 
-void Heap::RootMatchesObjectVisitor(const mirror::Object* root, void* arg) {
+static void RootMatchesObjectVisitor(const mirror::Object* root, void* arg) {
   mirror::Object* obj = reinterpret_cast<mirror::Object*>(arg);
   if (root == obj) {
     LOG(INFO) << "Object " << obj << " is a root";
@@ -1221,94 +1278,109 @@
   }
 };
 
+// Verify a reference from an object.
 class VerifyReferenceVisitor {
  public:
-  VerifyReferenceVisitor(Heap* heap, bool* failed)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
-                            Locks::heap_bitmap_lock_)
-      : heap_(heap),
-        failed_(failed) {
+  VerifyReferenceVisitor(Heap* heap)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_)
+      : heap_(heap), failed_(false) {
+  }
+
+  bool Failed() const {
+    return failed_;
   }
 
   // TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for smarter
-  // analysis.
+  // analysis on visitors.
   void operator ()(const mirror::Object* obj, const mirror::Object* ref,
-                   const MemberOffset& /* offset */, bool /* is_static */) const
+                   const MemberOffset& offset, bool /* is_static */) const
       NO_THREAD_SAFETY_ANALYSIS {
     // Verify that the reference is live.
-    if (ref != NULL && !IsLive(ref)) {
-      CardTable* card_table = heap_->GetCardTable();
-      ObjectStack* alloc_stack = heap_->allocation_stack_.get();
-      ObjectStack* live_stack = heap_->live_stack_.get();
+    if (UNLIKELY(ref != NULL && !IsLive(ref))) {
+      accounting::CardTable* card_table = heap_->GetCardTable();
+      accounting::ObjectStack* alloc_stack = heap_->allocation_stack_.get();
+      accounting::ObjectStack* live_stack = heap_->live_stack_.get();
 
-      byte* card_addr = card_table->CardFromAddr(obj);
-      LOG(ERROR) << "Object " << obj << " references dead object " << ref << "\n"
-                 << "IsDirty = " << (*card_addr == CardTable::kCardDirty) << "\n"
-                 << "Obj type " << PrettyTypeOf(obj) << "\n"
-                 << "Ref type " << PrettyTypeOf(ref);
-      card_table->CheckAddrIsInCardTable(reinterpret_cast<const byte*>(obj));
-      void* cover_begin = card_table->AddrFromCard(card_addr);
-      void* cover_end = reinterpret_cast<void*>(reinterpret_cast<size_t>(cover_begin) +
-          CardTable::kCardSize);
-      LOG(ERROR) << "Card " << reinterpret_cast<void*>(card_addr) << " covers " << cover_begin
-                 << "-" << cover_end;
-      SpaceBitmap* bitmap = heap_->GetLiveBitmap()->GetSpaceBitmap(obj);
+      if (obj != NULL) {
+        byte* card_addr = card_table->CardFromAddr(obj);
+        LOG(ERROR) << "Object " << obj << " references dead object " << ref << " at offset " << offset
+                   << "\nIsDirty = " << (*card_addr == accounting::CardTable::kCardDirty)
+                   << "\nObj type " << PrettyTypeOf(obj)
+                   << "\nRef type " << PrettyTypeOf(ref);
+        card_table->CheckAddrIsInCardTable(reinterpret_cast<const byte*>(obj));
+        void* cover_begin = card_table->AddrFromCard(card_addr);
+        void* cover_end = reinterpret_cast<void*>(reinterpret_cast<size_t>(cover_begin) +
+            accounting::CardTable::kCardSize);
+        LOG(ERROR) << "Card " << reinterpret_cast<void*>(card_addr) << " covers " << cover_begin
+            << "-" << cover_end;
+        accounting::SpaceBitmap* bitmap = heap_->GetLiveBitmap()->GetContinuousSpaceBitmap(obj);
 
-      // Print out how the object is live.
-      if (bitmap->Test(obj)) {
-        LOG(ERROR) << "Object " << obj << " found in live bitmap";
+        // Print out how the object is live.
+        if (bitmap != NULL && bitmap->Test(obj)) {
+          LOG(ERROR) << "Object " << obj << " found in live bitmap";
+        }
+        if (alloc_stack->Contains(const_cast<mirror::Object*>(obj))) {
+          LOG(ERROR) << "Object " << obj << " found in allocation stack";
+        }
+        if (live_stack->Contains(const_cast<mirror::Object*>(obj))) {
+          LOG(ERROR) << "Object " << obj << " found in live stack";
+        }
+        // Attempt to see if the card table missed the reference.
+        ScanVisitor scan_visitor;
+        byte* byte_cover_begin = reinterpret_cast<byte*>(card_table->AddrFromCard(card_addr));
+        card_table->Scan(bitmap, byte_cover_begin,
+                         byte_cover_begin + accounting::CardTable::kCardSize,
+                         scan_visitor, VoidFunctor());
+
+        // Search to see if any of the roots reference our object.
+        void* arg = const_cast<void*>(reinterpret_cast<const void*>(obj));
+        Runtime::Current()->VisitRoots(&RootMatchesObjectVisitor, arg, false, false);
+
+        // Search to see if any of the roots reference our reference.
+        arg = const_cast<void*>(reinterpret_cast<const void*>(ref));
+        Runtime::Current()->VisitRoots(&RootMatchesObjectVisitor, arg, false, false);
+      } else {
+        LOG(ERROR) << "Root references dead object " << ref << "\nRef type " << PrettyTypeOf(ref);
       }
-      if (std::binary_search(alloc_stack->Begin(), alloc_stack->End(), obj)) {
-        LOG(ERROR) << "Object " << obj << " found in allocation stack";
+      if (alloc_stack->Contains(const_cast<mirror::Object*>(ref))) {
+        LOG(ERROR) << "Reference " << ref << " found in allocation stack!";
       }
-      if (std::binary_search(live_stack->Begin(), live_stack->End(), obj)) {
-        LOG(ERROR) << "Object " << obj << " found in live stack";
-      }
-      if (std::binary_search(live_stack->Begin(), live_stack->End(), ref)) {
+      if (live_stack->Contains(const_cast<mirror::Object*>(ref))) {
         LOG(ERROR) << "Reference " << ref << " found in live stack!";
       }
-
-      // Attempt to see if the card table missed the reference.
-      ScanVisitor scan_visitor;
-      byte* byte_cover_begin = reinterpret_cast<byte*>(card_table->AddrFromCard(card_addr));
-      card_table->Scan(bitmap, byte_cover_begin, byte_cover_begin + CardTable::kCardSize,
-                       scan_visitor, VoidFunctor());
-
-      // Search to see if any of the roots reference our object.
-      void* arg = const_cast<void*>(reinterpret_cast<const void*>(obj));
-      Runtime::Current()->VisitRoots(&Heap::RootMatchesObjectVisitor, arg);
-      *failed_ = true;
+      heap_->image_mod_union_table_->Dump(LOG(ERROR) << "Image mod-union table: ");
+      heap_->zygote_mod_union_table_->Dump(LOG(ERROR) << "Zygote mod-union table: ");
+      failed_ = true;
     }
   }
 
   bool IsLive(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
-    if (heap_->GetLiveBitmap()->Test(obj)) {
-      return true;
-    }
-    ObjectStack* alloc_stack = heap_->allocation_stack_.get();
-    // At this point we need to search the allocation since things in the live stack may get swept.
-    // If the object is not either in the live bitmap or allocation stack, so the object must be
-    // dead.
-    return std::binary_search(alloc_stack->Begin(), alloc_stack->End(), obj);
+    return heap_->IsLiveObjectLocked(obj);
+  }
+
+  static void VerifyRoots(const mirror::Object* root, void* arg) {
+    VerifyReferenceVisitor* visitor = reinterpret_cast<VerifyReferenceVisitor*>(arg);
+    (*visitor)(NULL, root, MemberOffset(0), true);
   }
 
  private:
-  Heap* heap_;
-  bool* failed_;
+  Heap* const heap_;
+  mutable bool failed_;
 };
 
+// Verify all references within an object, for use with HeapBitmap::Visit.
 class VerifyObjectVisitor {
  public:
-  VerifyObjectVisitor(Heap* heap)
-      : heap_(heap),
-        failed_(false) {
-
+  VerifyObjectVisitor(Heap* heap) : heap_(heap), failed_(false) {
   }
 
   void operator ()(const mirror::Object* obj) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
-    VerifyReferenceVisitor visitor(heap_, const_cast<bool*>(&failed_));
-    MarkSweep::VisitObjectReferences(obj, visitor);
+    // Note: we are verifying the references in obj but not obj itself, this is because obj must
+    // be live or else how did we find it in the live bitmap?
+    VerifyReferenceVisitor visitor(heap_);
+    collector::MarkSweep::VisitObjectReferences(obj, visitor);
+    failed_ = failed_ || visitor.Failed();
   }
 
   bool Failed() const {
@@ -1316,18 +1388,19 @@
   }
 
  private:
-  Heap* heap_;
-  bool failed_;
+  Heap* const heap_;
+  mutable bool failed_;
 };
 
 // Must do this with mutators suspended since we are directly accessing the allocation stacks.
 bool Heap::VerifyHeapReferences() {
   Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
   // Lets sort our allocation stacks so that we can efficiently binary search them.
-  std::sort(allocation_stack_->Begin(), allocation_stack_->End());
-  std::sort(live_stack_->Begin(), live_stack_->End());
+  allocation_stack_->Sort();
+  live_stack_->Sort();
   // Perform the verification.
   VerifyObjectVisitor visitor(this);
+  Runtime::Current()->VisitRoots(VerifyReferenceVisitor::VerifyRoots, &visitor, false, false);
   GetLiveBitmap()->Visit(visitor);
   // We don't want to verify the objects in the allocation stack since they themselves may be
   // pointing to dead objects if they are not reachable.
@@ -1343,8 +1416,7 @@
   VerifyReferenceCardVisitor(Heap* heap, bool* failed)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
                             Locks::heap_bitmap_lock_)
-      : heap_(heap),
-        failed_(failed) {
+      : heap_(heap), failed_(failed) {
   }
 
   // TODO: Fix lock analysis to not use NO_THREAD_SAFETY_ANALYSIS, requires support for
@@ -1354,7 +1426,7 @@
     // Filter out class references since changing an object's class does not mark the card as dirty.
     // Also handles large objects, since the only reference they hold is a class reference.
     if (ref != NULL && !ref->IsClass()) {
-      CardTable* card_table = heap_->GetCardTable();
+      accounting::CardTable* card_table = heap_->GetCardTable();
       // If the object is not dirty and it is referencing something in the live stack other than
       // class, then it must be on a dirty card.
       if (!card_table->AddrIsInCardTable(obj)) {
@@ -1363,9 +1435,9 @@
       } else if (!card_table->IsDirty(obj)) {
         // Card should be either kCardDirty if it got re-dirtied after we aged it, or
         // kCardDirty - 1 if it didnt get touched since we aged it.
-        ObjectStack* live_stack = heap_->live_stack_.get();
-        if (std::binary_search(live_stack->Begin(), live_stack->End(), ref)) {
-          if (std::binary_search(live_stack->Begin(), live_stack->End(), obj)) {
+        accounting::ObjectStack* live_stack = heap_->live_stack_.get();
+        if (live_stack->Contains(const_cast<mirror::Object*>(ref))) {
+          if (live_stack->Contains(const_cast<mirror::Object*>(obj))) {
             LOG(ERROR) << "Object " << obj << " found in live stack";
           }
           if (heap_->GetLiveBitmap()->Test(obj)) {
@@ -1406,8 +1478,8 @@
   }
 
  private:
-  Heap* heap_;
-  bool* failed_;
+  Heap* const heap_;
+  bool* const failed_;
 };
 
 class VerifyLiveStackReferences {
@@ -1421,7 +1493,7 @@
   void operator ()(const mirror::Object* obj) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
     VerifyReferenceCardVisitor visitor(heap_, const_cast<bool*>(&failed_));
-    MarkSweep::VisitObjectReferences(obj, visitor);
+    collector::MarkSweep::VisitObjectReferences(obj, visitor);
   }
 
   bool Failed() const {
@@ -1429,7 +1501,7 @@
   }
 
  private:
-  Heap* heap_;
+  Heap* const heap_;
   bool failed_;
 };
 
@@ -1437,7 +1509,7 @@
   Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
 
   // We need to sort the live stack since we binary search it.
-  std::sort(live_stack_->Begin(), live_stack_->End());
+  live_stack_->Sort();
   VerifyLiveStackReferences visitor(this);
   GetLiveBitmap()->Visit(visitor);
 
@@ -1458,30 +1530,31 @@
 
   // Sort the live stack so that we can quickly binary search it later.
   if (verify_object_mode_ > kNoHeapVerification) {
-    std::sort(live_stack_->Begin(), live_stack_->End());
+    live_stack_->Sort();
   }
 }
 
-void Heap::ProcessCards(TimingLogger& timings) {
-  // Clear image space cards and keep track of cards we cleared in the mod-union table.
-  for (Spaces::iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    ContinuousSpace* space = *it;
+void Heap::ProcessCards(base::NewTimingLogger& 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) {
+    space::ContinuousSpace* space = *it;
     if (space->IsImageSpace()) {
-      mod_union_table_->ClearCards(*it);
-      timings.AddSplit("ModUnionClearCards");
-    } else if (space->GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) {
+      timings.NewSplit("ModUnionClearCards");
+      image_mod_union_table_->ClearCards(space);
+    } else if (space->IsZygoteSpace()) {
+      timings.NewSplit("ZygoteModUnionClearCards");
       zygote_mod_union_table_->ClearCards(space);
-      timings.AddSplit("ZygoteModUnionClearCards");
     } else {
       // No mod union table for the AllocSpace. Age the cards so that the GC knows that these cards
       // were dirty before the GC started.
+      timings.NewSplit("AllocSpaceClearCards");
       card_table_->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), VoidFunctor());
-      timings.AddSplit("AllocSpaceClearCards");
     }
   }
 }
 
-void Heap::PreGcVerification(GarbageCollector* gc) {
+void Heap::PreGcVerification(collector::GarbageCollector* gc) {
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   Thread* self = Thread::Current();
 
@@ -1516,43 +1589,48 @@
     ReaderMutexLock reader_lock(self, *Locks::heap_bitmap_lock_);
     zygote_mod_union_table_->Update();
     zygote_mod_union_table_->Verify();
-    mod_union_table_->Update();
-    mod_union_table_->Verify();
+    image_mod_union_table_->Update();
+    image_mod_union_table_->Verify();
     thread_list->ResumeAll();
   }
 }
 
-void Heap::PreSweepingGcVerification(GarbageCollector* gc) {
+void Heap::PreSweepingGcVerification(collector::GarbageCollector* gc) {
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
-  Thread* self = Thread::Current();
 
   // Called before sweeping occurs since we want to make sure we are not going so reclaim any
   // reachable objects.
   if (verify_post_gc_heap_) {
+    Thread* self = Thread::Current();
+    CHECK_NE(self->GetState(), kRunnable);
+    Locks::mutator_lock_->SharedUnlock(self);
     thread_list->SuspendAll();
-    WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    // Swapping bound bitmaps does nothing.
-    live_bitmap_.swap(mark_bitmap_);
-    if (!VerifyHeapReferences()) {
-      LOG(FATAL) << "Post " << gc->GetName() << "Gc verification failed";
+    {
+      WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+      // Swapping bound bitmaps does nothing.
+      gc->SwapBitmaps();
+      if (!VerifyHeapReferences()) {
+        LOG(FATAL) << "Post " << gc->GetName() << "GC verification failed";
+      }
+      gc->SwapBitmaps();
     }
-    live_bitmap_.swap(mark_bitmap_);
     thread_list->ResumeAll();
+    Locks::mutator_lock_->SharedLock(self);
   }
 }
 
-void Heap::PostGcVerification(GarbageCollector* gc) {
+void Heap::PostGcVerification(collector::GarbageCollector* gc) {
   Thread* self = Thread::Current();
 
   if (verify_system_weaks_) {
     ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-    MarkSweep* mark_sweep = down_cast<MarkSweep*>(gc);
+    collector::MarkSweep* mark_sweep = down_cast<collector::MarkSweep*>(gc);
     mark_sweep->VerifySystemWeaks();
   }
 }
 
-GcType Heap::WaitForConcurrentGcToComplete(Thread* self) {
-  GcType last_gc_type = kGcTypeNone;
+collector::GcType Heap::WaitForConcurrentGcToComplete(Thread* self) {
+  collector::GcType last_gc_type = collector::kGcTypeNone;
   if (concurrent_gc_) {
     bool do_wait;
     uint64_t wait_start = NanoTime();
@@ -1583,7 +1661,7 @@
 }
 
 void Heap::DumpForSigQuit(std::ostream& os) {
-  os << "Heap: " << GetPercentFree() << "% free, " << PrettySize(GetUsedMemorySize()) << "/"
+  os << "Heap: " << GetPercentFree() << "% free, " << PrettySize(GetBytesAllocated()) << "/"
      << PrettySize(GetTotalMemory()) << "; " << GetObjectsAllocated() << " objects\n";
   DumpGcPerformanceInfo(os);
 }
@@ -1606,7 +1684,7 @@
   // This doesn't actually resize any memory. It just lets the heap grow more when necessary.
   const size_t bytes_allocated = GetBytesAllocated();
   last_gc_size_ = bytes_allocated;
-  last_gc_time_ = NanoTime();
+  last_gc_time_ns_ = NanoTime();
 
   size_t target_size = bytes_allocated / GetTargetHeapUtilization();
   if (target_size > bytes_allocated + max_free_) {
@@ -1617,20 +1695,23 @@
 
   SetIdealFootprint(target_size);
 
-  // Calculate when to perform the next ConcurrentGC if we have enough free memory.
-  if (concurrent_gc_ && GetFreeMemory() >= concurrent_min_free_) {
+  // Calculate when to perform the next ConcurrentGC.
+  if (concurrent_gc_) {
     // Calculate the estimated GC duration.
     double gc_duration_seconds = NsToMs(gc_duration) / 1000.0;
     // Estimate how many remaining bytes we will have when we need to start the next GC.
     size_t remaining_bytes = allocation_rate_ * gc_duration_seconds;
-    if (remaining_bytes < max_allowed_footprint_) {
+    remaining_bytes = std::max(remaining_bytes, kMinConcurrentRemainingBytes);
+    if (UNLIKELY(remaining_bytes > max_allowed_footprint_)) {
+      // A never going to happen situation that from the estimated allocation rate we will exceed
+      // the applications entire footprint with the given estimated allocation rate. Schedule
+      // another GC straight away.
+      concurrent_start_bytes_ = bytes_allocated;
+    } else {
       // Start a concurrent GC when we get close to the estimated remaining bytes. When the
       // allocation rate is very high, remaining_bytes could tell us that we should start a GC
       // right away.
       concurrent_start_bytes_ = std::max(max_allowed_footprint_ - remaining_bytes, bytes_allocated);
-    } else {
-      // The estimated rate is so high that we should request another GC straight away.
-      concurrent_start_bytes_ = bytes_allocated;
     }
     DCHECK_LE(concurrent_start_bytes_, max_allowed_footprint_);
     DCHECK_LE(max_allowed_footprint_, growth_limit_);
@@ -1736,30 +1817,6 @@
       arg_array.GetArray(), arg_array.GetNumBytes(), &result, 'V');
 }
 
-size_t Heap::GetBytesAllocated() const {
-  return num_bytes_allocated_;
-}
-
-size_t Heap::GetObjectsAllocated() const {
-  size_t total = 0;
-  // TODO: C++0x
-  for (Spaces::const_iterator it = spaces_.begin(); it != spaces_.end(); ++it) {
-    Space* space = *it;
-    if (space->IsAllocSpace()) {
-      total += space->AsAllocSpace()->GetNumObjectsAllocated();
-    }
-  }
-  return total;
-}
-
-size_t Heap::GetConcurrentStartSize() const {
-  return concurrent_start_size_;
-}
-
-size_t Heap::GetConcurrentMinFree() const {
-  return concurrent_min_free_;
-}
-
 void Heap::EnqueueClearedReferences(mirror::Object** cleared) {
   DCHECK(cleared != NULL);
   if (*cleared != NULL) {
@@ -1811,11 +1868,11 @@
   }
 
   // Wait for any GCs currently running to finish.
-  if (WaitForConcurrentGcToComplete(self) == kGcTypeNone) {
+  if (WaitForConcurrentGcToComplete(self) == collector::kGcTypeNone) {
     if (alloc_space_->Size() > min_alloc_space_size_for_sticky_gc_) {
-      CollectGarbageInternal(kGcTypeSticky, kGcCauseBackground, false);
+      CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseBackground, false);
     } else {
-      CollectGarbageInternal(kGcTypePartial, kGcCauseBackground, false);
+      CollectGarbageInternal(collector::kGcTypePartial, kGcCauseBackground, false);
     }
   }
 }
@@ -1835,8 +1892,8 @@
   // not how much use we're making of those pages.
   uint64_t ms_time = MilliTime();
   float utilization =
-      static_cast<float>(alloc_space_->GetNumBytesAllocated()) / alloc_space_->Size();
-  if ((utilization > 0.75f) || ((ms_time - last_trim_time_) < 2 * 1000)) {
+      static_cast<float>(alloc_space_->GetBytesAllocated()) / alloc_space_->Size();
+  if ((utilization > 0.75f) || ((ms_time - last_trim_time_ms_) < 2 * 1000)) {
     // Don't bother trimming the alloc space if it's more than 75% utilized, or if a
     // heap trim occurred in the last two seconds.
     return;
@@ -1861,7 +1918,7 @@
     return;
   }
 
-  last_trim_time_ = ms_time;
+  last_trim_time_ms_ = ms_time;
   JNIEnv* env = self->GetJniEnv();
   DCHECK(WellKnownClasses::java_lang_Daemons != NULL);
   DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL);
@@ -1875,4 +1932,5 @@
   return alloc_space_->Trim();
 }
 
+}  // namespace gc
 }  // namespace art
diff --git a/src/heap.h b/src/gc/heap.h
similarity index 66%
rename from src/heap.h
rename to src/gc/heap.h
index 642c436..d86c7dc 100644
--- a/src/heap.h
+++ b/src/gc/heap.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_HEAP_H_
-#define ART_SRC_HEAP_H_
+#ifndef ART_SRC_GC_HEAP_H_
+#define ART_SRC_GC_HEAP_H_
 
 #include <iosfwd>
 #include <string>
@@ -23,10 +23,9 @@
 
 #include "atomic_integer.h"
 #include "base/timing_logger.h"
-#include "gc/atomic_stack.h"
-#include "gc/card_table.h"
-#include "gc/gc_type.h"
-#include "gc/heap_bitmap.h"
+#include "gc/accounting/atomic_stack.h"
+#include "gc/accounting/card_table.h"
+#include "gc/collector/gc_type.h"
 #include "globals.h"
 #include "gtest/gtest.h"
 #include "locks.h"
@@ -35,32 +34,44 @@
 #include "thread_pool.h"
 
 namespace art {
-namespace mirror {
-class Class;
-class Object;
-}  // namespace mirror
-class AllocSpace;
+
 class ConditionVariable;
-class DlMallocSpace;
-class GarbageCollector;
-class HeapBitmap;
-class ImageSpace;
-class LargeObjectSpace;
-class MarkSweep;
-class ModUnionTable;
 class Mutex;
-class Space;
-class SpaceTest;
 class StackVisitor;
 class Thread;
 class TimingLogger;
 
-typedef std::vector<ContinuousSpace*> Spaces;
+namespace mirror {
+  class Class;
+  class Object;
+}  // namespace mirror
+
+namespace gc {
+namespace accounting {
+  class HeapBitmap;
+  class ModUnionTable;
+  class SpaceSetMap;
+}  // namespace accounting
+
+namespace collector {
+  class GarbageCollector;
+  class MarkSweep;
+}  // namespace collector
+
+namespace space {
+  class AllocSpace;
+  class DiscontinuousSpace;
+  class DlMallocSpace;
+  class ImageSpace;
+  class LargeObjectSpace;
+  class Space;
+  class SpaceTest;
+}  // namespace space
 
 class AgeCardVisitor {
  public:
   byte operator ()(byte card) const {
-    if (card == CardTable::kCardDirty) {
+    if (card == accounting::CardTable::kCardDirty) {
       return card - 1;
     } else {
       return 0;
@@ -68,9 +79,14 @@
   }
 };
 
+// What caused the GC?
 enum GcCause {
+  // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before
+  // retrying allocation.
   kGcCauseForAlloc,
+  // A background GC trying to ensure there is free memory ahead of allocations.
   kGcCauseBackground,
+  // An explicit System.gc() call.
   kGcCauseExplicit,
 };
 std::ostream& operator<<(std::ostream& os, const GcCause& policy);
@@ -120,10 +136,8 @@
 
   // Check sanity of all live references.
   void VerifyHeap() LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
-  static void RootMatchesObjectVisitor(const mirror::Object* root, void* arg);
   bool VerifyHeapReferences()
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
   bool VerifyMissingCardMarks()
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -139,20 +153,12 @@
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Initiates an explicit garbage collection.
-  void CollectGarbage(bool clear_soft_references)
-      LOCKS_EXCLUDED(Locks::mutator_lock_);
+  void CollectGarbage(bool clear_soft_references) LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Does a concurrent GC, should only be called by the GC daemon thread
   // through runtime.
   void ConcurrentGC(Thread* self) LOCKS_EXCLUDED(Locks::runtime_shutdown_lock_);
 
-  // Implements java.lang.Runtime.maxMemory.
-  int64_t GetMaxMemory() const;
-  // Implements java.lang.Runtime.totalMemory.
-  int64_t GetTotalMemory() const;
-  // Implements java.lang.Runtime.freeMemory.
-  int64_t GetFreeMemory() const;
-
   // Implements VMDebug.countInstancesOfClass and JDWP VM_InstanceCount.
   // The boolean decides whether to use IsAssignableFrom or == when comparing classes.
   void CountInstances(const std::vector<mirror::Class*>& classes, bool use_is_assignable_from,
@@ -188,14 +194,14 @@
 
   // Blocks the caller until the garbage collector becomes idle and returns
   // true if we waited for the GC to complete.
-  GcType WaitForConcurrentGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
+  collector::GcType WaitForConcurrentGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
 
-  const Spaces& GetSpaces() const {
-    return spaces_;
+  const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const {
+    return continuous_spaces_;
   }
 
-  Spaces& GetSpaces() {
-    return spaces_;
+  const std::vector<space::DiscontinuousSpace*>& GetDiscontinuousSpaces() const {
+    return discontinuous_spaces_;
   }
 
   void SetReferenceOffsets(MemberOffset reference_referent_offset,
@@ -257,47 +263,78 @@
     card_table_->MarkCard(dst);
   }
 
-  CardTable* GetCardTable() {
+  accounting::CardTable* GetCardTable() const {
     return card_table_.get();
   }
 
   void AddFinalizerReference(Thread* self, mirror::Object* object);
 
-  size_t GetBytesAllocated() const;
+  // Returns the number of bytes currently allocated.
+  size_t GetBytesAllocated() const {
+    return num_bytes_allocated_;
+  }
+
+  // Returns the number of objects currently allocated.
   size_t GetObjectsAllocated() const;
-  size_t GetConcurrentStartSize() const;
-  size_t GetConcurrentMinFree() const;
-  size_t GetUsedMemorySize() const;
 
   // Returns the total number of objects allocated since the heap was created.
-  size_t GetTotalObjectsAllocated() const;
+  size_t GetObjectsAllocatedEver() const;
 
   // Returns the total number of bytes allocated since the heap was created.
-  size_t GetTotalBytesAllocated() const;
+  size_t GetBytesAllocatedEver() const;
 
   // Returns the total number of objects freed since the heap was created.
-  size_t GetTotalObjectsFreed() const;
+  size_t GetObjectsFreedEver() const {
+    return total_objects_freed_ever_;
+  }
 
   // Returns the total number of bytes freed since the heap was created.
-  size_t GetTotalBytesFreed() const;
+  size_t GetBytesFreedEver() const {
+    return total_bytes_freed_ever_;
+  }
 
-  // Functions for getting the bitmap which corresponds to an object's address.
-  // This is probably slow, TODO: use better data structure like binary tree .
-  ContinuousSpace* FindSpaceFromObject(const mirror::Object*) const;
+  // Implements java.lang.Runtime.maxMemory, returning the maximum amount of memory a program can
+  // consume. For a regular VM this would relate to the -Xmx option and would return -1 if no Xmx
+  // were specified. Android apps start with a growth limit (small heap size) which is
+  // cleared/extended for large apps.
+  int64_t GetMaxMemory() const {
+    return growth_limit_;
+  }
+
+  // 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_;
+  }
+
+  // Implements java.lang.Runtime.freeMemory.
+  int64_t GetFreeMemory() const {
+    return GetTotalMemory() - num_bytes_allocated_;
+  }
+
+  // Get the space that corresponds to an object's address. Current implementation searches all
+  // spaces in turn. If fail_ok is false then failing to find a space will cause an abort.
+  // TODO: consider using faster data structure like binary tree.
+  space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const;
+  space::DiscontinuousSpace* FindDiscontinuousSpaceFromObject(const mirror::Object*,
+                                                              bool fail_ok) const;
+  space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const;
 
   void DumpForSigQuit(std::ostream& os);
 
   size_t Trim();
 
-  HeapBitmap* GetLiveBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+  accounting::HeapBitmap* GetLiveBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     return live_bitmap_.get();
   }
 
-  HeapBitmap* GetMarkBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+  accounting::HeapBitmap* GetMarkBitmap() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     return mark_bitmap_.get();
   }
 
-  ObjectStack* GetLiveStack() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+  accounting::ObjectStack* GetLiveStack() SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     return live_stack_.get();
   }
 
@@ -308,24 +345,32 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Mark all the objects in the allocation stack in the specified bitmap.
-  void MarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack)
+  void MarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+                      accounting::ObjectStack* stack)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Unmark all the objects in the allocation stack in the specified bitmap.
-  void UnMarkAllocStack(SpaceBitmap* bitmap, SpaceSetMap* large_objects, ObjectStack* stack)
+  void UnMarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
+                        accounting::ObjectStack* stack)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // Update and mark mod union table based on gc type.
-  void UpdateAndMarkModUnion(MarkSweep* mark_sweep, TimingLogger& timings, GcType gc_type)
+  void UpdateAndMarkModUnion(collector::MarkSweep* mark_sweep, base::NewTimingLogger& timings,
+                             collector::GcType gc_type)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // DEPRECATED: Should remove in "near" future when support for multiple image spaces is added.
   // Assumes there is only one image space.
-  ImageSpace* GetImageSpace();
-  DlMallocSpace* GetAllocSpace();
-  LargeObjectSpace* GetLargeObjectsSpace() {
-    return large_object_space_.get();
+  space::ImageSpace* GetImageSpace() const;
+
+  space::DlMallocSpace* GetAllocSpace() const {
+    return alloc_space_;
   }
+
+  space::LargeObjectSpace* GetLargeObjectsSpace() const {
+    return large_object_space_;
+  }
+
   void DumpSpaces();
 
   // UnReserve the address range where the oat file will be placed.
@@ -344,12 +389,12 @@
  private:
   // Allocates uninitialized storage. Passing in a null space tries to place the object in the
   // large object space.
-  mirror::Object* Allocate(Thread* self, AllocSpace* space, size_t num_bytes)
+  mirror::Object* Allocate(Thread* self, space::AllocSpace* space, size_t num_bytes)
       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Try to allocate a number of bytes, this function never does any GCs.
-  mirror::Object* TryToAllocate(Thread* self, AllocSpace* space, size_t alloc_size, bool grow)
+  mirror::Object* TryToAllocate(Thread* self, space::AllocSpace* space, size_t alloc_size, bool grow)
       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -365,14 +410,16 @@
 
   // Sometimes CollectGarbageInternal decides to run a different Gc than you requested. Returns
   // which type of Gc was actually ran.
-  GcType CollectGarbageInternal(GcType gc_plan, GcCause gc_cause, bool clear_soft_references)
+  collector::GcType CollectGarbageInternal(collector::GcType gc_plan, GcCause gc_cause,
+                                           bool clear_soft_references)
       LOCKS_EXCLUDED(gc_complete_lock_,
                      Locks::heap_bitmap_lock_,
                      Locks::thread_suspend_count_lock_);
 
-  void PreGcVerification(GarbageCollector* gc);
-  void PreSweepingGcVerification(GarbageCollector* gc);
-  void PostGcVerification(GarbageCollector* gc);
+  void PreGcVerification(collector::GarbageCollector* gc);
+  void PreSweepingGcVerification(collector::GarbageCollector* gc)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void PostGcVerification(collector::GarbageCollector* gc);
 
   // Given the current contents of the alloc space, increase the allowed heap footprint to match
   // the target utilization ratio.  This should only be called immediately after a full garbage
@@ -381,7 +428,9 @@
 
   size_t GetPercentFree();
 
-  void AddSpace(ContinuousSpace* space) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+  void AddContinuousSpace(space::ContinuousSpace* space) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+  void AddDiscontinuousSpace(space::DiscontinuousSpace* space)
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
 
   // No thread saftey analysis since we call this everywhere and it is impossible to find a proper
   // lock ordering for it.
@@ -394,26 +443,32 @@
   void SwapStacks();
 
   // Clear cards and update the mod union table.
-  void ProcessCards(TimingLogger& timings);
+  void ProcessCards(base::NewTimingLogger& timings);
 
-  Spaces spaces_;
+  // All-known continuous spaces, where objects lie within fixed bounds.
+  std::vector<space::ContinuousSpace*> continuous_spaces_;
 
-  // A map that we use to temporarily reserve address range for the oat file.
-  UniquePtr<MemMap> oat_file_map_;
+  // All-known discontinuous spaces, where objects may be placed throughout virtual memory.
+  std::vector<space::DiscontinuousSpace*> discontinuous_spaces_;
 
-  // The alloc space which we are currently allocating into.
-  DlMallocSpace* alloc_space_;
+  // The allocation space we are currently allocating into.
+  space::DlMallocSpace* alloc_space_;
+
+  // The large object space we are currently allocating into.
+  space::LargeObjectSpace* large_object_space_;
+
+  // The card table, dirtied by the write barrier.
+  UniquePtr<accounting::CardTable> card_table_;
 
   // The mod-union table remembers all of the references from the image space to the alloc /
-  // zygote spaces.
-  UniquePtr<ModUnionTable> mod_union_table_;
+  // zygote spaces to allow the card table to be cleared.
+  UniquePtr<accounting::ModUnionTable> image_mod_union_table_;
 
   // This table holds all of the references from the zygote space to the alloc space.
-  UniquePtr<ModUnionTable> zygote_mod_union_table_;
+  UniquePtr<accounting::ModUnionTable> zygote_mod_union_table_;
 
-  UniquePtr<CardTable> card_table_;
-
-  // True for concurrent mark sweep GC, false for mark sweep.
+  // What kind of concurrency behavior is the runtime after? True for concurrent mark sweep GC,
+  // false for stop-the-world mark sweep.
   const bool concurrent_gc_;
 
   // If we have a zygote space.
@@ -424,40 +479,43 @@
   Mutex* gc_complete_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   UniquePtr<ConditionVariable> gc_complete_cond_ GUARDED_BY(gc_complete_lock_);
 
-  // Reference queue lock
-  UniquePtr<Mutex> reference_queue_lock_;
+  // Mutex held when adding references to reference queues.
+  // TODO: move to a UniquePtr, currently annotalysis is confused that UniquePtr isn't lockable.
+  Mutex* reference_queue_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
 
   // True while the garbage collector is running.
   volatile bool is_gc_running_ GUARDED_BY(gc_complete_lock_);
 
   // Last Gc type we ran. Used by WaitForConcurrentGc to know which Gc was waited on.
-  volatile GcType last_gc_type_ GUARDED_BY(gc_complete_lock_);
-
-  // If enabled, causes Gc for alloc when heap size reaches the current footprint limit before the
-  // Gc updates it.
-  const bool enforce_heap_growth_rate_;
+  volatile collector::GcType last_gc_type_ GUARDED_BY(gc_complete_lock_);
 
   // Maximum size that the heap can reach.
-  size_t capacity_;
+  const size_t capacity_;
+  // The size the heap is limited to. This is initially smaller than capacity, but for largeHeap
+  // programs it is "cleared" making it the same as capacity.
   size_t growth_limit_;
+  // When the number of bytes allocated exceeds the footprint TryAllocate returns NULL indicating
+  // a GC should be triggered.
   size_t max_allowed_footprint_;
 
-  // Minimum bytes before concurrent GC starts.
-  size_t concurrent_start_size_;
-  size_t concurrent_min_free_;
+  // When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that
+  // it completes ahead of an allocation failing.
   size_t concurrent_start_bytes_;
 
-  // Number of bytes allocated since the last Gc, we use this to help determine when to schedule concurrent GCs.
+  // Number of back-to-back sticky mark sweep collections.
   size_t sticky_gc_count_;
 
-  size_t total_bytes_freed_;
-  size_t total_objects_freed_;
+  // After how many sticky GCs we force to do a partial GC instead of sticky mark bits GC.
+  const size_t sticky_to_partial_gc_ratio_;
+
+  // Since the heap was created, how many bytes have been freed.
+  size_t total_bytes_freed_ever_;
+
+  // Since the heap was created, how many objects have been freed.
+  size_t total_objects_freed_ever_;
 
   // Primitive objects larger than this size are put in the large object space.
-  size_t large_object_threshold_;
-
-  // Large object space.
-  UniquePtr<LargeObjectSpace> large_object_space_;
+  const size_t large_object_threshold_;
 
   // Number of bytes allocated.  Adjusted after each allocation and free.
   AtomicInteger num_bytes_allocated_;
@@ -472,9 +530,6 @@
   // Parallel GC data structures.
   UniquePtr<ThreadPool> thread_pool_;
 
-  // After how many GCs we force to do a partial GC instead of sticky mark bits GC.
-  const size_t partial_gc_frequency_;
-
   // Sticky mark bits GC has some overhead, so if we have less a few megabytes of AllocSpace then
   // it's probably better to just do a partial GC.
   const size_t min_alloc_space_size_for_sticky_gc_;
@@ -483,31 +538,34 @@
   // normal GC, it is important to not use it when we are almost out of memory.
   const size_t min_remaining_space_for_sticky_gc_;
 
-  // Last trim time
-  uint64_t last_trim_time_;
+  // The last time a heap trim occurred.
+  uint64_t last_trim_time_ms_;
 
-  // The time at which the last GC ended.
-  uint64_t last_gc_time_;
+  // The nanosecond time at which the last GC ended.
+  uint64_t last_gc_time_ns_;
 
   // How many bytes were allocated at the end of the last GC.
   uint64_t last_gc_size_;
 
-  // Estimated allocation rate (bytes / second).
+  // Estimated allocation rate (bytes / second). Computed between the time of the last GC cycle
+  // and the start of the current one.
   uint64_t allocation_rate_;
 
-  UniquePtr<HeapBitmap> live_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
-  UniquePtr<HeapBitmap> mark_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
+  // For a GC cycle, a bitmap that is set corresponding to the
+  UniquePtr<accounting::HeapBitmap> live_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
+  UniquePtr<accounting::HeapBitmap> mark_bitmap_ GUARDED_BY(Locks::heap_bitmap_lock_);
 
   // Mark stack that we reuse to avoid re-allocating the mark stack.
-  UniquePtr<ObjectStack> mark_stack_;
+  UniquePtr<accounting::ObjectStack> mark_stack_;
 
   // Allocation stack, new allocations go here so that we can do sticky mark bits. This enables us
   // to use the live bitmap as the old mark bitmap.
   const size_t max_allocation_stack_size_;
-  UniquePtr<ObjectStack> allocation_stack_;
+  bool is_allocation_stack_sorted_;
+  UniquePtr<accounting::ObjectStack> allocation_stack_;
 
   // Second allocation stack so that we can process allocation with the heap unlocked.
-  UniquePtr<ObjectStack> live_stack_;
+  UniquePtr<accounting::ObjectStack> live_stack_;
 
   // offset of java.lang.ref.Reference.referent
   MemberOffset reference_referent_offset_;
@@ -544,22 +602,22 @@
   // The current state of heap verification, may be enabled or disabled.
   HeapVerificationMode verify_object_mode_;
 
-  typedef std::vector<MarkSweep*> Collectors;
-  Collectors mark_sweep_collectors_;
+  std::vector<collector::MarkSweep*> mark_sweep_collectors_;
 
-  friend class MarkSweep;
+  // A map that we use to temporarily reserve address range for the oat file.
+  UniquePtr<MemMap> oat_file_map_;
+
+  friend class collector::MarkSweep;
   friend class VerifyReferenceCardVisitor;
   friend class VerifyReferenceVisitor;
   friend class VerifyObjectVisitor;
   friend class ScopedHeapLock;
-  FRIEND_TEST(SpaceTest, AllocAndFree);
-  FRIEND_TEST(SpaceTest, AllocAndFreeList);
-  FRIEND_TEST(SpaceTest, ZygoteSpace);
-  friend class SpaceTest;
+  friend class space::SpaceTest;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(Heap);
 };
 
+}  // namespace gc
 }  // namespace art
 
-#endif  // ART_SRC_HEAP_H_
+#endif  // ART_SRC_GC_HEAP_H_
diff --git a/src/gc/heap_bitmap-inl.h b/src/gc/heap_bitmap-inl.h
deleted file mode 100644
index 2811183..0000000
--- a/src/gc/heap_bitmap-inl.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_HEAP_BITMAP_INL_H_
-#define ART_SRC_GC_HEAP_BITMAP_INL_H_
-
-#include "heap_bitmap.h"
-
-namespace art {
-
-template <typename Visitor>
-inline void HeapBitmap::Visit(const Visitor& visitor) {
-  // TODO: C++0x auto
-  for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
-    SpaceBitmap* bitmap = *it;
-    bitmap->VisitMarkedRange(bitmap->HeapBegin(), bitmap->HeapLimit(), visitor, VoidFunctor());
-  }
-  large_objects_->Visit(visitor);
-}
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_HEAP_BITMAP_INL_H_
diff --git a/src/gc/heap_bitmap.cc b/src/gc/heap_bitmap.cc
deleted file mode 100644
index cef6884..0000000
--- a/src/gc/heap_bitmap.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "heap_bitmap.h"
-#include "space.h"
-
-namespace art {
-
-void HeapBitmap::ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap) {
-  // TODO: C++0x auto
-  for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
-    if (*it == old_bitmap) {
-      *it = new_bitmap;
-      return;
-    }
-  }
-  LOG(FATAL) << "bitmap " << static_cast<const void*>(old_bitmap) << " not found";
-}
-
-void HeapBitmap::AddSpaceBitmap(SpaceBitmap* bitmap) {
-  DCHECK(bitmap != NULL);
-
-  // Check for interval overlap.
-  for (Bitmaps::const_iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
-    SpaceBitmap* cur_bitmap = *it;
-    if (bitmap->HeapBegin() < cur_bitmap->HeapLimit() &&
-        bitmap->HeapLimit() > cur_bitmap->HeapBegin()) {
-      LOG(FATAL) << "Overlapping space bitmaps added to heap bitmap!";
-    }
-  }
-  bitmaps_.push_back(bitmap);
-}
-
-void HeapBitmap::SetLargeObjects(SpaceSetMap* large_objects) {
-  DCHECK(large_objects != NULL);
-  large_objects_ = large_objects;
-}
-
-HeapBitmap::HeapBitmap(Heap* heap) : heap_(heap), large_objects_(NULL) {
-
-}
-
-void HeapBitmap::Walk(SpaceBitmap::Callback* callback, void* arg) {
-  // TODO: C++0x auto
-  for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
-    (*it)->Walk(callback, arg);
-  }
-
-  large_objects_->Walk(callback, arg);
-}
-
-}  // namespace art
diff --git a/src/gc/heap_bitmap.h b/src/gc/heap_bitmap.h
deleted file mode 100644
index 87e0848..0000000
--- a/src/gc/heap_bitmap.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_HEAP_BITMAP_H_
-#define ART_SRC_GC_HEAP_BITMAP_H_
-
-#include "locks.h"
-#include "space_bitmap.h"
-
-namespace art {
-class Heap;
-
-class HeapBitmap {
- public:
-  bool Test(const mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
-    SpaceBitmap* bitmap = GetSpaceBitmap(obj);
-    if (LIKELY(bitmap != NULL)) {
-      return bitmap->Test(obj);
-    } else {
-      return large_objects_->Test(obj);
-    }
-  }
-
-  void Clear(const mirror::Object* obj)
-  EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
-    SpaceBitmap* bitmap = GetSpaceBitmap(obj);
-    if (LIKELY(bitmap != NULL)) {
-      bitmap->Clear(obj);
-    } else {
-      large_objects_->Clear(obj);
-    }
-  }
-
-  void Set(const mirror::Object* obj)
-  EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
-    SpaceBitmap* bitmap = GetSpaceBitmap(obj);
-    if (LIKELY(bitmap != NULL)) {
-      bitmap->Set(obj);
-    } else {
-      large_objects_->Set(obj);
-    }
-  }
-
-  SpaceBitmap* GetSpaceBitmap(const mirror::Object* obj) {
-    // TODO: C++0x auto
-    for (Bitmaps::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
-      if ((*it)->HasAddress(obj)) {
-        return *it;
-      }
-    }
-    return NULL;
-  }
-
-  void Walk(SpaceBitmap::Callback* callback, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  template <typename Visitor>
-  void Visit(const Visitor& visitor)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Find and replace a bitmap pointer, this is used by for the bitmap swapping in the GC.
-  void ReplaceBitmap(SpaceBitmap* old_bitmap, SpaceBitmap* new_bitmap)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  HeapBitmap(Heap* heap);
-
-  inline SpaceSetMap* GetLargeObjects() const {
-    return large_objects_;
-  }
-
-  void SetLargeObjects(SpaceSetMap* large_objects);
-
- private:
-
-  const Heap* const heap_;
-
-  void AddSpaceBitmap(SpaceBitmap* bitmap);
-
-  typedef std::vector<SpaceBitmap*> Bitmaps;
-  Bitmaps bitmaps_;
-
-  // Large object sets.
-  SpaceSetMap* large_objects_;
-
-  friend class Heap;
-};
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_HEAP_BITMAP_H_
diff --git a/src/heap_test.cc b/src/gc/heap_test.cc
similarity index 73%
rename from src/heap_test.cc
rename to src/gc/heap_test.cc
index 8bed7e3..02708e8 100644
--- a/src/heap_test.cc
+++ b/src/gc/heap_test.cc
@@ -15,14 +15,15 @@
  */
 
 #include "common_test.h"
-#include "gc/card_table-inl.h"
-#include "gc/space_bitmap-inl.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/space_bitmap-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "sirt_ref.h"
 
 namespace art {
+namespace gc {
 
 class HeapTest : public CommonTest {};
 
@@ -56,9 +57,15 @@
 
 TEST_F(HeapTest, HeapBitmapCapacityTest) {
   byte* heap_begin = reinterpret_cast<byte*>(0x1000);
-  const size_t heap_capacity = SpaceBitmap::kAlignment * (sizeof(intptr_t) * 8 + 1);
-  UniquePtr<SpaceBitmap> bitmap(SpaceBitmap::Create("test bitmap", heap_begin, heap_capacity));
-  bitmap->Set(reinterpret_cast<const mirror::Object*>(&heap_begin[heap_capacity - SpaceBitmap::kAlignment]));
+  const size_t heap_capacity = accounting::SpaceBitmap::kAlignment * (sizeof(intptr_t) * 8 + 1);
+  UniquePtr<accounting::SpaceBitmap> bitmap(accounting::SpaceBitmap::Create("test bitmap",
+                                                                            heap_begin,
+                                                                            heap_capacity));
+  mirror::Object* fake_end_of_heap_object =
+      reinterpret_cast<mirror::Object*>(&heap_begin[heap_capacity -
+                                                    accounting::SpaceBitmap::kAlignment]);
+  bitmap->Set(fake_end_of_heap_object);
 }
 
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/mod_union_table-inl.h b/src/gc/mod_union_table-inl.h
deleted file mode 100644
index c1c69fb..0000000
--- a/src/gc/mod_union_table-inl.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_MOD_UNION_TABLE_INL_H_
-#define ART_SRC_GC_MOD_UNION_TABLE_INL_H_
-
-#include "mod_union_table.h"
-
-namespace art {
-
-template <typename Implementation>
-class ModUnionTableToZygoteAllocspace : public Implementation {
-public:
-  ModUnionTableToZygoteAllocspace(Heap* heap) : Implementation(heap) {
-  }
-
-  bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
-    const Spaces& spaces = Implementation::GetHeap()->GetSpaces();
-    for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-      if ((*it)->Contains(ref)) {
-        return (*it)->IsAllocSpace();
-      }
-    }
-    // Assume it points to a large object.
-    // TODO: Check.
-    return true;
-  }
-};
-
-template <typename Implementation>
-class ModUnionTableToAllocspace : public Implementation {
-public:
-  ModUnionTableToAllocspace(Heap* heap) : Implementation(heap) {
-  }
-
-  bool AddReference(const mirror::Object* /* obj */, const mirror::Object* ref) {
-    const Spaces& spaces = Implementation::GetHeap()->GetSpaces();
-    for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-      if ((*it)->Contains(ref)) {
-        return (*it)->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect;
-      }
-    }
-    // Assume it points to a large object.
-    // TODO: Check.
-    return true;
-  }
-};
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_MOD_UNION_TABLE_INL_H_
diff --git a/src/gc/mod_union_table.cc b/src/gc/mod_union_table.cc
deleted file mode 100644
index da950bb..0000000
--- a/src/gc/mod_union_table.cc
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mod_union_table.h"
-
-#include "base/stl_util.h"
-#include "card_table-inl.h"
-#include "heap.h"
-#include "heap_bitmap.h"
-#include "mark_sweep.h"
-#include "mark_sweep-inl.h"
-#include "mirror/object-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/field-inl.h"
-#include "mirror/object_array-inl.h"
-#include "space.h"
-#include "space_bitmap-inl.h"
-#include "thread.h"
-#include "UniquePtr.h"
-
-using namespace art::mirror;
-
-namespace art {
-
-class MarkIfReachesAllocspaceVisitor {
- public:
-  explicit MarkIfReachesAllocspaceVisitor(Heap* const heap, SpaceBitmap* bitmap)
-    : heap_(heap),
-      bitmap_(bitmap) {
-  }
-
-  // Extra parameters are required since we use this same visitor signature for checking objects.
-  void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */, bool /* is_static */) const {
-    // TODO: Optimize?
-    // TODO: C++0x auto
-    const Spaces& spaces = heap_->GetSpaces();
-    for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
-      if ((*cur)->IsAllocSpace() && (*cur)->Contains(ref)) {
-        bitmap_->Set(obj);
-        break;
-      }
-    }
-  }
-
- private:
-  Heap* const heap_;
-  SpaceBitmap* bitmap_;
-};
-
-class ModUnionVisitor {
- public:
-  explicit ModUnionVisitor(Heap* const heap, SpaceBitmap* bitmap)
-    : heap_(heap),
-      bitmap_(bitmap) {
-  }
-
-  void operator ()(const Object* obj) const
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
-                            Locks::mutator_lock_) {
-    DCHECK(obj != NULL);
-    // We don't have an early exit since we use the visitor pattern, an early exit should
-    // significantly speed this up.
-    MarkIfReachesAllocspaceVisitor visitor(heap_, bitmap_);
-    MarkSweep::VisitObjectReferences(obj, visitor);
-  }
- private:
-  Heap* const heap_;
-  SpaceBitmap* bitmap_;
-};
-
-class ModUnionClearCardSetVisitor {
- public:
-  explicit ModUnionClearCardSetVisitor(std::set<byte*>* const cleared_cards)
-    : cleared_cards_(cleared_cards) {
-  }
-
-  inline void operator ()(byte* card, byte expected_value, byte new_value) const {
-    if (expected_value == CardTable::kCardDirty) {
-      cleared_cards_->insert(card);
-    }
-  }
-
- private:
-  std::set<byte*>* const cleared_cards_;
-};
-
-class ModUnionClearCardVisitor {
- public:
-  explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
-    : cleared_cards_(cleared_cards) {
-  }
-
-  void operator ()(byte* card, byte expected_card, byte new_card) const {
-    if (expected_card == CardTable::kCardDirty) {
-      cleared_cards_->push_back(card);
-    }
-  }
- private:
-  std::vector<byte*>* cleared_cards_;
-};
-
-ModUnionTableBitmap::ModUnionTableBitmap(Heap* heap) : ModUnionTable(heap)  {
-  // Prevent fragmentation of the heap which is caused by resizing of the vector.
-  // TODO: Make a new vector which uses madvise (basically same as a mark stack).
-  cleared_cards_.reserve(32);
-  const Spaces& spaces = heap->GetSpaces();
-  // Create one heap bitmap per image space.
-  // TODO: C++0x auto
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    ContinuousSpace* space = *it;
-    if (space->IsImageSpace()) {
-      // The mod-union table is only needed when we have an image space since it's purpose is to
-      // cache image roots.
-      UniquePtr<SpaceBitmap> bitmap(SpaceBitmap::Create("mod-union table bitmap", space->Begin(),
-                                                        space->Size()));
-      CHECK(bitmap.get() != NULL) << "Failed to create mod-union bitmap";
-      bitmaps_.Put(space, bitmap.release());
-    }
-  }
-}
-
-ModUnionTableBitmap::~ModUnionTableBitmap() {
-  STLDeleteValues(&bitmaps_);
-}
-
-void ModUnionTableBitmap::ClearCards(ContinuousSpace* space) {
-  CardTable* card_table = heap_->GetCardTable();
-  ModUnionClearCardVisitor visitor(&cleared_cards_);
-  // Clear dirty cards in the this image space and update the corresponding mod-union bits.
-  card_table->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), visitor);
-}
-
-void ModUnionTableBitmap::Update() {
-  CardTable* card_table = heap_->GetCardTable();
-  while (!cleared_cards_.empty()) {
-    byte* card = cleared_cards_.back();
-    cleared_cards_.pop_back();
-
-    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
-    uintptr_t end = start + CardTable::kCardSize;
-    ContinuousSpace* space = heap_->FindSpaceFromObject(reinterpret_cast<Object*>(start));
-    SpaceBitmap* bitmap = space->GetLiveBitmap();
-
-    // Clear the mod-union bitmap range corresponding to this card so that we don't have any
-    // objects marked which do not reach the alloc space.
-    bitmap->VisitRange(start, end, SpaceBitmap::ClearVisitor(bitmap));
-
-    // At this point we need to update the mod-union bitmap to contain all the objects which reach
-    // the alloc space.
-    ModUnionVisitor visitor(heap_, bitmap);
-    space->GetLiveBitmap()->VisitMarkedRange(start, end, visitor, VoidFunctor());
-  }
-}
-
-class ModUnionScanImageRootVisitor {
- public:
-  ModUnionScanImageRootVisitor(MarkSweep* const mark_sweep) : mark_sweep_(mark_sweep) {
-  }
-
-  void operator ()(const Object* root) const
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(root != NULL);
-    mark_sweep_->ScanRoot(root);
-  }
-
- private:
-  MarkSweep* const mark_sweep_;
-};
-
-void ModUnionTableBitmap::MarkReferences(MarkSweep* mark_sweep) {
-  // Some tests have no image space, and therefore no mod-union bitmap.
-  ModUnionScanImageRootVisitor image_root_scanner(mark_sweep);
-  for (BitmapMap::iterator it = bitmaps_.begin(); it != bitmaps_.end(); ++it) {
-    const ContinuousSpace* space = it->first;
-    uintptr_t begin = reinterpret_cast<uintptr_t>(space->Begin());
-    uintptr_t end = reinterpret_cast<uintptr_t>(space->End());
-    it->second->VisitMarkedRange(begin, end, image_root_scanner, VoidFunctor());
-  }
-}
-
-
-ModUnionTableReferenceCache::ModUnionTableReferenceCache(Heap* heap) : ModUnionTable(heap) {
-
-}
-
-ModUnionTableReferenceCache::~ModUnionTableReferenceCache() {
-
-}
-
-void ModUnionTableReferenceCache::ClearCards(ContinuousSpace* space) {
-  CardTable* card_table = GetHeap()->GetCardTable();
-  ModUnionClearCardSetVisitor visitor(&cleared_cards_);
-  // Clear dirty cards in the this space and update the corresponding mod-union bits.
-  card_table->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), visitor);
-}
-
-class AddToReferenceArrayVisitor {
- public:
-  explicit AddToReferenceArrayVisitor(
-      ModUnionTableReferenceCache* const mod_union_table,
-        ModUnionTableReferenceCache::ReferenceArray* references)
-    : mod_union_table_(mod_union_table),
-      references_(references) {
-  }
-
-  // Extra parameters are required since we use this same visitor signature for checking objects.
-  void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
-                     bool /* is_static */) const {
-    // Only add the reference if it is non null and fits our criteria.
-    if (ref != NULL && mod_union_table_->AddReference(obj, ref)) {
-      references_->push_back(ref);
-    }
-  }
-
- private:
-  ModUnionTableReferenceCache* mod_union_table_;
-  ModUnionTable::ReferenceArray* references_;
-};
-
-class ModUnionReferenceVisitor {
- public:
-  explicit ModUnionReferenceVisitor(
-        ModUnionTableReferenceCache* const mod_union_table,
-        ModUnionTableReferenceCache::ReferenceArray* references)
-    : mod_union_table_(mod_union_table),
-      references_(references) {
-  }
-
-  void operator ()(const Object* obj) const
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
-                            Locks::mutator_lock_) {
-    DCHECK(obj != NULL);
-    // We don't have an early exit since we use the visitor pattern, an early
-    // exit should significantly speed this up.
-    AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
-    MarkSweep::VisitObjectReferences(obj, visitor);
-  }
- private:
-  ModUnionTableReferenceCache* const mod_union_table_;
-  ModUnionTable::ReferenceArray* references_;
-};
-
-
-class CheckReferenceVisitor {
- public:
-  typedef std::set<const Object*> ReferenceSet;
-
-  explicit CheckReferenceVisitor(
-      ModUnionTableReferenceCache* const mod_union_table,
-      const ReferenceSet& references)
-    : mod_union_table_(mod_union_table),
-      references_(references) {
-  }
-
-  // Extra parameters are required since we use this same visitor signature for checking objects.
-  // TODO: Fixme when anotatalysis works with visitors.
-  void operator ()(const Object* obj, const Object* ref, const MemberOffset& /* offset */,
-                     bool /* is_static */) const
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
-    Heap* heap = mod_union_table_->GetHeap();
-    if (ref != NULL && mod_union_table_->AddReference(obj, ref) &&
-        references_.find(ref) == references_.end()) {
-      ContinuousSpace* from_space = heap->FindSpaceFromObject(obj);
-      ContinuousSpace* to_space = heap->FindSpaceFromObject(ref);
-      LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj) << ")"
-                << "References " << reinterpret_cast<const void*>(ref)
-                << "(" << PrettyTypeOf(ref) << ") without being in mod-union table";
-      LOG(INFO) << "FromSpace " << from_space->GetName() << " type " << from_space->GetGcRetentionPolicy();
-      LOG(INFO) << "ToSpace " << to_space->GetName() << " type " << to_space->GetGcRetentionPolicy();
-      mod_union_table_->GetHeap()->DumpSpaces();
-      LOG(FATAL) << "FATAL ERROR";
-    }
-  }
-
- private:
-  ModUnionTableReferenceCache* const mod_union_table_;
-  const ReferenceSet& references_;
-};
-
-class ModUnionCheckReferences {
- public:
-  typedef std::set<const Object*> ReferenceSet;
-
-  explicit ModUnionCheckReferences (
-      ModUnionTableReferenceCache* const mod_union_table,
-      const ReferenceSet& references)
-    : mod_union_table_(mod_union_table),
-      references_(references) {
-  }
-
-  void operator ()(const Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
-    DCHECK(obj != NULL);
-    if (kDebugLocking) {
-      Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
-    }
-    CheckReferenceVisitor visitor(mod_union_table_, references_);
-    MarkSweep::VisitObjectReferences(obj, visitor);
-  }
-
- private:
-  ModUnionTableReferenceCache* const mod_union_table_;
-  const ReferenceSet& references_;
-};
-
-void ModUnionTableReferenceCache::Verify() {
-  // Start by checking that everything in the mod union table is marked.
-  Heap* heap = GetHeap();
-  for (ReferenceMap::const_iterator it = references_.begin(); it != references_.end(); ++it) {
-    for (ReferenceArray::const_iterator it_ref = it->second.begin(); it_ref != it->second.end();
-        ++it_ref ) {
-      DCHECK(heap->GetLiveBitmap()->Test(*it_ref));
-    }
-  }
-
-  // Check the references of each clean card which is also in the mod union table.
-  for (ReferenceMap::const_iterator it = references_.begin(); it != references_.end(); ++it) {
-    const byte* card = &*it->first;
-    if (*card == CardTable::kCardClean) {
-      std::set<const Object*> reference_set;
-      for (ReferenceArray::const_iterator itr = it->second.begin(); itr != it->second.end();++itr) {
-        reference_set.insert(*itr);
-      }
-      ModUnionCheckReferences visitor(this, reference_set);
-      CardTable* card_table = heap->GetCardTable();
-      uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
-      uintptr_t end = start + CardTable::kCardSize;
-      SpaceBitmap* live_bitmap =
-              heap->FindSpaceFromObject(reinterpret_cast<Object*>(start))->GetLiveBitmap();
-      live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
-    }
-  }
-}
-
-void ModUnionTableReferenceCache::Update() {
-  Heap* heap = GetHeap();
-  CardTable* card_table = heap->GetCardTable();
-
-  ReferenceArray cards_references;
-  ModUnionReferenceVisitor visitor(this, &cards_references);
-
-  for (ClearedCards::iterator it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
-    byte* card = *it;
-    // Clear and re-compute alloc space references associated with this card.
-    cards_references.clear();
-    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
-    uintptr_t end = start + CardTable::kCardSize;
-    SpaceBitmap* live_bitmap =
-        heap->FindSpaceFromObject(reinterpret_cast<Object*>(start))->GetLiveBitmap();
-    live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
-
-    // Update the corresponding references for the card.
-    // TODO: C++0x auto
-    ReferenceMap::iterator found = references_.find(card);
-    if (found == references_.end()) {
-      if (cards_references.empty()) {
-        // No reason to add empty array.
-        continue;
-      }
-      references_.Put(card, cards_references);
-    } else {
-      found->second = cards_references;
-    }
-  }
-  cleared_cards_.clear();
-}
-
-void ModUnionTableReferenceCache::MarkReferences(MarkSweep* mark_sweep) {
-  // TODO: C++0x auto
-  size_t count = 0;
-  for (ReferenceMap::const_iterator it = references_.begin(); it != references_.end(); ++it) {
-    for (ReferenceArray::const_iterator it_ref = it->second.begin(); it_ref != it->second.end(); ++it_ref ) {
-      mark_sweep->MarkRoot(*it_ref);
-      ++count;
-    }
-  }
-  if (VLOG_IS_ON(heap)) {
-    VLOG(gc) << "Marked " << count << " references in mod union table";
-  }
-}
-
-ModUnionTableCardCache::ModUnionTableCardCache(Heap* heap) : ModUnionTable(heap) {
-
-}
-
-ModUnionTableCardCache::~ModUnionTableCardCache() {
-
-}
-
-void ModUnionTableCardCache::ClearCards(ContinuousSpace* space) {
-  CardTable* card_table = GetHeap()->GetCardTable();
-  ModUnionClearCardSetVisitor visitor(&cleared_cards_);
-  // Clear dirty cards in the this space and update the corresponding mod-union bits.
-  card_table->ModifyCardsAtomic(space->Begin(), space->End(), AgeCardVisitor(), visitor);
-}
-
-// Mark all references to the alloc space(s).
-void ModUnionTableCardCache::MarkReferences(MarkSweep* mark_sweep) {
-  CardTable* card_table = heap_->GetCardTable();
-  ModUnionScanImageRootVisitor visitor(mark_sweep);
-  for (ClearedCards::const_iterator it = cleared_cards_.begin(); it != cleared_cards_.end(); ++it) {
-    byte* card = *it;
-    uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
-    uintptr_t end = start + CardTable::kCardSize;
-    SpaceBitmap* live_bitmap =
-        heap_->FindSpaceFromObject(reinterpret_cast<Object*>(start))->GetLiveBitmap();
-    live_bitmap->VisitMarkedRange(start, end, visitor, VoidFunctor());
-  }
-}
-
-}  // namespace art
diff --git a/src/gc/mod_union_table.h b/src/gc/mod_union_table.h
deleted file mode 100644
index c0b9535..0000000
--- a/src/gc/mod_union_table.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_MOD_UNION_TABLE_H_
-#define ART_SRC_GC_MOD_UNION_TABLE_H_
-
-#include "globals.h"
-#include "safe_map.h"
-
-#include <set>
-#include <vector>
-
-namespace art {
-namespace mirror {
-class Object;
-}
-class ContinuousSpace;
-class Heap;
-class HeapBitmap;
-class MarkSweep;
-class Space;
-class SpaceBitmap;
-
-// Base class
-class ModUnionTable {
- public:
-  typedef std::vector<const mirror::Object*> ReferenceArray;
-  typedef std::set<byte*> ClearedCards;
-
-  ModUnionTable(Heap* heap) : heap_(heap) {
-
-  }
-
-  virtual ~ModUnionTable() {
-
-  }
-
-  // Clear cards which map to a memory range of a space.
-  virtual void ClearCards(ContinuousSpace* space) = 0;
-
-  // Update the mod-union table.
-  virtual void Update() = 0;
-
-  // Mark all references which are stored in the mod union table.
-  virtual void MarkReferences(MarkSweep* mark_sweep) = 0;
-
-  // Verification, sanity checks that we don't have clean cards which conflict with out cached data
-  // for said cards. Exclusive lock is required since verify sometimes uses
-  // SpaceBitmap::VisitMarkedRange and VisitMarkedRange can't know if the callback will modify the
-  // bitmap or not.
-  virtual void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) = 0;
-
-  Heap* GetHeap() const {
-    return heap_;
-  }
-
- protected:
-  Heap* const heap_;
-};
-
-// Bitmap implementation.
-// DEPRECATED, performs strictly less well than merely caching which cards were dirty.
-class ModUnionTableBitmap : public ModUnionTable {
- public:
-  ModUnionTableBitmap(Heap* heap);
-  virtual ~ModUnionTableBitmap();
-
-  // Clear space cards.
-  void ClearCards(ContinuousSpace* space);
-
-  // Update table based on cleared cards.
-  void Update()
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Mark all references to the alloc space(s).
-  void MarkReferences(MarkSweep* mark_sweep) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
- protected:
-  // Cleared card array, used to update the mod-union table.
-  std::vector<byte*> cleared_cards_;
-
-  // One bitmap per image space.
-  // TODO: Add support for Zygote spaces?
-  typedef SafeMap<ContinuousSpace*, SpaceBitmap*> BitmapMap;
-  BitmapMap bitmaps_;
-};
-
-// Reference caching implementation. Caches references pointing to alloc space(s) for each card.
-class ModUnionTableReferenceCache : public ModUnionTable {
- public:
-  typedef SafeMap<const byte*, ReferenceArray > ReferenceMap;
-
-  ModUnionTableReferenceCache(Heap* heap);
-  virtual ~ModUnionTableReferenceCache();
-
-  // Clear and store cards for a space.
-  void ClearCards(ContinuousSpace* space);
-
-  // Update table based on cleared cards.
-  void Update()
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Mark all references to the alloc space(s).
-  void MarkReferences(MarkSweep* mark_sweep)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  // Exclusive lock is required since verify uses SpaceBitmap::VisitMarkedRange and
-  // VisitMarkedRange can't know if the callback will modify the bitmap or not.
-  void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  // Function that tells whether or not to add a reference to the table.
-  virtual bool AddReference(const mirror::Object* obj, const mirror::Object* ref) = 0;
-
- protected:
-  // Cleared card array, used to update the mod-union table.
-  ClearedCards cleared_cards_;
-
-  // Maps from dirty cards to their corresponding alloc space references.
-  ReferenceMap references_;
-};
-
-// Card caching implementation. Keeps track of which cards we cleared and only this information.
-class ModUnionTableCardCache : public ModUnionTable {
- public:
-  typedef SafeMap<const byte*, ReferenceArray > ReferenceMap;
-
-  ModUnionTableCardCache(Heap* heap);
-  virtual ~ModUnionTableCardCache();
-
-  // Clear and store cards for a space.
-  void ClearCards(ContinuousSpace* space);
-
-  // Nothing to update.
-  void Update() {}
-
-  // Mark all references to the alloc space(s).
-  void MarkReferences(MarkSweep* mark_sweep)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  // Nothing to verify.
-  void Verify() {}
-
- protected:
-  // Cleared card array, used to update the mod-union table.
-  ClearedCards cleared_cards_;
-};
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_MOD_UNION_TABLE_H_
diff --git a/src/gc/partial_mark_sweep.h b/src/gc/partial_mark_sweep.h
deleted file mode 100644
index 64c0bcd..0000000
--- a/src/gc/partial_mark_sweep.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_PARTIAL_MARK_SWEEP_H_
-#define ART_SRC_GC_PARTIAL_MARK_SWEEP_H_
-
-#include "locks.h"
-#include "mark_sweep.h"
-
-namespace art {
-
-class PartialMarkSweep : public MarkSweep {
- public:
-  virtual GcType GetGcType() const {
-    return kGcTypePartial;
-  }
-
-  explicit PartialMarkSweep(Heap* heap, bool is_concurrent);
-  ~PartialMarkSweep();
-
-protected:
-  virtual void BindBitmaps()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  DISALLOW_COPY_AND_ASSIGN(PartialMarkSweep);
-};
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_PARTIAL_MARK_SWEEP_H_
diff --git a/src/gc/space.h b/src/gc/space.h
deleted file mode 100644
index d2bcd53..0000000
--- a/src/gc/space.h
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_SRC_GC_SPACE_H_
-#define ART_SRC_GC_SPACE_H_
-
-#include <string>
-
-#include "UniquePtr.h"
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "globals.h"
-#include "image.h"
-#include "dlmalloc.h"
-#include "mem_map.h"
-
-namespace art {
-
-static const bool kDebugSpaces = kIsDebugBuild;
-
-namespace mirror {
-class Object;
-}  // namespace mirror
-class DlMallocSpace;
-class ImageSpace;
-class LargeObjectSpace;
-class SpaceBitmap;
-
-enum GcRetentionPolicy {
-  kGcRetentionPolicyNeverCollect,
-  kGcRetentionPolicyAlwaysCollect,
-  kGcRetentionPolicyFullCollect, // Collect only for full GC
-};
-std::ostream& operator<<(std::ostream& os, const GcRetentionPolicy& policy);
-
-enum SpaceType {
-  kSpaceTypeImageSpace,
-  kSpaceTypeAllocSpace,
-  kSpaceTypeZygoteSpace,
-  kSpaceTypeLargeObjectSpace,
-};
-std::ostream& operator<<(std::ostream& os, const SpaceType& space_type);
-
-// A space contains memory allocated for managed objects.
-class Space {
- public:
-  virtual bool CanAllocateInto() const = 0;
-  virtual bool IsCompactible() const = 0;
-  virtual bool Contains(const mirror::Object* obj) const = 0;
-  virtual SpaceType GetType() const = 0;
-  virtual GcRetentionPolicy GetGcRetentionPolicy() const = 0;
-  virtual std::string GetName() const = 0;
-
-  ImageSpace* AsImageSpace();
-  DlMallocSpace* AsAllocSpace();
-  DlMallocSpace* AsZygoteSpace();
-  LargeObjectSpace* AsLargeObjectSpace();
-
-  bool IsImageSpace() const {
-    return GetType() == kSpaceTypeImageSpace;
-  }
-
-  bool IsAllocSpace() const {
-    return GetType() == kSpaceTypeAllocSpace || GetType() == kSpaceTypeZygoteSpace;
-  }
-
-  bool IsZygoteSpace() const {
-    return GetType() == kSpaceTypeZygoteSpace;
-  }
-
-  bool IsLargeObjectSpace() const {
-    return GetType() == kSpaceTypeLargeObjectSpace;
-  }
-
-  virtual void Dump(std::ostream& /* os */) const { }
-
-  virtual ~Space() {}
-
- protected:
-  Space() { }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(Space);
-};
-
-// AllocSpace interface.
-class AllocSpace {
- public:
-  virtual bool CanAllocateInto() const {
-    return true;
-  }
-
-  // General statistics
-  virtual uint64_t GetNumBytesAllocated() const = 0;
-  virtual uint64_t GetNumObjectsAllocated() const = 0;
-  virtual uint64_t GetTotalBytesAllocated() const = 0;
-  virtual uint64_t GetTotalObjectsAllocated() const = 0;
-
-  // Allocate num_bytes without allowing growth.
-  virtual mirror::Object* Alloc(Thread* self, size_t num_bytes) = 0;
-
-  // Return the storage space required by obj.
-  virtual size_t AllocationSize(const mirror::Object* obj) = 0;
-
-  // Returns how many bytes were freed.
-  virtual size_t Free(Thread* self, mirror::Object* ptr) = 0;
-
-  // Returns how many bytes were freed.
-  virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) = 0;
-
- protected:
-  AllocSpace() {}
-  virtual ~AllocSpace() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AllocSpace);
-};
-
-// Continuous spaces have bitmaps, and an address range.
-class ContinuousSpace : public Space {
- public:
-  // Address at which the space begins
-  byte* Begin() const {
-    return begin_;
-  }
-
-  // Address at which the space ends, which may vary as the space is filled.
-  byte* End() const {
-    return end_;
-  }
-
-  // Current size of space
-  size_t Size() const {
-    return End() - Begin();
-  }
-
-  virtual SpaceBitmap* GetLiveBitmap() const = 0;
-  virtual SpaceBitmap* GetMarkBitmap() const = 0;
-
-  // Is object within this space?
-  bool HasAddress(const mirror::Object* obj) const {
-    const byte* byte_ptr = reinterpret_cast<const byte*>(obj);
-    return Begin() <= byte_ptr && byte_ptr < End();
-  }
-
-  virtual bool Contains(const mirror::Object* obj) const {
-    return HasAddress(obj);
-  }
-
-  virtual ~ContinuousSpace() {}
-
-  virtual std::string GetName() const {
-    return name_;
-  }
-
-  virtual GcRetentionPolicy GetGcRetentionPolicy() const {
-    return gc_retention_policy_;
-  }
-
- protected:
-  ContinuousSpace(const std::string& name, byte* begin, byte* end,
-                  GcRetentionPolicy gc_retention_policy);
-
-  std::string name_;
-  GcRetentionPolicy gc_retention_policy_;
-
-  // The beginning of the storage for fast access.
-  byte* begin_;
-
-  // Current end of the space.
-  byte* end_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ContinuousSpace);
-};
-
-class DiscontinuousSpace : public virtual Space {
- public:
-  // Is object within this space?
-  virtual bool Contains(const mirror::Object* obj) const = 0;
-
-  virtual std::string GetName() const {
-    return name_;
-  }
-
-  virtual GcRetentionPolicy GetGcRetentionPolicy() const {
-    return gc_retention_policy_;
-  }
-
-protected:
-  DiscontinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy);
-
-private:
-  std::string name_;
-  GcRetentionPolicy gc_retention_policy_;
-
-  DISALLOW_COPY_AND_ASSIGN(DiscontinuousSpace);
-};
-
-std::ostream& operator<<(std::ostream& os, const Space& space);
-
-class MemMapSpace : public ContinuousSpace {
- public:
-  // Maximum which the mapped space can grow to.
-  virtual size_t Capacity() const {
-    return mem_map_->Size();
-  }
-
-  // Size of the space without a limit on its growth. By default this is just the Capacity, but
-  // for the allocation space we support starting with a small heap and then extending it.
-  virtual size_t NonGrowthLimitCapacity() const {
-    return Capacity();
-  }
-
- protected:
-  MemMapSpace(const std::string& name, MemMap* mem_map, size_t initial_size,
-              GcRetentionPolicy gc_retention_policy);
-
-  MemMap* GetMemMap() {
-    return mem_map_.get();
-  }
-
-  const MemMap* GetMemMap() const {
-    return mem_map_.get();
-  }
-
- private:
-  // Underlying storage of the space
-  UniquePtr<MemMap> mem_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(MemMapSpace);
-};
-
-// An alloc space is a space where objects may be allocated and garbage collected.
-class DlMallocSpace : public MemMapSpace, public AllocSpace {
- public:
-  typedef void(*WalkCallback)(void *start, void *end, size_t num_bytes, void* callback_arg);
-
-  virtual bool CanAllocateInto() const {
-    return true;
-  }
-
-  virtual bool IsCompactible() const {
-    return false;
-  }
-
-  virtual SpaceType GetType() const {
-    return kSpaceTypeAllocSpace;
-  }
-
-  // Create a AllocSpace with the requested sizes. The requested
-  // base address is not guaranteed to be granted, if it is required,
-  // the caller should call Begin on the returned space to confirm
-  // the request was granted.
-  static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
-                            size_t capacity, byte* requested_begin);
-
-  // Allocate num_bytes without allowing the underlying mspace to grow.
-  virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes);
-
-  // Allocate num_bytes allowing the underlying mspace to grow.
-  virtual mirror::Object* Alloc(Thread* self, size_t num_bytes);
-
-  // Return the storage space required by obj.
-  virtual size_t AllocationSize(const mirror::Object* obj);
-  virtual size_t Free(Thread* self, mirror::Object* ptr);
-  virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs);
-
-  void* MoreCore(intptr_t increment);
-
-  void* GetMspace() const {
-    return mspace_;
-  }
-
-  // Hands unused pages back to the system.
-  size_t Trim();
-
-  // Perform a mspace_inspect_all which calls back for each allocation chunk. The chunk may not be
-  // in use, indicated by num_bytes equaling zero.
-  void Walk(WalkCallback callback, void* arg);
-
-  // Returns the number of bytes that the heap is allowed to obtain from the system via MoreCore.
-  size_t GetFootprintLimit();
-
-  // Set the maximum number of bytes that the heap is allowed to obtain from the system via
-  // MoreCore. Note this is used to stop the mspace growing beyond the limit to Capacity. When
-  // allocations fail we GC before increasing the footprint limit and allowing the mspace to grow.
-  void SetFootprintLimit(size_t limit);
-
-  // Removes the fork time growth limit on capacity, allowing the application to allocate up to the
-  // maximum reserved size of the heap.
-  void ClearGrowthLimit() {
-    growth_limit_ = NonGrowthLimitCapacity();
-  }
-
-  // Override capacity so that we only return the possibly limited capacity
-  virtual size_t Capacity() const {
-    return growth_limit_;
-  }
-
-  // The total amount of memory reserved for the alloc space
-  virtual size_t NonGrowthLimitCapacity() const {
-    return GetMemMap()->Size();
-  }
-
-  virtual SpaceBitmap* GetLiveBitmap() const {
-    return live_bitmap_.get();
-  }
-
-  virtual SpaceBitmap* GetMarkBitmap() const {
-    return mark_bitmap_.get();
-  }
-
-  virtual void Dump(std::ostream& os) const;
-
-  void SetGrowthLimit(size_t growth_limit);
-
-  // Swap the live and mark bitmaps of this space. This is used by the GC for concurrent sweeping.
-  virtual void SwapBitmaps();
-
-  // Turn ourself into a zygote space and return a new alloc space which has our unused memory.
-  DlMallocSpace* CreateZygoteSpace();
-
-  void SetGcRetentionPolicy(GcRetentionPolicy gc_retention_policy) {
-    gc_retention_policy_ = gc_retention_policy;
-  }
-
-  virtual uint64_t GetNumBytesAllocated() const {
-    return num_bytes_allocated_;
-  }
-
-  virtual uint64_t GetNumObjectsAllocated() const {
-    return num_objects_allocated_;
-  }
-
-  virtual uint64_t GetTotalBytesAllocated() const {
-    return total_bytes_allocated_;
-  }
-
-  virtual uint64_t GetTotalObjectsAllocated() const {
-    return total_objects_allocated_;
-  }
-
- private:
-  size_t InternalAllocationSize(const mirror::Object* obj);
-  mirror::Object* AllocWithoutGrowthLocked(size_t num_bytes) EXCLUSIVE_LOCKS_REQUIRED(lock_);
-
-  UniquePtr<SpaceBitmap> live_bitmap_;
-  UniquePtr<SpaceBitmap> mark_bitmap_;
-  UniquePtr<SpaceBitmap> temp_bitmap_;
-
-  // Approximate number of bytes which have been allocated into the space.
-  size_t num_bytes_allocated_;
-  size_t num_objects_allocated_;
-  size_t total_bytes_allocated_;
-  size_t total_objects_allocated_;
-
-  static size_t bitmap_index_;
-
-  DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin, byte* end,
-             size_t growth_limit);
-
-  bool Init(size_t initial_size, size_t maximum_size, size_t growth_size, byte* requested_base);
-
-  static void* CreateMallocSpace(void* base, size_t morecore_start, size_t initial_size);
-
-  // The boundary tag overhead.
-  static const size_t kChunkOverhead = kWordSize;
-
-  // Used to ensure mutual exclusion when the allocation spaces data structures are being modified.
-  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-
-  // Underlying malloc space
-  void* const mspace_;
-
-  // The capacity of the alloc space until such time that ClearGrowthLimit is called.
-  // The underlying mem_map_ controls the maximum size we allow the heap to grow to. The growth
-  // limit is a value <= to the mem_map_ capacity used for ergonomic reasons because of the zygote.
-  // Prior to forking the zygote the heap will have a maximally sized mem_map_ but the growth_limit_
-  // will be set to a lower value. The growth_limit_ is used as the capacity of the alloc_space_,
-  // however, capacity normally can't vary. In the case of the growth_limit_ it can be cleared
-  // one time by a call to ClearGrowthLimit.
-  size_t growth_limit_;
-
-  friend class MarkSweep;
-
-  DISALLOW_COPY_AND_ASSIGN(DlMallocSpace);
-};
-
-// An image space is a space backed with a memory mapped image
-class ImageSpace : public MemMapSpace {
- public:
-  virtual bool CanAllocateInto() const {
-    return false;
-  }
-
-  virtual bool IsCompactible() const {
-    return false;
-  }
-
-  virtual SpaceType GetType() const {
-    return kSpaceTypeImageSpace;
-  }
-
-  // create a Space from an image file. cannot be used for future allocation or collected.
-  static ImageSpace* Create(const std::string& image)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  const ImageHeader& GetImageHeader() const {
-    return *reinterpret_cast<ImageHeader*>(Begin());
-  }
-
-  const std::string GetImageFilename() const {
-    return GetName();
-  }
-
-  // Mark the objects defined in this space in the given live bitmap
-  void RecordImageAllocations(SpaceBitmap* live_bitmap) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  virtual SpaceBitmap* GetLiveBitmap() const {
-    return live_bitmap_.get();
-  }
-
-  virtual SpaceBitmap* GetMarkBitmap() const {
-    // ImageSpaces have the same bitmap for both live and marked. This helps reduce the number of
-    // special cases to test against.
-    return live_bitmap_.get();
-  }
-
-  virtual void Dump(std::ostream& os) const;
-
- private:
-  friend class Space;
-
-  UniquePtr<SpaceBitmap> live_bitmap_;
-  static size_t bitmap_index_;
-
-  ImageSpace(const std::string& name, MemMap* mem_map);
-
-  DISALLOW_COPY_AND_ASSIGN(ImageSpace);
-};
-
-// Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
-// pages back to the kernel.
-void MspaceMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/);
-
-}  // namespace art
-
-#endif  // ART_SRC_GC_SPACE_H_
diff --git a/src/gc/space.cc b/src/gc/space/dlmalloc_space.cc
similarity index 63%
rename from src/gc/space.cc
rename to src/gc/space/dlmalloc_space.cc
index 1d3ee28..02acd28 100644
--- a/src/gc/space.cc
+++ b/src/gc/space/dlmalloc_space.cc
@@ -13,33 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#include "space.h"
-
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/unix_file/fd_file.h"
-#include "card_table.h"
-#include "dlmalloc.h"
-#include "image.h"
-#include "mirror/array.h"
-#include "mirror/abstract_method.h"
-#include "mirror/class-inl.h"
-#include "mirror/object-inl.h"
-#include "os.h"
+#include "dlmalloc_space.h"
+#include "gc/accounting/card_table.h"
+#include "gc/heap.h"
 #include "runtime.h"
-#include "space_bitmap.h"
-#include "space_bitmap-inl.h"
 #include "thread.h"
-#include "UniquePtr.h"
 #include "utils.h"
 
+//#include <valgrind/memcheck.h>
+#include <valgrind.h>
+
 namespace art {
-
-static const bool kPrefetchDuringDlMallocFreeList = true;
-
-// Magic padding value that we use to check for buffer overruns.
-static const word kPaddingValue = 0xBAC0BAC0;
+namespace gc {
+namespace space {
 
 // TODO: Remove define macro
 #define CHECK_MEMORY_CALL(call, args, what) \
@@ -51,45 +37,86 @@
     } \
   } while (false)
 
-ImageSpace* Space::AsImageSpace() {
-  DCHECK_EQ(GetType(), kSpaceTypeImageSpace);
-  return down_cast<ImageSpace*>(down_cast<MemMapSpace*>(this));
-}
+static const bool kPrefetchDuringDlMallocFreeList = true;
 
-DlMallocSpace* Space::AsAllocSpace() {
-  DCHECK_EQ(GetType(), kSpaceTypeAllocSpace);
-  return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
-}
+// Number of bytes to use as a red zone (rdz). A red zone of this size will be placed before and
+// after each allocation. 8 bytes provides long/double alignment.
+const size_t kValgrindRedZoneBytes = 8;
 
-DlMallocSpace* Space::AsZygoteSpace() {
-  DCHECK_EQ(GetType(), kSpaceTypeZygoteSpace);
-  return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
-}
+// A specialization of DlMallocSpace that provides information to valgrind wrt allocations.
+class ValgrindDlMallocSpace : public DlMallocSpace {
+ public:
+  virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes) {
+    void* obj_with_rdz = DlMallocSpace::AllocWithGrowth(self, num_bytes + (2 * kValgrindRedZoneBytes));
+    if (obj_with_rdz != NULL) {
+      //VALGRIND_MAKE_MEM_UNDEFINED();
+      mirror::Object* result = reinterpret_cast<mirror::Object*>(reinterpret_cast<byte*>(obj_with_rdz) +
+                                                                 kValgrindRedZoneBytes);
+      VALGRIND_MEMPOOL_ALLOC(GetMspace(), result, num_bytes);
+      LOG(INFO) << "AllocWithGrowth on " << self << " = " << obj_with_rdz
+          << " of size " << num_bytes;
+      return result;
+    } else {
+      return NULL;
+    }
+  }
 
-LargeObjectSpace* Space::AsLargeObjectSpace() {
-  DCHECK_EQ(GetType(), kSpaceTypeLargeObjectSpace);
-  return reinterpret_cast<LargeObjectSpace*>(this);
-}
+  virtual mirror::Object* Alloc(Thread* self, size_t num_bytes) {
+    void* obj_with_rdz = DlMallocSpace::Alloc(self, num_bytes + (2 * kValgrindRedZoneBytes));
+    if (obj_with_rdz != NULL) {
+      mirror::Object* result = reinterpret_cast<mirror::Object*>(reinterpret_cast<byte*>(obj_with_rdz) +
+                                                                 kValgrindRedZoneBytes);
+      VALGRIND_MEMPOOL_ALLOC(GetMspace(), result, num_bytes);
+      LOG(INFO) << "Alloc on " << self << " = " << obj_with_rdz
+          << " of size " << num_bytes;
+      return result;
+    } else {
+      return NULL;
+    }
+  }
 
-ContinuousSpace::ContinuousSpace(const std::string& name, byte* begin, byte* end,
-                                 GcRetentionPolicy gc_retention_policy)
-    : name_(name), gc_retention_policy_(gc_retention_policy), begin_(begin), end_(end) {
+  virtual size_t AllocationSize(const mirror::Object* obj) {
+    const void* obj_after_rdz = reinterpret_cast<const void*>(obj);
+    size_t result = DlMallocSpace::AllocationSize(
+        reinterpret_cast<const mirror::Object*>(reinterpret_cast<const byte*>(obj_after_rdz) -
+                                                kValgrindRedZoneBytes));
+    return result - (2 * kValgrindRedZoneBytes);
+  }
 
-}
+  virtual size_t Free(Thread* self, mirror::Object* ptr) {
+    void* obj_after_rdz = reinterpret_cast<void*>(ptr);
+    void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
+    LOG(INFO) << "Free on " << self << " of " << obj_with_rdz;
+    size_t freed = DlMallocSpace::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
+    VALGRIND_MEMPOOL_FREE(GetMspace(), obj_after_rdz);
+    return freed - (2 * kValgrindRedZoneBytes);
+  }
 
-DiscontinuousSpace::DiscontinuousSpace(const std::string& name,
-                                       GcRetentionPolicy gc_retention_policy)
-    : name_(name), gc_retention_policy_(gc_retention_policy) {
+  virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
+    size_t freed = 0;
+    for (size_t i = 0; i < num_ptrs; i++) {
+      void* obj_after_rdz = reinterpret_cast<void*>(ptrs[i]);
+      void* obj_with_rdz = reinterpret_cast<byte*>(obj_after_rdz) - kValgrindRedZoneBytes;
+      LOG(INFO) << "FreeList on " << self << " of " << obj_with_rdz;
+      freed += DlMallocSpace::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
+      VALGRIND_MEMPOOL_FREE(GetMspace(), obj_after_rdz);
+    }
+    return freed - (2 * kValgrindRedZoneBytes * num_ptrs);
+  }
 
-}
+  ValgrindDlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
+                        byte* end, size_t growth_limit) :
+      DlMallocSpace(name, mem_map, mspace, begin, end, growth_limit) {
+    VALGRIND_CREATE_MEMPOOL(GetMspace(), kValgrindRedZoneBytes, true);
+  }
 
-MemMapSpace::MemMapSpace(const std::string& name, MemMap* mem_map, size_t initial_size,
-                         GcRetentionPolicy gc_retention_policy)
-    : ContinuousSpace(name, mem_map->Begin(), mem_map->Begin() + initial_size, gc_retention_policy),
-      mem_map_(mem_map)
-{
+  virtual ~ValgrindDlMallocSpace() {
+    VALGRIND_DESTROY_MEMPOOL(GetMspace());
+  }
 
-}
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ValgrindDlMallocSpace);
+};
 
 size_t DlMallocSpace::bitmap_index_ = 0;
 
@@ -103,15 +130,15 @@
 
   size_t bitmap_index = bitmap_index_++;
 
-  static const uintptr_t kGcCardSize = static_cast<uintptr_t>(CardTable::kCardSize);
+  static const uintptr_t kGcCardSize = static_cast<uintptr_t>(accounting::CardTable::kCardSize);
   CHECK(reinterpret_cast<uintptr_t>(mem_map->Begin()) % kGcCardSize == 0);
   CHECK(reinterpret_cast<uintptr_t>(mem_map->End()) % kGcCardSize == 0);
-  live_bitmap_.reset(SpaceBitmap::Create(
+  live_bitmap_.reset(accounting::SpaceBitmap::Create(
       StringPrintf("allocspace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
       Begin(), Capacity()));
   DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace live bitmap #" << bitmap_index;
 
-  mark_bitmap_.reset(SpaceBitmap::Create(
+  mark_bitmap_.reset(accounting::SpaceBitmap::Create(
       StringPrintf("allocspace %s mark-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
       Begin(), Capacity()));
   DCHECK(live_bitmap_.get() != NULL) << "could not create allocspace mark bitmap #" << bitmap_index;
@@ -177,8 +204,13 @@
 
   // Everything is set so record in immutable structure and leave
   MemMap* mem_map_ptr = mem_map.release();
-  DlMallocSpace* space = new DlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end,
-                                           growth_limit);
+  DlMallocSpace* space;
+  if (RUNNING_ON_VALGRIND > 0) {
+    space = new ValgrindDlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end,
+                                      growth_limit);
+  } else {
+    space = new DlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end, growth_limit);
+  }
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
     LOG(INFO) << "Space::CreateAllocSpace exiting (" << PrettyDuration(NanoTime() - start_time)
         << " ) " << *space;
@@ -203,33 +235,26 @@
 }
 
 void DlMallocSpace::SwapBitmaps() {
-  SpaceBitmap* temp_live_bitmap = live_bitmap_.release();
-  live_bitmap_.reset(mark_bitmap_.release());
-  mark_bitmap_.reset(temp_live_bitmap);
+  live_bitmap_.swap(mark_bitmap_);
   // Swap names to get more descriptive diagnostics.
-  std::string temp_name = live_bitmap_->GetName();
+  std::string temp_name(live_bitmap_->GetName());
   live_bitmap_->SetName(mark_bitmap_->GetName());
   mark_bitmap_->SetName(temp_name);
 }
 
 mirror::Object* DlMallocSpace::AllocWithoutGrowthLocked(size_t num_bytes) {
-  if (kDebugSpaces) {
-    num_bytes += sizeof(word);
-  }
-
   mirror::Object* result = reinterpret_cast<mirror::Object*>(mspace_calloc(mspace_, 1, num_bytes));
-  if (kDebugSpaces && result != NULL) {
-    CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
-        << ") not in bounds of allocation space " << *this;
-    // Put a magic pattern before and after the allocation.
-    *reinterpret_cast<word*>(reinterpret_cast<byte*>(result) + AllocationSize(result)
-        - sizeof(word) - kChunkOverhead) = kPaddingValue;
+  if (result != NULL) {
+    if (kDebugSpaces) {
+      CHECK(Contains(result)) << "Allocation (" << reinterpret_cast<void*>(result)
+            << ") not in bounds of allocation space " << *this;
+    }
+    size_t allocation_size = AllocationSize(result);
+    num_bytes_allocated_ += allocation_size;
+    total_bytes_allocated_ += allocation_size;
+    ++total_objects_allocated_;
+    ++num_objects_allocated_;
   }
-  size_t allocation_size = AllocationSize(result);
-  num_bytes_allocated_ += allocation_size;
-  total_bytes_allocated_ += allocation_size;
-  ++total_objects_allocated_;
-  ++num_objects_allocated_;
   return result;
 }
 
@@ -263,8 +288,8 @@
 
 DlMallocSpace* DlMallocSpace::CreateZygoteSpace() {
   end_ = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(end_), kPageSize));
-  DCHECK(IsAligned<CardTable::kCardSize>(begin_));
-  DCHECK(IsAligned<CardTable::kCardSize>(end_));
+  DCHECK(IsAligned<accounting::CardTable::kCardSize>(begin_));
+  DCHECK(IsAligned<accounting::CardTable::kCardSize>(end_));
   DCHECK(IsAligned<kPageSize>(begin_));
   DCHECK(IsAligned<kPageSize>(end_));
   size_t size = RoundUp(Size(), kPageSize);
@@ -291,7 +316,7 @@
   VLOG(heap) << "Size " << GetMemMap()->Size();
   VLOG(heap) << "GrowthLimit " << PrettySize(growth_limit);
   VLOG(heap) << "Capacity " << PrettySize(capacity);
-  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(GetName().c_str(), End(), capacity, PROT_READ | PROT_WRITE));
+  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(GetName(), 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;
@@ -314,9 +339,6 @@
   if (kDebugSpaces) {
     CHECK(ptr != NULL);
     CHECK(Contains(ptr)) << "Free (" << ptr << ") not in bounds of heap " << *this;
-    CHECK_EQ(
-        *reinterpret_cast<word*>(reinterpret_cast<byte*>(ptr) + AllocationSize(ptr) -
-            sizeof(word) - kChunkOverhead), kPaddingValue);
   }
   const size_t bytes_freed = InternalAllocationSize(ptr);
   num_bytes_allocated_ -= bytes_freed;
@@ -374,20 +396,16 @@
   lock_.AssertHeld(Thread::Current());
   byte* original_end = end_;
   if (increment != 0) {
-    VLOG(heap) << "AllocSpace::MoreCore " << PrettySize(increment);
+    VLOG(heap) << "DlMallocSpace::MoreCore " << PrettySize(increment);
     byte* new_end = original_end + increment;
     if (increment > 0) {
-#if DEBUG_SPACES
       // Should never be asked to increase the allocation beyond the capacity of the space. Enforced
       // by mspace_set_footprint_limit.
       CHECK_LE(new_end, Begin() + Capacity());
-#endif
       CHECK_MEMORY_CALL(mprotect, (original_end, increment, PROT_READ | PROT_WRITE), GetName());
     } else {
-#if DEBUG_SPACES
       // Should never be asked for negative footprint (ie before begin)
       CHECK_GT(original_end + increment, Begin());
-#endif
       // Advise we don't need the pages and protect them
       // TODO: by removing permissions to the pages we may be causing TLB shoot-down which can be
       // expensive (note the same isn't true for giving permissions to a page as the protected
@@ -414,29 +432,13 @@
   return InternalAllocationSize(obj);
 }
 
-void MspaceMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) {
-  // Is this chunk in use?
-  if (used_bytes != 0) {
-    return;
-  }
-  // Do we have any whole pages to give back?
-  start = reinterpret_cast<void*>(RoundUp(reinterpret_cast<uintptr_t>(start), kPageSize));
-  end = reinterpret_cast<void*>(RoundDown(reinterpret_cast<uintptr_t>(end), kPageSize));
-  if (end > start) {
-    size_t length = reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start);
-    CHECK_MEMORY_CALL(madvise, (start, length, MADV_DONTNEED), "trim");
-    size_t* reclaimed = reinterpret_cast<size_t*>(arg);
-    *reclaimed += length;
-  }
-}
-
 size_t DlMallocSpace::Trim() {
   MutexLock mu(Thread::Current(), lock_);
   // Trim to release memory at the end of the space.
   mspace_trim(mspace_, 0);
   // Visit space looking for page-sized holes to advise the kernel we don't need.
   size_t reclaimed = 0;
-  mspace_inspect_all(mspace_, MspaceMadviseCallback, &reclaimed);
+  mspace_inspect_all(mspace_, DlmallocMadviseCallback, &reclaimed);
   return reclaimed;
 }
 
@@ -465,111 +467,14 @@
   mspace_set_footprint_limit(mspace_, new_size);
 }
 
-size_t ImageSpace::bitmap_index_ = 0;
-
-ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map)
-    : MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
-  const size_t bitmap_index = bitmap_index_++;
-  live_bitmap_.reset(SpaceBitmap::Create(
-      StringPrintf("imagespace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
-      Begin(), Capacity()));
-  DCHECK(live_bitmap_.get() != NULL) << "could not create imagespace live bitmap #" << bitmap_index;
-}
-
-ImageSpace* ImageSpace::Create(const std::string& image_file_name) {
-  CHECK(!image_file_name.empty());
-
-  uint64_t start_time = 0;
-  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
-    start_time = NanoTime();
-    LOG(INFO) << "Space::CreateImageSpace entering" << " image_file_name=" << image_file_name;
-  }
-
-  UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
-  if (file.get() == NULL) {
-    LOG(ERROR) << "Failed to open " << image_file_name;
-    return NULL;
-  }
-  ImageHeader image_header;
-  bool success = file->ReadFully(&image_header, sizeof(image_header));
-  if (!success || !image_header.IsValid()) {
-    LOG(ERROR) << "Invalid image header " << image_file_name;
-    return NULL;
-  }
-  UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
-                                                 file->GetLength(),
-                                                 PROT_READ | PROT_WRITE,
-                                                 MAP_PRIVATE | MAP_FIXED,
-                                                 file->Fd(),
-                                                 0,
-                                                 false));
-  if (map.get() == NULL) {
-    LOG(ERROR) << "Failed to map " << image_file_name;
-    return NULL;
-  }
-  CHECK_EQ(image_header.GetImageBegin(), map->Begin());
-  DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
-
-  Runtime* runtime = Runtime::Current();
-  mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
-  runtime->SetResolutionMethod(down_cast<mirror::AbstractMethod*>(resolution_method));
-
-  mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kSaveAll);
-  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsOnly);
-  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
-  runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsAndArgs);
-
-  ImageSpace* space = new ImageSpace(image_file_name, map.release());
-  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
-    LOG(INFO) << "Space::CreateImageSpace exiting (" << PrettyDuration(NanoTime() - start_time)
-        << ") " << *space;
-  }
-  return space;
-}
-
-void ImageSpace::RecordImageAllocations(SpaceBitmap* live_bitmap) const {
-  uint64_t start_time = 0;
-  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
-    LOG(INFO) << "ImageSpace::RecordImageAllocations entering";
-    start_time = NanoTime();
-  }
-  DCHECK(!Runtime::Current()->IsStarted());
-  CHECK(live_bitmap != NULL);
-  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
-  byte* end = End();
-  while (current < end) {
-    DCHECK_ALIGNED(current, kObjectAlignment);
-    const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current);
-    live_bitmap->Set(obj);
-    current += RoundUp(obj->SizeOf(), kObjectAlignment);
-  }
-  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
-    LOG(INFO) << "ImageSpace::RecordImageAllocations exiting ("
-        << PrettyDuration(NanoTime() - start_time) << ")";
-  }
-}
-
-std::ostream& operator<<(std::ostream& os, const Space& space) {
-  space.Dump(os);
-  return os;
-}
-
 void DlMallocSpace::Dump(std::ostream& os) const {
   os << GetType()
-      << "begin=" << reinterpret_cast<void*>(Begin())
+      << " begin=" << reinterpret_cast<void*>(Begin())
       << ",end=" << reinterpret_cast<void*>(End())
       << ",size=" << PrettySize(Size()) << ",capacity=" << PrettySize(Capacity())
       << ",name=\"" << GetName() << "\"]";
 }
 
-void ImageSpace::Dump(std::ostream& os) const {
-  os << GetType()
-      << "begin=" << reinterpret_cast<void*>(Begin())
-      << ",end=" << reinterpret_cast<void*>(End())
-      << ",size=" << PrettySize(Size())
-      << ",name=\"" << GetName() << "\"]";
-}
-
+}  // namespace space
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/space/dlmalloc_space.h b/src/gc/space/dlmalloc_space.h
new file mode 100644
index 0000000..00df0e6
--- /dev/null
+++ b/src/gc/space/dlmalloc_space.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_SPACE_DLMALLOC_SPACE_H_
+#define ART_SRC_GC_SPACE_DLMALLOC_SPACE_H_
+
+#include "gc/allocator/dlmalloc.h"
+#include "space.h"
+
+namespace art {
+namespace gc {
+
+namespace collector {
+  class MarkSweep;
+}  // namespace collector
+
+namespace space {
+
+// An alloc space is a space where objects may be allocated and garbage collected.
+class DlMallocSpace : public MemMapSpace, public AllocSpace {
+ public:
+  typedef void(*WalkCallback)(void *start, void *end, size_t num_bytes, void* callback_arg);
+
+  SpaceType GetType() const {
+    if (GetGcRetentionPolicy() == kGcRetentionPolicyFullCollect) {
+      return kSpaceTypeZygoteSpace;
+    } else {
+      return kSpaceTypeAllocSpace;
+    }
+  }
+
+  // Create a AllocSpace with the requested sizes. The requested
+  // base address is not guaranteed to be granted, if it is required,
+  // the caller should call Begin on the returned space to confirm
+  // the request was granted.
+  static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
+                               size_t capacity, byte* requested_begin);
+
+  // Allocate num_bytes without allowing the underlying mspace to grow.
+  virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes);
+
+  // Allocate num_bytes allowing the underlying mspace to grow.
+  virtual mirror::Object* Alloc(Thread* self, size_t num_bytes);
+
+  // Return the storage space required by obj.
+  virtual size_t AllocationSize(const mirror::Object* obj);
+  virtual size_t Free(Thread* self, mirror::Object* ptr);
+  virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs);
+
+  void* MoreCore(intptr_t increment);
+
+  void* GetMspace() const {
+    return mspace_;
+  }
+
+  // Hands unused pages back to the system.
+  size_t Trim();
+
+  // Perform a mspace_inspect_all which calls back for each allocation chunk. The chunk may not be
+  // in use, indicated by num_bytes equaling zero.
+  void Walk(WalkCallback callback, void* arg);
+
+  // Returns the number of bytes that the heap is allowed to obtain from the system via MoreCore.
+  size_t GetFootprintLimit();
+
+  // Set the maximum number of bytes that the heap is allowed to obtain from the system via
+  // MoreCore. Note this is used to stop the mspace growing beyond the limit to Capacity. When
+  // allocations fail we GC before increasing the footprint limit and allowing the mspace to grow.
+  void SetFootprintLimit(size_t limit);
+
+  // Removes the fork time growth limit on capacity, allowing the application to allocate up to the
+  // maximum reserved size of the heap.
+  void ClearGrowthLimit() {
+    growth_limit_ = NonGrowthLimitCapacity();
+  }
+
+  // Override capacity so that we only return the possibly limited capacity
+  size_t Capacity() const {
+    return growth_limit_;
+  }
+
+  // The total amount of memory reserved for the alloc space.
+  size_t NonGrowthLimitCapacity() const {
+    return GetMemMap()->Size();
+  }
+
+  accounting::SpaceBitmap* GetLiveBitmap() const {
+    return live_bitmap_.get();
+  }
+
+  accounting::SpaceBitmap* GetMarkBitmap() const {
+    return mark_bitmap_.get();
+  }
+
+  void Dump(std::ostream& os) const;
+
+  void SetGrowthLimit(size_t growth_limit);
+
+  // Swap the live and mark bitmaps of this space. This is used by the GC for concurrent sweeping.
+  void SwapBitmaps();
+
+  // Turn ourself into a zygote space and return a new alloc space which has our unused memory.
+  DlMallocSpace* CreateZygoteSpace();
+
+  uint64_t GetBytesAllocated() const {
+    return num_bytes_allocated_;
+  }
+
+  uint64_t GetObjectsAllocated() const {
+    return num_objects_allocated_;
+  }
+
+  uint64_t GetTotalBytesAllocated() const {
+    return total_bytes_allocated_;
+  }
+
+  uint64_t GetTotalObjectsAllocated() const {
+    return total_objects_allocated_;
+  }
+
+ protected:
+  DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin, byte* end,
+                size_t growth_limit);
+
+ private:
+  size_t InternalAllocationSize(const mirror::Object* obj);
+  mirror::Object* AllocWithoutGrowthLocked(size_t num_bytes) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+  bool Init(size_t initial_size, size_t maximum_size, size_t growth_size, byte* requested_base);
+
+  static void* CreateMallocSpace(void* base, size_t morecore_start, size_t initial_size);
+
+  UniquePtr<accounting::SpaceBitmap> live_bitmap_;
+  UniquePtr<accounting::SpaceBitmap> mark_bitmap_;
+  UniquePtr<accounting::SpaceBitmap> temp_bitmap_;
+
+  // Approximate number of bytes which have been allocated into the space.
+  size_t num_bytes_allocated_;
+  size_t num_objects_allocated_;
+  size_t total_bytes_allocated_;
+  size_t total_objects_allocated_;
+
+  static size_t bitmap_index_;
+
+  // The boundary tag overhead.
+  static const size_t kChunkOverhead = kWordSize;
+
+  // Used to ensure mutual exclusion when the allocation spaces data structures are being modified.
+  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+
+  // Underlying malloc space
+  void* const mspace_;
+
+  // The capacity of the alloc space until such time that ClearGrowthLimit is called.
+  // The underlying mem_map_ controls the maximum size we allow the heap to grow to. The growth
+  // limit is a value <= to the mem_map_ capacity used for ergonomic reasons because of the zygote.
+  // Prior to forking the zygote the heap will have a maximally sized mem_map_ but the growth_limit_
+  // will be set to a lower value. The growth_limit_ is used as the capacity of the alloc_space_,
+  // however, capacity normally can't vary. In the case of the growth_limit_ it can be cleared
+  // one time by a call to ClearGrowthLimit.
+  size_t growth_limit_;
+
+  friend class collector::MarkSweep;
+
+  DISALLOW_COPY_AND_ASSIGN(DlMallocSpace);
+};
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_SPACE_DLMALLOC_SPACE_H_
diff --git a/src/gc/space/image_space.cc b/src/gc/space/image_space.cc
new file mode 100644
index 0000000..46c3937
--- /dev/null
+++ b/src/gc/space/image_space.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "image_space.h"
+
+#include "base/unix_file/fd_file.h"
+#include "gc/accounting/space_bitmap-inl.h"
+#include "mirror/abstract_method.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "os.h"
+#include "runtime.h"
+#include "space-inl.h"
+#include "utils.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+size_t ImageSpace::bitmap_index_ = 0;
+
+ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map)
+: MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
+  const size_t bitmap_index = bitmap_index_++;
+  live_bitmap_.reset(accounting::SpaceBitmap::Create(
+      StringPrintf("imagespace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
+      Begin(), Capacity()));
+  DCHECK(live_bitmap_.get() != NULL) << "could not create imagespace live bitmap #" << bitmap_index;
+}
+
+ImageSpace* ImageSpace::Create(const std::string& image_file_name) {
+  CHECK(!image_file_name.empty());
+
+  uint64_t start_time = 0;
+  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+    start_time = NanoTime();
+    LOG(INFO) << "Space::CreateImageSpace entering" << " image_file_name=" << image_file_name;
+  }
+
+  UniquePtr<File> file(OS::OpenFile(image_file_name.c_str(), false));
+  if (file.get() == NULL) {
+    LOG(ERROR) << "Failed to open " << image_file_name;
+    return NULL;
+  }
+  ImageHeader image_header;
+  bool success = file->ReadFully(&image_header, sizeof(image_header));
+  if (!success || !image_header.IsValid()) {
+    LOG(ERROR) << "Invalid image header " << image_file_name;
+    return NULL;
+  }
+  UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
+                                                 file->GetLength(),
+                                                 PROT_READ | PROT_WRITE,
+                                                 MAP_PRIVATE | MAP_FIXED,
+                                                 file->Fd(),
+                                                 0,
+                                                 false));
+  if (map.get() == NULL) {
+    LOG(ERROR) << "Failed to map " << image_file_name;
+    return NULL;
+  }
+  CHECK_EQ(image_header.GetImageBegin(), map->Begin());
+  DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
+
+  Runtime* runtime = Runtime::Current();
+  mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
+  runtime->SetResolutionMethod(down_cast<mirror::AbstractMethod*>(resolution_method));
+
+  mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kSaveAll);
+  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsOnly);
+  callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
+  runtime->SetCalleeSaveMethod(down_cast<mirror::AbstractMethod*>(callee_save_method), Runtime::kRefsAndArgs);
+
+  ImageSpace* space = new ImageSpace(image_file_name, map.release());
+  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+    LOG(INFO) << "Space::CreateImageSpace exiting (" << PrettyDuration(NanoTime() - start_time)
+             << ") " << *space;
+  }
+  return space;
+}
+
+void ImageSpace::RecordImageAllocations(accounting::SpaceBitmap* live_bitmap) const {
+  uint64_t start_time = 0;
+  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+    LOG(INFO) << "ImageSpace::RecordImageAllocations entering";
+    start_time = NanoTime();
+  }
+  DCHECK(!Runtime::Current()->IsStarted());
+  CHECK(live_bitmap != NULL);
+  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
+  byte* end = End();
+  while (current < end) {
+    DCHECK_ALIGNED(current, kObjectAlignment);
+    const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current);
+    live_bitmap->Set(obj);
+    current += RoundUp(obj->SizeOf(), kObjectAlignment);
+  }
+  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
+    LOG(INFO) << "ImageSpace::RecordImageAllocations exiting ("
+        << PrettyDuration(NanoTime() - start_time) << ")";
+  }
+}
+
+void ImageSpace::Dump(std::ostream& os) const {
+  os << GetType()
+      << "begin=" << reinterpret_cast<void*>(Begin())
+      << ",end=" << reinterpret_cast<void*>(End())
+      << ",size=" << PrettySize(Size())
+      << ",name=\"" << GetName() << "\"]";
+}
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/space/image_space.h b/src/gc/space/image_space.h
new file mode 100644
index 0000000..afec5b7
--- /dev/null
+++ b/src/gc/space/image_space.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_SPACE_IMAGE_SPACE_H_
+#define ART_SRC_GC_SPACE_IMAGE_SPACE_H_
+
+#include "space.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+// An image space is a space backed with a memory mapped image.
+class ImageSpace : public MemMapSpace {
+ public:
+  bool CanAllocateInto() const {
+    return false;
+  }
+
+  SpaceType GetType() const {
+    return kSpaceTypeImageSpace;
+  }
+
+  // create a Space from an image file. cannot be used for future allocation or collected.
+  static ImageSpace* Create(const std::string& image)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  const ImageHeader& GetImageHeader() const {
+    return *reinterpret_cast<ImageHeader*>(Begin());
+  }
+
+  const std::string GetImageFilename() const {
+    return GetName();
+  }
+
+  // Mark the objects defined in this space in the given live bitmap
+  void RecordImageAllocations(accounting::SpaceBitmap* live_bitmap) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  accounting::SpaceBitmap* GetLiveBitmap() const {
+    return live_bitmap_.get();
+  }
+
+  accounting::SpaceBitmap* GetMarkBitmap() const {
+    // ImageSpaces have the same bitmap for both live and marked. This helps reduce the number of
+    // special cases to test against.
+    return live_bitmap_.get();
+  }
+
+  void Dump(std::ostream& os) const;
+
+ private:
+  friend class Space;
+
+  static size_t bitmap_index_;
+
+  UniquePtr<accounting::SpaceBitmap> live_bitmap_;
+
+  ImageSpace(const std::string& name, MemMap* mem_map);
+
+  DISALLOW_COPY_AND_ASSIGN(ImageSpace);
+};
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_SPACE_IMAGE_SPACE_H_
diff --git a/src/gc/large_object_space.cc b/src/gc/space/large_object_space.cc
similarity index 97%
rename from src/gc/large_object_space.cc
rename to src/gc/space/large_object_space.cc
index c3bf382..3cee1b7 100644
--- a/src/gc/large_object_space.cc
+++ b/src/gc/space/large_object_space.cc
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
+#include "large_object_space.h"
+
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "large_object_space.h"
 #include "UniquePtr.h"
-#include "dlmalloc.h"
 #include "image.h"
 #include "os.h"
-#include "space_bitmap.h"
 #include "thread.h"
 #include "utils.h"
 
 namespace art {
+namespace gc {
+namespace space {
 
 void LargeObjectSpace::SwapBitmaps() {
   live_objects_.swap(mark_objects_);
@@ -39,8 +40,6 @@
     : DiscontinuousSpace(name, kGcRetentionPolicyAlwaysCollect),
       num_bytes_allocated_(0), num_objects_allocated_(0), total_bytes_allocated_(0),
       total_objects_allocated_(0) {
-  live_objects_.reset(new SpaceSetMap("large live objects"));
-  mark_objects_.reset(new SpaceSetMap("large marked objects"));
 }
 
 
@@ -281,4 +280,6 @@
      << " end: " << reinterpret_cast<void*>(End());
 }
 
-}
+}  // namespace space
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/large_object_space.h b/src/gc/space/large_object_space.h
similarity index 84%
rename from src/gc/large_object_space.h
rename to src/gc/space/large_object_space.h
index 8a2f970..197fad3 100644
--- a/src/gc/large_object_space.h
+++ b/src/gc/space/large_object_space.h
@@ -14,51 +14,38 @@
  * limitations under the License.
  */
 
-#ifndef ART_SRC_GC_LARGE_OBJECT_SPACE_H_
-#define ART_SRC_GC_LARGE_OBJECT_SPACE_H_
+#ifndef ART_SRC_GC_SPACE_LARGE_OBJECT_SPACE_H_
+#define ART_SRC_GC_SPACE_LARGE_OBJECT_SPACE_H_
 
-#include "space.h"
+
+#include "dlmalloc_space.h"
 #include "safe_map.h"
+#include "space.h"
 
 #include <set>
 #include <vector>
 
 namespace art {
-class SpaceSetMap;
+namespace gc {
+namespace space {
 
 // Abstraction implemented by all large object spaces.
 class LargeObjectSpace : public DiscontinuousSpace, public AllocSpace {
  public:
-  virtual bool CanAllocateInto() const {
-    return true;
-  }
-
-  virtual bool IsCompactible() const {
-    return true;
-  }
-
   virtual SpaceType GetType() const {
     return kSpaceTypeLargeObjectSpace;
   }
 
-  virtual SpaceSetMap* GetLiveObjects() const {
-    return live_objects_.get();
-  }
-
-  virtual SpaceSetMap* GetMarkObjects() const {
-    return mark_objects_.get();
-  }
-
   virtual void SwapBitmaps();
   virtual void CopyLiveToMarked();
   virtual void Walk(DlMallocSpace::WalkCallback, void* arg) = 0;
   virtual ~LargeObjectSpace() {}
 
-  uint64_t GetNumBytesAllocated() const {
+  uint64_t GetBytesAllocated() const {
     return num_bytes_allocated_;
   }
 
-  uint64_t GetNumObjectsAllocated() const {
+  uint64_t GetObjectsAllocated() const {
     return num_objects_allocated_;
   }
 
@@ -82,10 +69,10 @@
   size_t total_bytes_allocated_;
   size_t total_objects_allocated_;
 
-  UniquePtr<SpaceSetMap> live_objects_;
-  UniquePtr<SpaceSetMap> mark_objects_;
-
   friend class Space;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LargeObjectSpace);
 };
 
 // A discontinuous large object space implemented by individual mmap/munmap calls.
@@ -96,12 +83,13 @@
   static LargeObjectMapSpace* Create(const std::string& name);
 
   // Return the storage space required by obj.
-  virtual size_t AllocationSize(const mirror::Object* obj);
-  virtual mirror::Object* Alloc(Thread* self, size_t num_bytes);
+  size_t AllocationSize(const mirror::Object* obj);
+  mirror::Object* Alloc(Thread* self, size_t num_bytes);
   size_t Free(Thread* self, mirror::Object* ptr);
-  virtual void Walk(DlMallocSpace::WalkCallback, void* arg);
+  void Walk(DlMallocSpace::WalkCallback, void* arg);
   // TODO: disabling thread safety analysis as this may be called when we already hold lock_.
-  virtual bool Contains(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS;
+  bool Contains(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS;
+
 private:
   LargeObjectMapSpace(const std::string& name);
   virtual ~LargeObjectMapSpace() {}
@@ -114,6 +102,7 @@
 };
 
 // A continuous large object space with a free-list to handle holes.
+// TODO: this implementation is buggy.
 class FreeListSpace : public LargeObjectSpace {
  public:
   virtual ~FreeListSpace();
@@ -140,7 +129,7 @@
     return End() - Begin();
   }
 
-  virtual void Dump(std::ostream& os) const;
+  void Dump(std::ostream& os) const;
 
  private:
   static const size_t kAlignment = kPageSize;
@@ -197,6 +186,8 @@
   FreeChunks free_chunks_ GUARDED_BY(lock_);
 };
 
-}
+}  // namespace space
+}  // namespace gc
+}  // namespace art
 
-#endif  // ART_SRC_GC_LARGE_OBJECT_SPACE_H_
+#endif  // ART_SRC_GC_SPACE_LARGE_OBJECT_SPACE_H_
diff --git a/src/gc/space/space-inl.h b/src/gc/space/space-inl.h
new file mode 100644
index 0000000..8216d1b
--- /dev/null
+++ b/src/gc/space/space-inl.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_SPACE_SPACE_INL_H_
+#define ART_SRC_GC_SPACE_SPACE_INL_H_
+
+#include "space.h"
+
+#include "dlmalloc_space.h"
+#include "image_space.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+inline ImageSpace* Space::AsImageSpace() {
+  DCHECK_EQ(GetType(), kSpaceTypeImageSpace);
+  return down_cast<ImageSpace*>(down_cast<MemMapSpace*>(this));
+}
+
+inline DlMallocSpace* Space::AsDlMallocSpace() {
+  DCHECK_EQ(GetType(), kSpaceTypeAllocSpace);
+  return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
+}
+
+inline DlMallocSpace* Space::AsZygoteSpace() {
+  DCHECK_EQ(GetType(), kSpaceTypeZygoteSpace);
+  return down_cast<DlMallocSpace*>(down_cast<MemMapSpace*>(this));
+}
+
+inline LargeObjectSpace* Space::AsLargeObjectSpace() {
+  DCHECK_EQ(GetType(), kSpaceTypeLargeObjectSpace);
+  return reinterpret_cast<LargeObjectSpace*>(this);
+}
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_SPACE_SPACE_INL_H_
diff --git a/src/gc/space/space.cc b/src/gc/space/space.cc
new file mode 100644
index 0000000..eae281a
--- /dev/null
+++ b/src/gc/space/space.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "space.h"
+
+#include "base/logging.h"
+
+namespace art {
+namespace gc {
+namespace space {
+
+Space::Space(const std::string& name, GcRetentionPolicy gc_retention_policy) :
+    name_(name), gc_retention_policy_(gc_retention_policy) { }
+
+void Space::Dump(std::ostream& os) const {
+  os << GetName() << ":" << GetGcRetentionPolicy();
+}
+
+std::ostream& operator<<(std::ostream& os, const Space& space) {
+  space.Dump(os);
+  return os;
+}
+
+
+DiscontinuousSpace::DiscontinuousSpace(const std::string& name,
+                                       GcRetentionPolicy gc_retention_policy) :
+    Space(name, gc_retention_policy),
+    live_objects_(new accounting::SpaceSetMap("large live objects")),
+    mark_objects_(new accounting::SpaceSetMap("large marked objects")) {
+}
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
diff --git a/src/gc/space/space.h b/src/gc/space/space.h
new file mode 100644
index 0000000..ca01c55
--- /dev/null
+++ b/src/gc/space/space.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_GC_SPACE_SPACE_H_
+#define ART_SRC_GC_SPACE_SPACE_H_
+
+#include <string>
+
+#include "UniquePtr.h"
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "gc/accounting/space_bitmap.h"
+#include "globals.h"
+#include "image.h"
+#include "mem_map.h"
+
+namespace art {
+namespace mirror {
+  class Object;
+}  // namespace mirror
+
+namespace gc {
+
+namespace accounting {
+  class SpaceBitmap;
+} // namespace accounting
+
+class Heap;
+
+namespace space {
+
+class DlMallocSpace;
+class ImageSpace;
+class LargeObjectSpace;
+
+static const bool kDebugSpaces = kIsDebugBuild;
+
+// See Space::GetGcRetentionPolicy.
+enum GcRetentionPolicy {
+  // Objects are retained forever with this policy for a space.
+  kGcRetentionPolicyNeverCollect,
+  // Every GC cycle will attempt to collect objects in this space.
+  kGcRetentionPolicyAlwaysCollect,
+  // Objects will be considered for collection only in "full" GC cycles, ie faster partial
+  // collections won't scan these areas such as the Zygote.
+  kGcRetentionPolicyFullCollect,
+};
+std::ostream& operator<<(std::ostream& os, const GcRetentionPolicy& policy);
+
+enum SpaceType {
+  kSpaceTypeImageSpace,
+  kSpaceTypeAllocSpace,
+  kSpaceTypeZygoteSpace,
+  kSpaceTypeLargeObjectSpace,
+};
+std::ostream& operator<<(std::ostream& os, const SpaceType& space_type);
+
+// A space contains memory allocated for managed objects.
+class Space {
+ public:
+  // Dump space. Also key method for C++ vtables.
+  virtual void Dump(std::ostream& os) const;
+
+  // Name of the space. May vary, for example before/after the Zygote fork.
+  const char* GetName() const {
+    return name_.c_str();
+  }
+
+  // The policy of when objects are collected associated with this space.
+  GcRetentionPolicy GetGcRetentionPolicy() const {
+    return gc_retention_policy_;
+  }
+
+  // Does the space support allocation?
+  virtual bool CanAllocateInto() const {
+    return true;
+  }
+
+  // Is the given object contained within this space?
+  virtual bool Contains(const mirror::Object* obj) const = 0;
+
+  // The kind of space this: image, alloc, zygote, large object.
+  virtual SpaceType GetType() const = 0;
+
+  // Is this an image space, ie one backed by a memory mapped image file.
+  bool IsImageSpace() const {
+    return GetType() == kSpaceTypeImageSpace;
+  }
+  ImageSpace* AsImageSpace();
+
+  // Is this a dlmalloc backed allocation space?
+  bool IsDlMallocSpace() const {
+    SpaceType type = GetType();
+    return type == kSpaceTypeAllocSpace || type == kSpaceTypeZygoteSpace;
+  }
+  DlMallocSpace* AsDlMallocSpace();
+
+  // Is this the space allocated into by the Zygote and no-longer in use?
+  bool IsZygoteSpace() const {
+    return GetType() == kSpaceTypeZygoteSpace;
+  }
+  DlMallocSpace* AsZygoteSpace();
+
+  // Does this space hold large objects and implement the large object space abstraction?
+  bool IsLargeObjectSpace() const {
+    return GetType() == kSpaceTypeLargeObjectSpace;
+  }
+  LargeObjectSpace* AsLargeObjectSpace();
+
+  virtual ~Space() {}
+
+ protected:
+  Space(const std::string& name, GcRetentionPolicy gc_retention_policy);
+
+  void SetGcRetentionPolicy(GcRetentionPolicy gc_retention_policy) {
+    gc_retention_policy_ = gc_retention_policy;
+  }
+
+  // Name of the space that may vary due to the Zygote fork.
+  std::string name_;
+
+ private:
+  // When should objects within this space be reclaimed? Not constant as we vary it in the case
+  // of Zygote forking.
+  GcRetentionPolicy gc_retention_policy_;
+
+  friend class art::gc::Heap;
+
+  DISALLOW_COPY_AND_ASSIGN(Space);
+};
+std::ostream& operator<<(std::ostream& os, const Space& space);
+
+// AllocSpace interface.
+class AllocSpace {
+ public:
+  // Number of bytes currently allocated.
+  virtual uint64_t GetBytesAllocated() const = 0;
+  // Number of objects currently allocated.
+  virtual uint64_t GetObjectsAllocated() const = 0;
+  // Number of bytes allocated since the space was created.
+  virtual uint64_t GetTotalBytesAllocated() const = 0;
+  // Number of objects allocated since the space was created.
+  virtual uint64_t GetTotalObjectsAllocated() const = 0;
+
+  // Allocate num_bytes without allowing growth.
+  virtual mirror::Object* Alloc(Thread* self, size_t num_bytes) = 0;
+
+  // Return the storage space required by obj.
+  virtual size_t AllocationSize(const mirror::Object* obj) = 0;
+
+  // Returns how many bytes were freed.
+  virtual size_t Free(Thread* self, mirror::Object* ptr) = 0;
+
+  // Returns how many bytes were freed.
+  virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) = 0;
+
+ protected:
+  AllocSpace() {}
+  virtual ~AllocSpace() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AllocSpace);
+};
+
+// Continuous spaces have bitmaps, and an address range. Although not required, objects within
+// continuous spaces can be marked in the card table.
+class ContinuousSpace : public Space {
+ public:
+  // Address at which the space begins
+  byte* Begin() const {
+    return begin_;
+  }
+
+  // Address at which the space ends, which may vary as the space is filled.
+  byte* End() const {
+    return end_;
+  }
+
+  // Current size of space
+  size_t Size() const {
+    return End() - Begin();
+  }
+
+  virtual accounting::SpaceBitmap* GetLiveBitmap() const = 0;
+  virtual accounting::SpaceBitmap* GetMarkBitmap() const = 0;
+
+  // Is object within this space? We check to see if the pointer is beyond the end first as
+  // continuous spaces are iterated over from low to high.
+  bool HasAddress(const mirror::Object* obj) const {
+    const byte* byte_ptr = reinterpret_cast<const byte*>(obj);
+    return byte_ptr < End() && byte_ptr >= Begin();
+  }
+
+  bool Contains(const mirror::Object* obj) const {
+    return HasAddress(obj);
+  }
+
+  virtual ~ContinuousSpace() {}
+
+ protected:
+  ContinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy,
+                  byte* begin, byte* end) :
+      Space(name, gc_retention_policy), begin_(begin), end_(end) {
+  }
+
+
+  // The beginning of the storage for fast access.
+  byte* const begin_;
+
+  // Current end of the space.
+  byte* end_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContinuousSpace);
+};
+
+// A space where objects may be allocated higgledy-piggledy throughout virtual memory. Currently
+// the card table can't cover these objects and so the write barrier shouldn't be triggered. This
+// is suitable for use for large primitive arrays.
+class DiscontinuousSpace : public Space {
+ public:
+  accounting::SpaceSetMap* GetLiveObjects() const {
+    return live_objects_.get();
+  }
+
+  accounting::SpaceSetMap* GetMarkObjects() const {
+    return mark_objects_.get();
+  }
+
+  virtual ~DiscontinuousSpace() {}
+
+ protected:
+  DiscontinuousSpace(const std::string& name, GcRetentionPolicy gc_retention_policy);
+
+  UniquePtr<accounting::SpaceSetMap> live_objects_;
+  UniquePtr<accounting::SpaceSetMap> mark_objects_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DiscontinuousSpace);
+};
+
+class MemMapSpace : public ContinuousSpace {
+ public:
+  // Maximum which the mapped space can grow to.
+  virtual size_t Capacity() const {
+    return mem_map_->Size();
+  }
+
+  // Size of the space without a limit on its growth. By default this is just the Capacity, but
+  // for the allocation space we support starting with a small heap and then extending it.
+  virtual size_t NonGrowthLimitCapacity() const {
+    return Capacity();
+  }
+
+ protected:
+  MemMapSpace(const std::string& name, MemMap* mem_map, size_t initial_size,
+              GcRetentionPolicy gc_retention_policy)
+      : ContinuousSpace(name, gc_retention_policy,
+                        mem_map->Begin(), mem_map->Begin() + initial_size),
+        mem_map_(mem_map) {
+  }
+
+  MemMap* GetMemMap() {
+    return mem_map_.get();
+  }
+
+  const MemMap* GetMemMap() const {
+    return mem_map_.get();
+  }
+
+ private:
+  // Underlying storage of the space
+  UniquePtr<MemMap> mem_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemMapSpace);
+};
+
+}  // namespace space
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_SRC_GC_SPACE_SPACE_H_
diff --git a/src/gc/space_test.cc b/src/gc/space/space_test.cc
similarity index 97%
rename from src/gc/space_test.cc
rename to src/gc/space/space_test.cc
index 372ec77..08ae894 100644
--- a/src/gc/space_test.cc
+++ b/src/gc/space/space_test.cc
@@ -14,22 +14,27 @@
  * limitations under the License.
  */
 
-#include "space.h"
+#include "dlmalloc_space.h"
 
 #include "common_test.h"
-#include "dlmalloc.h"
 #include "globals.h"
 #include "UniquePtr.h"
 
 #include <stdint.h>
 
 namespace art {
+namespace gc {
+namespace space {
 
 class SpaceTest : public CommonTest {
  public:
   void SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size,
                                            int round, size_t growth_limit);
   void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size);
+
+  void AddContinuousSpace(ContinuousSpace* space) {
+    Runtime::Current()->GetHeap()->AddContinuousSpace(space);
+  }
 };
 
 TEST_F(SpaceTest, Init) {
@@ -79,7 +84,7 @@
     ASSERT_TRUE(space != NULL);
 
     // Make space findable to the heap, will also delete space when runtime is cleaned up
-    Runtime::Current()->GetHeap()->AddSpace(space);
+    AddContinuousSpace(space);
     Thread* self = Thread::Current();
 
     // Succeeds, fits without adjusting the footprint limit.
@@ -121,7 +126,7 @@
     space = space->CreateZygoteSpace();
 
     // Make space findable to the heap, will also delete space when runtime is cleaned up
-    Runtime::Current()->GetHeap()->AddSpace(space);
+    AddContinuousSpace(space);
 
     // Succeeds, fits without adjusting the footprint limit.
     ptr1 = space->Alloc(self, 1 * MB);
@@ -148,7 +153,7 @@
   Thread* self = Thread::Current();
 
   // Make space findable to the heap, will also delete space when runtime is cleaned up
-  Runtime::Current()->GetHeap()->AddSpace(space);
+  AddContinuousSpace(space);
 
   // Succeeds, fits without adjusting the footprint limit.
   mirror::Object* ptr1 = space->Alloc(self, 1 * MB);
@@ -190,7 +195,7 @@
   ASSERT_TRUE(space != NULL);
 
   // Make space findable to the heap, will also delete space when runtime is cleaned up
-  Runtime::Current()->GetHeap()->AddSpace(space);
+  AddContinuousSpace(space);
   Thread* self = Thread::Current();
 
   // Succeeds, fits without adjusting the max allowed footprint.
@@ -384,7 +389,7 @@
   EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity);
 
   // Make space findable to the heap, will also delete space when runtime is cleaned up
-  Runtime::Current()->GetHeap()->AddSpace(space);
+  AddContinuousSpace(space);
 
   // In this round we don't allocate with growth and therefore can't grow past the initial size.
   // This effectively makes the growth_limit the initial_size, so assert this.
@@ -419,4 +424,6 @@
 TEST_SizeFootPrintGrowthLimitAndTrim(4MB, 4 * MB)
 TEST_SizeFootPrintGrowthLimitAndTrim(8MB, 8 * MB)
 
+}  // namespace space
+}  // namespace gc
 }  // namespace art
diff --git a/src/gc/sticky_mark_sweep.cc b/src/gc/sticky_mark_sweep.cc
deleted file mode 100644
index 988d4e7..0000000
--- a/src/gc/sticky_mark_sweep.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "heap.h"
-#include "large_object_space.h"
-#include "space.h"
-#include "sticky_mark_sweep.h"
-#include "thread.h"
-
-namespace art {
-
-StickyMarkSweep::StickyMarkSweep(Heap* heap, bool is_concurrent)
-    : PartialMarkSweep(heap, is_concurrent) {
-  cumulative_timings_.SetName(GetName());
-}
-
-StickyMarkSweep::~StickyMarkSweep() {
-
-}
-
-void StickyMarkSweep::BindBitmaps() {
-  PartialMarkSweep::BindBitmaps();
-
-  Spaces& spaces = GetHeap()->GetSpaces();
-  WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
-  // For sticky GC, we want to bind the bitmaps of both the zygote space and the alloc space.
-  // This lets us start with the mark bitmap of the previous garbage collection as the current
-  // mark bitmap of the alloc space. After the sticky GC finishes, we then unbind the bitmaps,
-  // making it so that the live bitmap of the alloc space is contains the newly marked objects
-  // from the sticky GC.
-  for (Spaces::iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    if ((*it)->GetGcRetentionPolicy() == kGcRetentionPolicyAlwaysCollect) {
-      BindLiveToMarkBitmap(*it);
-    }
-  }
-
-  GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked();
-}
-
-void StickyMarkSweep::MarkReachableObjects() {
-  DisableFinger();
-  RecursiveMarkDirtyObjects(CardTable::kCardDirty - 1);
-}
-
-void StickyMarkSweep::Sweep(TimingLogger& timings, bool swap_bitmaps) {
-  ObjectStack* live_stack = GetHeap()->GetLiveStack();
-  SweepArray(timings_, live_stack, false);
-  timings_.AddSplit("SweepArray");
-}
-
-}  // namespace art
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index 7539066..d66ec79 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -44,8 +44,10 @@
 #include "common_throws.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
 #include "globals.h"
-#include "heap.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
 #include "mirror/field.h"
@@ -55,7 +57,6 @@
 #include "os.h"
 #include "safe_map.h"
 #include "scoped_thread_state_change.h"
-#include "gc/space.h"
 #include "thread_list.h"
 
 namespace art {
@@ -412,7 +413,7 @@
       LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) {
     // Walk the roots and the heap.
     current_record_.StartNewRecord(body_fp_, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
-    Runtime::Current()->VisitRoots(RootVisitor, this);
+    Runtime::Current()->VisitRoots(RootVisitor, this, false, false);
     Thread* self = Thread::Current();
     {
       WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
diff --git a/src/image_test.cc b/src/image_test.cc
index 8066a90..9f86a1a 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -22,7 +22,7 @@
 #include "image_writer.h"
 #include "oat_writer.h"
 #include "signal_catcher.h"
-#include "gc/space.h"
+#include "gc/space/image_space.h"
 #include "UniquePtr.h"
 #include "utils.h"
 #include "vector_output_stream.h"
@@ -43,27 +43,19 @@
   {
     std::vector<uint8_t> oat_contents;
     {
+      jobject class_loader = NULL;
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
+
       ScopedObjectAccess soa(Thread::Current());
-      std::vector<const DexFile*> dex_files;
-      dex_files.push_back(java_lang_dex_file_);
-      dex_files.push_back(conscrypt_file_);
       VectorOutputStream output_stream(tmp_elf.GetFilename(), oat_contents);
-      bool success_oat = OatWriter::Create(output_stream, dex_files, 0, 0, "", *compiler_driver_.get());
+      bool success_oat = OatWriter::Create(output_stream, class_linker->GetBootClassPath(),
+                                           0, 0, "", *compiler_driver_.get());
       ASSERT_TRUE(success_oat);
 
-      // Force all system classes into memory
-      for (size_t dex_file_index = 0; dex_file_index < dex_files.size(); ++dex_file_index) {
-        const DexFile* dex_file = dex_files[dex_file_index];
-        for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); ++class_def_index) {
-          const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-          const char* descriptor = dex_file->GetClassDescriptor(class_def);
-          mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
-          EXPECT_TRUE(klass != NULL) << descriptor;
-        }
-      }
       bool success_elf = compiler_driver_->WriteElf(GetTestAndroidRoot(),
                                                     !kIsTargetBuild,
-                                                    dex_files,
+                                                    class_linker->GetBootClassPath(),
                                                     oat_contents,
                                                     tmp_elf.GetFile());
       ASSERT_TRUE(success_elf);
@@ -76,10 +68,9 @@
   ScratchFile tmp_image;
   const uintptr_t requested_image_base = ART_BASE_ADDRESS;
   {
-    ImageWriter writer(NULL);
+    ImageWriter writer(*compiler_driver_.get());
     bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
-                                      tmp_oat->GetPath(), tmp_oat->GetPath(),
-                                      *compiler_driver_.get());
+                                      tmp_oat->GetPath(), tmp_oat->GetPath());
     ASSERT_TRUE(success_image);
     bool success_fixup = compiler_driver_->FixupElf(tmp_oat.get(), writer.GetOatDataBegin());
     ASSERT_TRUE(success_fixup);
@@ -92,15 +83,18 @@
     file->ReadFully(&image_header, sizeof(image_header));
     ASSERT_TRUE(image_header.IsValid());
 
-    Heap* heap = Runtime::Current()->GetHeap();
-    ASSERT_EQ(1U, heap->GetSpaces().size());
-    ContinuousSpace* space = heap->GetSpaces().front();
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    ASSERT_EQ(1U, heap->GetContinuousSpaces().size());
+    gc::space::ContinuousSpace* space = heap->GetContinuousSpaces().front();
     ASSERT_FALSE(space->IsImageSpace());
     ASSERT_TRUE(space != NULL);
-    ASSERT_TRUE(space->IsAllocSpace());
+    ASSERT_TRUE(space->IsDlMallocSpace());
     ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->GetLength()));
   }
 
+  ASSERT_TRUE(compiler_driver_->GetImageClasses() != NULL);
+  CompilerDriver::DescriptorSet image_classes(*compiler_driver_->GetImageClasses());
+
   // Need to delete the compiler since it has worker threads which are attached to runtime.
   compiler_driver_.reset();
 
@@ -131,14 +125,14 @@
   ASSERT_TRUE(runtime_.get() != NULL);
   class_linker_ = runtime_->GetClassLinker();
 
-  Heap* heap = Runtime::Current()->GetHeap();
-  ASSERT_EQ(2U, heap->GetSpaces().size());
-  ASSERT_TRUE(heap->GetSpaces()[0]->IsImageSpace());
-  ASSERT_FALSE(heap->GetSpaces()[0]->IsAllocSpace());
-  ASSERT_FALSE(heap->GetSpaces()[1]->IsImageSpace());
-  ASSERT_TRUE(heap->GetSpaces()[1]->IsAllocSpace());
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  ASSERT_EQ(2U, heap->GetContinuousSpaces().size());
+  ASSERT_TRUE(heap->GetContinuousSpaces()[0]->IsImageSpace());
+  ASSERT_FALSE(heap->GetContinuousSpaces()[0]->IsDlMallocSpace());
+  ASSERT_FALSE(heap->GetContinuousSpaces()[1]->IsImageSpace());
+  ASSERT_TRUE(heap->GetContinuousSpaces()[1]->IsDlMallocSpace());
 
-  ImageSpace* image_space = heap->GetImageSpace();
+  gc::space::ImageSpace* image_space = heap->GetImageSpace();
   byte* image_begin = image_space->Begin();
   byte* image_end = image_space->End();
   CHECK_EQ(requested_image_base, reinterpret_cast<uintptr_t>(image_begin));
@@ -148,7 +142,13 @@
     mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
     EXPECT_TRUE(klass != NULL) << descriptor;
     EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
-    EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    if (image_classes.find(descriptor) != image_classes.end()) {
+      // image classes should be located before the end of the image.
+      EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    } else {
+      // non image classes should be in a space after the image.
+      EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+    }
     EXPECT_EQ(*klass->GetRawLockWordAddress(), 0);  // address should have been removed from monitor
   }
 }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index a989a4e..f0b49be 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -26,17 +26,18 @@
 #include "compiled_method.h"
 #include "compiler/driver/compiler_driver.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
-#include "gc/large_object_space.h"
-#include "gc/space.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/accounting/heap_bitmap.h"
+#include "gc/heap.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
 #include "globals.h"
-#include "heap.h"
 #include "image.h"
 #include "intern_table.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
@@ -57,16 +58,12 @@
 bool ImageWriter::Write(const std::string& image_filename,
                         uintptr_t image_begin,
                         const std::string& oat_filename,
-                        const std::string& oat_location,
-                        const CompilerDriver& compiler_driver) {
+                        const std::string& oat_location) {
   CHECK(!image_filename.empty());
 
   CHECK_NE(image_begin, 0U);
   image_begin_ = reinterpret_cast<byte*>(image_begin);
 
-  Heap* heap = Runtime::Current()->GetHeap();
-  const Spaces& spaces = heap->GetSpaces();
-
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
   for (size_t i = 0; i < all_dex_caches.size(); i++) {
@@ -81,6 +78,10 @@
   }
   oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location);
   class_linker->RegisterOatFile(*oat_file_);
+  interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset();
+  interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset();
+  portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset();
+  quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset();
 
   {
     Thread::Current()->TransitionFromSuspendedToRunnable();
@@ -89,12 +90,16 @@
     ComputeEagerResolvedStrings();
     Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   }
-  heap->CollectGarbage(false);  // Remove garbage
-  // Trim size of alloc spaces
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  heap->CollectGarbage(false);  // Remove garbage.
+  // Trim size of alloc spaces.
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
   // TODO: C++0x auto
-  for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
-    if ((*cur)->IsAllocSpace()) {
-      (*cur)->AsAllocSpace()->Trim();
+  typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    gc::space::ContinuousSpace* space = *it;
+    if (space->IsDlMallocSpace()) {
+      space->AsDlMallocSpace()->Trim();
     }
   }
 
@@ -110,10 +115,10 @@
   Thread::Current()->TransitionFromSuspendedToRunnable();
   size_t oat_loaded_size = 0;
   size_t oat_data_offset = 0;
-  compiler_driver.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
+  compiler_driver_.GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
   CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
   CopyAndFixupObjects();
-  PatchOatCodeAndMethods(compiler_driver);
+  PatchOatCodeAndMethods();
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
   UniquePtr<File> image_file(OS::OpenFile(image_filename.c_str(), true));
@@ -134,11 +139,15 @@
 }
 
 bool ImageWriter::AllocMemory() {
-  const Spaces& spaces = Runtime::Current()->GetHeap()->GetSpaces();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
   size_t size = 0;
-  for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-    if ((*it)->IsAllocSpace()) {
-      size += (*it)->Size();
+  // TODO: C++0x auto
+  typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    gc::space::ContinuousSpace* space = *it;
+    if (space->IsDlMallocSpace()) {
+      size += space->Size();
     }
   }
 
@@ -168,13 +177,13 @@
     return;
   }
   String* string = obj->AsString();
-  std::string utf8_string(string->ToModifiedUtf8());
+  const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
   ImageWriter* writer = reinterpret_cast<ImageWriter*>(arg);
   typedef Set::const_iterator CacheIt;  // TODO: C++0x auto
   for (CacheIt it = writer->dex_caches_.begin(), end = writer->dex_caches_.end(); it != end; ++it) {
     DexCache* dex_cache = *it;
     const DexFile& dex_file = *dex_cache->GetDexFile();
-    const DexFile::StringId* string_id = dex_file.FindStringId(utf8_string);
+    const DexFile::StringId* string_id = dex_file.FindStringId(utf16_string);
     if (string_id != NULL) {
       // This string occurs in this dex file, assign the dex cache entry.
       uint32_t string_idx = dex_file.GetIndexForStringId(*string_id);
@@ -188,49 +197,28 @@
 void ImageWriter::ComputeEagerResolvedStrings()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // TODO: Check image spaces only?
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   heap->FlushAllocStack();
   heap->GetLiveBitmap()->Walk(ComputeEagerResolvedStringsCallback, this);
 }
 
 bool ImageWriter::IsImageClass(const Class* klass) {
-  if (image_classes_ == NULL) {
-    return true;
-  }
-  while (klass->IsArrayClass()) {
-    klass = klass->GetComponentType();
-  }
-  if (klass->IsPrimitive()) {
-    return true;
-  }
-  const std::string descriptor(ClassHelper(klass).GetDescriptor());
-  return image_classes_->find(descriptor) != image_classes_->end();
+  return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor());
 }
 
-
 struct NonImageClasses {
   ImageWriter* image_writer;
   std::set<std::string>* non_image_classes;
 };
 
 void ImageWriter::PruneNonImageClasses() {
-  if (image_classes_ == NULL) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
     return;
   }
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
 
-  // Update image_classes_ with classes for objects created by <clinit> methods.
-  Thread* self = Thread::Current();
-  const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
-  Heap* heap = Runtime::Current()->GetHeap();
-  // TODO: Image spaces only?
-  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  heap->FlushAllocStack();
-  heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
-  self->EndAssertNoThreadSuspension(old_cause);
-
   // Make a list of classes we would like to prune.
   std::set<std::string> non_image_classes;
   NonImageClasses context;
@@ -271,28 +259,6 @@
   }
 }
 
-void ImageWriter::FindClinitImageClassesCallback(Object* object, void* arg) {
-  DCHECK(object != NULL);
-  DCHECK(arg != NULL);
-  ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-  Class* klass = object->GetClass();
-  while (klass->IsArrayClass()) {
-    klass = klass->GetComponentType();
-  }
-  if (klass->IsPrimitive()) {
-    return;
-  }
-  while (!klass->IsObjectClass()) {
-    ClassHelper kh(klass);
-    const char* descriptor = kh.GetDescriptor();
-    std::pair<DescriptorSet::iterator, bool> result = image_writer->image_classes_->insert(descriptor);
-    if (result.second) {
-      LOG(INFO) << "Adding " << descriptor << " to image classes";
-    }
-    klass = klass->GetSuperClass();
-  }
-}
-
 bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) {
   NonImageClasses* context = reinterpret_cast<NonImageClasses*>(arg);
   if (!context->image_writer->IsImageClass(klass)) {
@@ -303,11 +269,11 @@
 
 void ImageWriter::CheckNonImageClassesRemoved()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (image_classes_ == NULL) {
+  if (compiler_driver_.GetImageClasses() == NULL) {
     return;
   }
 
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   Thread* self = Thread::Current();
   {
     WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
@@ -332,8 +298,10 @@
 }
 
 void ImageWriter::DumpImageClasses() {
+  CompilerDriver::DescriptorSet* image_classes = compiler_driver_.GetImageClasses();
+  CHECK(image_classes != NULL);
   typedef std::set<std::string>::const_iterator It;  // TODO: C++0x auto
-  for (It it = image_classes_->begin(), end = image_classes_->end(); it != end; ++it) {
+  for (It it = image_classes->begin(), end = image_classes->end(); it != end; ++it) {
     LOG(INFO) << " " << *it;
   }
 }
@@ -410,8 +378,8 @@
   Thread* self = Thread::Current();
   SirtRef<ObjectArray<Object> > image_roots(self, CreateImageRoots());
 
-  Heap* heap = Runtime::Current()->GetHeap();
-  const Spaces& spaces = heap->GetSpaces();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
   DCHECK(!spaces.empty());
   DCHECK_EQ(0U, image_end_);
 
@@ -426,8 +394,11 @@
     // TODO: Add InOrderWalk to heap bitmap.
     const char* old = self->StartAssertNoThreadSuspension("ImageWriter");
     DCHECK(heap->GetLargeObjectsSpace()->GetLiveObjects()->IsEmpty());
-    for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-      (*it)->GetLiveBitmap()->InOrderWalk(CalculateNewObjectOffsetsCallback, this);
+    // TODO: C++0x auto
+    typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+    for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+      gc::space::ContinuousSpace* space = *it;
+      space->GetLiveBitmap()->InOrderWalk(CalculateNewObjectOffsetsCallback, this);
       DCHECK_LT(image_end_, image_->Size());
     }
     self->EndAssertNoThreadSuspension(old);
@@ -455,7 +426,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Thread* self = Thread::Current();
   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   // TODO: heap validation can't handle this fix up pass
   heap->DisableObjectValidation();
   // TODO: Image spaces only?
@@ -512,17 +483,34 @@
   if (orig->IsAbstract()) {
     // Code for abstract methods is set to the abstract method error stub when we load the image.
     copy->SetEntryPointFromCompiledCode(NULL);
+    copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+                                       (GetOatAddress(interpreter_to_interpreter_entry_offset_)));
     return;
+  } else {
+    copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
+                                       (GetOatAddress(interpreter_to_quick_entry_offset_)));
   }
 
   if (orig == Runtime::Current()->GetResolutionMethod()) {
-    // The resolution method's code is set to the resolution trampoline when we load the image.
-    copy->SetEntryPointFromCompiledCode(NULL);
+#if defined(ART_USE_PORTABLE_COMPILER)
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
     return;
   }
 
-  // Non-abstract methods have code
-  copy->SetEntryPointFromCompiledCode(GetOatAddress(orig->GetOatCodeOffset()));
+  // Use original code if it exists. Otherwise, set the code pointer to the resolution trampoline.
+  const byte* code = GetOatAddress(orig->GetOatCodeOffset());
+  if (code != NULL) {
+    copy->SetEntryPointFromCompiledCode(code);
+  } else {
+#if defined(ART_USE_PORTABLE_COMPILER)
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_));
+#else
+    copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_));
+#endif
+  }
 
   if (orig->IsNative()) {
     // The native method's pointer is set to a stub to lookup via dlsym when we load the image.
@@ -638,13 +626,13 @@
   return method;
 }
 
-void ImageWriter::PatchOatCodeAndMethods(const CompilerDriver& compiler) {
+void ImageWriter::PatchOatCodeAndMethods() {
   Thread* self = Thread::Current();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
 
   typedef std::vector<const CompilerDriver::PatchInformation*> Patches;
-  const Patches& code_to_patch = compiler.GetCodeToPatch();
+  const Patches& code_to_patch = compiler_driver_.GetCodeToPatch();
   for (size_t i = 0; i < code_to_patch.size(); i++) {
     const CompilerDriver::PatchInformation* patch = code_to_patch[i];
     AbstractMethod* target = GetTargetMethod(patch);
@@ -654,7 +642,7 @@
     SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
   }
 
-  const Patches& methods_to_patch = compiler.GetMethodsToPatch();
+  const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch();
   for (size_t i = 0; i < methods_to_patch.size(); i++) {
     const CompilerDriver::PatchInformation* patch = methods_to_patch[i];
     AbstractMethod* target = GetTargetMethod(patch);
diff --git a/src/image_writer.h b/src/image_writer.h
index 30a7f7f..b79cb2f 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -29,7 +29,7 @@
 #include "mirror/dex_cache.h"
 #include "os.h"
 #include "safe_map.h"
-#include "gc/space.h"
+#include "gc/space/space.h"
 #include "UniquePtr.h"
 
 namespace art {
@@ -37,18 +37,18 @@
 // Write a Space built during compilation for use during execution.
 class ImageWriter {
  public:
-  typedef std::set<std::string> DescriptorSet;
-  explicit ImageWriter(DescriptorSet* image_classes)
-      : oat_file_(NULL), image_end_(0), image_begin_(NULL), image_classes_(image_classes),
-        oat_data_begin_(NULL) {}
+  explicit ImageWriter(const CompilerDriver& compiler_driver)
+      : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL),
+        oat_data_begin_(NULL), interpreter_to_interpreter_entry_offset_(0),
+        interpreter_to_quick_entry_offset_(0), portable_resolution_trampoline_offset_(0),
+        quick_resolution_trampoline_offset_(0) {}
 
   ~ImageWriter() {}
 
   bool Write(const std::string& image_filename,
              uintptr_t image_begin,
              const std::string& oat_filename,
-             const std::string& oat_location,
-             const CompilerDriver& compiler_driver)
+             const std::string& oat_location)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   uintptr_t GetOatDataBegin() {
@@ -130,8 +130,6 @@
 
   // Remove unwanted classes from various roots.
   void PruneNonImageClasses() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void FindClinitImageClassesCallback(mirror::Object* object, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static bool NonImageClassesVisitor(mirror::Class* c, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -170,12 +168,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Patches references in OatFile to expect runtime addresses.
-  void PatchOatCodeAndMethods(const CompilerDriver& compiler)
+  void PatchOatCodeAndMethods()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
+  const CompilerDriver& compiler_driver_;
+
   // Map of Object to where it will be at runtime.
   SafeMap<const mirror::Object*, size_t> offsets_;
 
@@ -191,13 +191,16 @@
   // Beginning target image address for the output image.
   byte* image_begin_;
 
-  // Set of classes to be include in the image, or NULL for all.
-  DescriptorSet* image_classes_;
-
   // Beginning target oat address for the pointers from the output image to its oat file.
   const byte* oat_data_begin_;
 
-  // DexCaches seen while scanning for fixing up CodeAndDirectMethods.
+  // Offset from oat_data_begin_ to the stubs.
+  uint32_t interpreter_to_interpreter_entry_offset_;
+  uint32_t interpreter_to_quick_entry_offset_;
+  uint32_t portable_resolution_trampoline_offset_;
+  uint32_t quick_resolution_trampoline_offset_;
+
+  // DexCaches seen while scanning for fixing up CodeAndDirectMethods
   typedef std::set<mirror::DexCache*> Set;
   Set dex_caches_;
 };
diff --git a/src/instrumentation.cc b/src/instrumentation.cc
index 39fd377..8af0885 100644
--- a/src/instrumentation.cc
+++ b/src/instrumentation.cc
@@ -62,7 +62,7 @@
         if (is_initialized || !method->IsStatic() || method->IsConstructor()) {
           new_code = class_linker->GetOatCodeFor(method);
         } else {
-          new_code = GetResolutionTrampoline();
+          new_code = GetResolutionTrampoline(class_linker);
         }
       } else {  // !uninstall
         if (!interpreter_stubs_installed_ || method->IsNative()) {
@@ -380,7 +380,7 @@
   if (LIKELY(!instrumentation_stubs_installed_)) {
     const void* code = method->GetEntryPointFromCompiledCode();
     DCHECK(code != NULL);
-    if (LIKELY(code != GetResolutionTrampoline())) {
+    if (LIKELY(code != GetResolutionTrampoline(runtime->GetClassLinker()))) {
       return code;
     }
   }
diff --git a/src/instrumentation.h b/src/instrumentation.h
index e6fa251..e79c75e 100644
--- a/src/instrumentation.h
+++ b/src/instrumentation.h
@@ -137,12 +137,24 @@
     return instrumentation_stubs_installed_;
   }
 
+  bool HasMethodEntryListeners() const {
+    return have_method_entry_listeners_;
+  }
+
+  bool HasMethodExitListeners() const {
+    return have_method_exit_listeners_;
+  }
+
+  bool HasDexPcListeners() const {
+    return have_dex_pc_listeners_;
+  }
+
   // Inform listeners that a method has been entered. A dex PC is provided as we may install
   // listeners into executing code and get method enter events for methods already on the stack.
   void MethodEnterEvent(Thread* thread, mirror::Object* this_object,
                         const mirror::AbstractMethod* method, uint32_t dex_pc) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (have_method_entry_listeners_) {
+    if (UNLIKELY(HasMethodEntryListeners())) {
       MethodEnterEventImpl(thread, this_object, method, dex_pc);
     }
   }
@@ -152,7 +164,7 @@
                        const mirror::AbstractMethod* method, uint32_t dex_pc,
                        const JValue& return_value) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (have_method_exit_listeners_) {
+    if (UNLIKELY(HasMethodExitListeners())) {
       MethodExitEventImpl(thread, this_object, method, dex_pc, return_value);
     }
   }
@@ -166,7 +178,7 @@
   void DexPcMovedEvent(Thread* thread, mirror::Object* this_object,
                        const mirror::AbstractMethod* method, uint32_t dex_pc) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (UNLIKELY(have_dex_pc_listeners_)) {
+    if (UNLIKELY(HasDexPcListeners())) {
       DexPcMovedEventImpl(thread, this_object, method, dex_pc);
     }
   }
diff --git a/src/intern_table.cc b/src/intern_table.cc
index fa3c075..d1ad2db 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -38,13 +38,15 @@
      << image_strong_interns_.size() << " image strong\n";
 }
 
-void InternTable::VisitRoots(RootVisitor* visitor, void* arg) {
+void InternTable::VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty) {
   MutexLock mu(Thread::Current(), intern_table_lock_);
   typedef Table::const_iterator It; // TODO: C++0x auto
   for (It it = strong_interns_.begin(), end = strong_interns_.end(); it != end; ++it) {
     visitor(it->second, arg);
   }
-  is_dirty_ = false;
+  if (clean_dirty) {
+    is_dirty_ = false;
+  }
   // Note: we deliberately don't visit the weak_interns_ table and the immutable image roots.
 }
 
diff --git a/src/intern_table.h b/src/intern_table.h
index 3018317..1ff4f6d 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -66,7 +66,7 @@
 
   size_t Size() const;
 
-  void VisitRoots(RootVisitor* visitor, void* arg);
+  void VisitRoots(RootVisitor* visitor, void* arg, bool clean_dirty);
 
   void DumpForSigQuit(std::ostream& os) const;
 
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index e2cc3d6..dd96f8d 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -23,7 +23,8 @@
 #include "common_throws.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
-#include "gc/card_table-inl.h"
+#include "dex_instruction.h"
+#include "gc/accounting/card_table-inl.h"
 #include "invoke_arg_array_builder.h"
 #include "nth_caller_visitor.h"
 #include "mirror/class.h"
@@ -50,12 +51,13 @@
 static const int64_t kMaxLong = std::numeric_limits<int64_t>::max();
 static const int64_t kMinLong = std::numeric_limits<int64_t>::min();
 
-static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
-                                   ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
+                                   const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
+                                   JValue* result, size_t arg_offset)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
   // problems in core libraries.
-  std::string name(PrettyMethod(target_method));
+  std::string name(PrettyMethod(shadow_frame->GetMethod()));
   if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
     std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
     ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
@@ -132,7 +134,7 @@
     }
   } else {
     // Not special, continue with regular interpreter execution.
-    EnterInterpreterFromInterpreter(self, shadow_frame, result);
+    artInterpreterToInterpreterEntry(self, mh, code_item, shadow_frame, result);
   }
 }
 
@@ -383,51 +385,49 @@
   ref->MonitorExit(self);
 }
 
-static void DoInvoke(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame,
-                     const Instruction* inst, InvokeType type, bool is_range,
-                     JValue* result)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
-  Object* receiver;
-  if (type == kStatic) {
-    receiver = NULL;
-  } else {
-    receiver = shadow_frame.GetVRegReference(vregC);
-  }
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<InvokeType type, bool is_range, bool do_access_check>
+static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
+                     const Instruction* inst, JValue* result) NO_THREAD_SAFETY_ANALYSIS;
+
+template<InvokeType type, bool is_range, bool do_access_check>
+static void DoInvoke(Thread* self, ShadowFrame& shadow_frame,
+                     const Instruction* inst, JValue* result) {
   uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-  AbstractMethod* target_method = FindMethodFromCode(method_idx, receiver,
-                                                     shadow_frame.GetMethod(),
-                                                     self, true, type);
-  if (UNLIKELY(target_method == NULL)) {
+  uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+  Object* receiver = (type == kStatic) ? NULL : shadow_frame.GetVRegReference(vregC);
+  AbstractMethod* method = FindMethodFromCode(method_idx, receiver, shadow_frame.GetMethod(), self,
+                                              do_access_check, type);
+  if (UNLIKELY(method == NULL)) {
     CHECK(self->IsExceptionPending());
     result->SetJ(0);
     return;
   }
-  MethodHelper target_mh(target_method);
 
-  const DexFile::CodeItem* code_item = target_mh.GetCodeItem();
+  MethodHelper mh(method);
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
   uint16_t num_regs;
   uint16_t num_ins;
-  if (code_item != NULL) {
+  if (LIKELY(code_item != NULL)) {
     num_regs = code_item->registers_size_;
     num_ins = code_item->ins_size_;
-  } else if (target_method->IsAbstract()) {
+  } else if (method->IsAbstract()) {
     ThrowLocation throw_location = self->GetCurrentLocationForThrow();
     self->ThrowNewExceptionF(throw_location, "Ljava/lang/AbstractMethodError;",
-                             "abstract method \"%s\"", PrettyMethod(target_method).c_str());
+                             "abstract method \"%s\"", PrettyMethod(method).c_str());
     return;
   } else {
-    DCHECK(target_method->IsNative() || target_method->IsProxyMethod());
-    num_regs = num_ins = AbstractMethod::NumArgRegisters(target_mh.GetShorty());
-    if (!target_method->IsStatic()) {
+    DCHECK(method->IsNative() || method->IsProxyMethod());
+    num_regs = num_ins = AbstractMethod::NumArgRegisters(mh.GetShorty());
+    if (!method->IsStatic()) {
       num_regs++;
       num_ins++;
     }
   }
 
   void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
-  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame,
-                                                    target_method, 0, memory));
+  ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, method, 0, memory));
   size_t cur_reg = num_regs - num_ins;
   if (receiver != NULL) {
     new_shadow_frame->SetVRegReference(cur_reg, receiver);
@@ -435,13 +435,13 @@
   }
 
   size_t arg_offset = (receiver == NULL) ? 0 : 1;
-  const char* shorty = target_mh.GetShorty();
+  const char* shorty = mh.GetShorty();
   uint32_t arg[5];
   if (!is_range) {
     inst->GetArgs(arg);
   }
   for (size_t shorty_pos = 0; cur_reg < num_regs; ++shorty_pos, cur_reg++, arg_offset++) {
-    DCHECK_LT(shorty_pos + 1, target_mh.GetShortyLength());
+    DCHECK_LT(shorty_pos + 1, mh.GetShortyLength());
     size_t arg_pos = is_range ? vregC + arg_offset : arg[arg_offset];
     switch (shorty[shorty_pos + 1]) {
       case 'L': {
@@ -464,24 +464,33 @@
   }
 
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    (target_method->GetEntryPointFromInterpreter())(self, new_shadow_frame, result);
+    (method->GetEntryPointFromInterpreter())(self, mh, code_item, new_shadow_frame, result);
   } else {
-    UnstartedRuntimeInvoke(self, target_method, new_shadow_frame, result, num_regs - num_ins);
+    UnstartedRuntimeInvoke(self, mh, code_item, new_shadow_frame, result, num_regs - num_ins);
   }
 }
 
+// We use template functions to optimize compiler inlining process. Otherwise,
+// some parts of the code (like a switch statement) which depend on a constant
+// parameter would not be inlined while it should be. These constant parameters
+// are now part of the template arguments.
+// Note these template functions are static and inlined so they should not be
+// part of the final object file.
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst, FindFieldType find_type,
-                       Primitive::Type field_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+                       const Instruction* inst)
+    NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
 static inline void DoFieldGet(Thread* self, ShadowFrame& shadow_frame,
-                              const Instruction* inst, FindFieldType find_type,
-                              Primitive::Type field_type) {
+                              const Instruction* inst) {
   bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
-                               find_type, Primitive::FieldSize(field_type));
+                               find_type, Primitive::FieldSize(field_type),
+                               do_access_check);
   if (UNLIKELY(f == NULL)) {
     CHECK(self->IsExceptionPending());
     return;
@@ -524,18 +533,21 @@
   }
 }
 
-static void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
-                       const Instruction* inst, FindFieldType find_type,
-                       Primitive::Type field_type)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE;
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+static void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
+                       const Instruction* inst)
+    NO_THREAD_SAFETY_ANALYSIS ALWAYS_INLINE;
 
-static inline void DoFieldPut(Thread* self, ShadowFrame& shadow_frame,
-                              const Instruction* inst, FindFieldType find_type,
-                              Primitive::Type field_type) {
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+static inline void DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
+                              const Instruction* inst) {
   bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
   uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   Field* f = FindFieldFromCode(field_idx, shadow_frame.GetMethod(), self,
-                               find_type, Primitive::FieldSize(field_type));
+                               find_type, Primitive::FieldSize(field_type),
+                               do_access_check);
   if (UNLIKELY(f == NULL)) {
     CHECK(self->IsExceptionPending());
     return;
@@ -699,11 +711,15 @@
 // Code to run before each dex instruction.
 #define PREAMBLE()
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+// TODO: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) which is failing due to template
+// specialization.
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) __attribute__ ((hot));
+    NO_THREAD_SAFETY_ANALYSIS __attribute__ ((hot));
 
-static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+template<bool do_access_check>
+static JValue ExecuteImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame, JValue result_register) {
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
@@ -716,12 +732,14 @@
   // 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());
+  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..
-    instrumentation->MethodEnterEvent(self, this_object_ref.get(),
-                                      shadow_frame.GetMethod(), 0);
+    if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
+      instrumentation->MethodEnterEvent(self, this_object_ref.get(),
+                                        shadow_frame.GetMethod(), 0);
+    }
   }
   while (true) {
     if (UNLIKELY(self->TestAllFlags())) {
@@ -729,8 +747,10 @@
     }
     const uint32_t dex_pc = inst->GetDexPc(insns);
     shadow_frame.SetDexPC(dex_pc);
-    instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
-                                     shadow_frame.GetMethod(), dex_pc);
+    if (instrumentation->HasDexPcListeners()) {
+      instrumentation->DexPcMovedEvent(self, this_object_ref.get(),
+                                       shadow_frame.GetMethod(), dex_pc);
+    }
     const bool kTracing = false;
     if (kTracing) {
 #define TRACE_LOG std::cerr
@@ -838,8 +858,11 @@
       case Instruction::RETURN_VOID: {
         PREAMBLE();
         JValue result;
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::RETURN: {
@@ -847,16 +870,22 @@
         JValue result;
         result.SetJ(0);
         result.SetI(shadow_frame.GetVReg(inst->VRegA_11x()));
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::RETURN_WIDE: {
         PREAMBLE();
         JValue result;
         result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x()));
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::RETURN_OBJECT: {
@@ -864,8 +893,11 @@
         JValue result;
         result.SetJ(0);
         result.SetL(shadow_frame.GetVRegReference(inst->VRegA_11x()));
-        instrumentation->MethodExitEvent(self, this_object_ref.get(),
-                                         shadow_frame.GetMethod(), inst->GetDexPc(insns), result);
+        if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
+          instrumentation->MethodExitEvent(self, this_object_ref.get(),
+                                           shadow_frame.GetMethod(), inst->GetDexPc(insns),
+                                           result);
+        }
         return result;
       }
       case Instruction::CONST_4: {
@@ -959,7 +991,7 @@
       case Instruction::CONST_CLASS: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -995,7 +1027,7 @@
       case Instruction::CHECK_CAST: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1012,7 +1044,7 @@
       case Instruction::INSTANCE_OF: {
         PREAMBLE();
         Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                          self, false, true);
+                                          self, false, do_access_check);
         if (UNLIKELY(c == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1037,7 +1069,7 @@
       case Instruction::NEW_INSTANCE: {
         PREAMBLE();
         Object* obj = AllocObjectFromCode(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                          self, true);
+                                          self, do_access_check);
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1050,7 +1082,7 @@
         PREAMBLE();
         int32_t length = shadow_frame.GetVReg(inst->VRegB_22c());
         Object* obj = AllocArrayFromCode(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                         length, self, true);
+                                         length, self, do_access_check);
         if (UNLIKELY(obj == NULL)) {
           HANDLE_PENDING_EXCEPTION();
         } else {
@@ -1069,7 +1101,7 @@
           break;
         }
         Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_35c(), shadow_frame.GetMethod(),
-                                                   self, false, true);
+                                                   self, false, do_access_check);
         if (UNLIKELY(arrayClass == NULL)) {
           HANDLE_PENDING_EXCEPTION();
           break;
@@ -1117,7 +1149,7 @@
           break;
         }
         Class* arrayClass = ResolveVerifyAndClinit(inst->VRegB_3rc(), shadow_frame.GetMethod(),
-                                                   self, false, true);
+                                                   self, false, do_access_check);
         if (UNLIKELY(arrayClass == NULL)) {
           HANDLE_PENDING_EXCEPTION();
           break;
@@ -1193,34 +1225,34 @@
       }
       case Instruction::GOTO: {
         PREAMBLE();
-        inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_10t());
+        inst = inst->RelativeAt(inst->VRegA_10t());
         break;
       }
       case Instruction::GOTO_16: {
         PREAMBLE();
-        inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_20t());
+        inst = inst->RelativeAt(inst->VRegA_20t());
         break;
       }
       case Instruction::GOTO_32: {
         PREAMBLE();
-        inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegA_30t());
+        inst = inst->RelativeAt(inst->VRegA_30t());
         break;
       }
       case Instruction::PACKED_SWITCH: {
         PREAMBLE();
-        const uint16_t* switch_data = insns + inst->GetDexPc(insns) + inst->VRegB_31t();
+        const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
         int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
         DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
         uint16_t size = switch_data[1];
         DCHECK_GT(size, 0);
         const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-        CHECK(IsAligned<4>(keys));
+        DCHECK(IsAligned<4>(keys));
         int32_t first_key = keys[0];
         const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
         DCHECK(IsAligned<4>(targets));
         int32_t index = test_val - first_key;
         if (index >= 0 && index < size) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + targets[index]);
+          inst = inst->RelativeAt(targets[index]);
         } else {
           inst = inst->Next_3xx();
         }
@@ -1228,18 +1260,18 @@
       }
       case Instruction::SPARSE_SWITCH: {
         PREAMBLE();
-        uint32_t dex_pc = inst->GetDexPc(insns);
-        const uint16_t* switch_data = insns + dex_pc + inst->VRegB_31t();
+        const uint16_t* switch_data = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
         int32_t test_val = shadow_frame.GetVReg(inst->VRegA_31t());
-        CHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+        DCHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
         uint16_t size = switch_data[1];
-        CHECK_GT(size, 0);
+        DCHECK_GT(size, 0);
         const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-        CHECK(IsAligned<4>(keys));
+        DCHECK(IsAligned<4>(keys));
         const int32_t* entries = keys + size;
-        CHECK(IsAligned<4>(entries));
+        DCHECK(IsAligned<4>(entries));
         int lo = 0;
         int hi = size - 1;
+        const Instruction* current_inst = inst;
         inst = inst->Next_3xx();
         while (lo <= hi) {
           int mid = (lo + hi) / 2;
@@ -1249,7 +1281,7 @@
           } else if (test_val > foundVal) {
             lo = mid + 1;
           } else {
-            inst = Instruction::At(insns + dex_pc + entries[mid]);
+            inst = current_inst->RelativeAt(entries[mid]);
             break;
           }
         }
@@ -1339,7 +1371,7 @@
       case Instruction::IF_EQ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) == shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1348,7 +1380,7 @@
       case Instruction::IF_NE: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) != shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1357,7 +1389,7 @@
       case Instruction::IF_LT: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) < shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1366,7 +1398,7 @@
       case Instruction::IF_GE: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) >= shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1375,7 +1407,7 @@
       case Instruction::IF_GT: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) > shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1384,7 +1416,7 @@
       case Instruction::IF_LE: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_22t()) <= shadow_frame.GetVReg(inst->VRegB_22t())) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegC_22t());
+          inst = inst->RelativeAt(inst->VRegC_22t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1393,7 +1425,7 @@
       case Instruction::IF_EQZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) == 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1402,7 +1434,7 @@
       case Instruction::IF_NEZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) != 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1411,7 +1443,7 @@
       case Instruction::IF_LTZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) < 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1420,7 +1452,7 @@
       case Instruction::IF_GEZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) >= 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1429,7 +1461,7 @@
       case Instruction::IF_GTZ: {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) > 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1438,7 +1470,7 @@
       case Instruction::IF_LEZ:  {
         PREAMBLE();
         if (shadow_frame.GetVReg(inst->VRegA_21t()) <= 0) {
-          inst = Instruction::At(insns + inst->GetDexPc(insns) + inst->VRegB_21t());
+          inst = inst->RelativeAt(inst->VRegB_21t());
         } else {
           inst = inst->Next_2xx();
         }
@@ -1705,192 +1737,192 @@
       }
       case Instruction::IGET_BOOLEAN:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimBoolean);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_BYTE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimByte);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_CHAR:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimChar);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_SHORT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimShort);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimInt);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_WIDE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstancePrimitiveRead, Primitive::kPrimLong);
+        DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IGET_OBJECT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, InstanceObjectRead, Primitive::kPrimNot);
+        DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_BOOLEAN:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimBoolean);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_BYTE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimByte);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_CHAR:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimChar);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_SHORT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimShort);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimInt);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_WIDE:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticPrimitiveRead, Primitive::kPrimLong);
+        DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SGET_OBJECT:
         PREAMBLE();
-        DoFieldGet(self, shadow_frame, inst, StaticObjectRead, Primitive::kPrimNot);
+        DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_BOOLEAN:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimBoolean);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_BYTE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimByte);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_CHAR:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimChar);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_SHORT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimShort);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimInt);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_WIDE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstancePrimitiveWrite, Primitive::kPrimLong);
+        DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::IPUT_OBJECT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, InstanceObjectWrite, Primitive::kPrimNot);
+        DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_BOOLEAN:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimBoolean);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_BYTE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimByte);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_CHAR:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimChar);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_SHORT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimShort);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimInt);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_WIDE:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticPrimitiveWrite, Primitive::kPrimLong);
+        DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::SPUT_OBJECT:
         PREAMBLE();
-        DoFieldPut(self, shadow_frame, inst, StaticObjectWrite, Primitive::kPrimNot);
+        DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_2xx);
         break;
       case Instruction::INVOKE_VIRTUAL:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kVirtual, false, &result_register);
+        DoInvoke<kVirtual, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_VIRTUAL_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kVirtual, true, &result_register);
+        DoInvoke<kVirtual, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_SUPER:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kSuper, false, &result_register);
+        DoInvoke<kSuper, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_SUPER_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kSuper, true, &result_register);
+        DoInvoke<kSuper, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_DIRECT:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kDirect, false, &result_register);
+        DoInvoke<kDirect, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_DIRECT_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kDirect, true, &result_register);
+        DoInvoke<kDirect, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_INTERFACE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kInterface, false, &result_register);
+        DoInvoke<kInterface, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_INTERFACE_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kInterface, true, &result_register);
+        DoInvoke<kInterface, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_STATIC:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kStatic, false, &result_register);
+        DoInvoke<kStatic, false, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::INVOKE_STATIC_RANGE:
         PREAMBLE();
-        DoInvoke(self, mh, shadow_frame, inst, kStatic, true, &result_register);
+        DoInvoke<kStatic, true, do_access_check>(self, shadow_frame, inst, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(Next_3xx);
         break;
       case Instruction::NEG_INT:
@@ -2296,6 +2328,14 @@
         inst = inst->Next_1xx();
         break;
       }
+      case Instruction::DIV_INT_2ADDR: {
+        PREAMBLE();
+        uint32_t vregA = inst->VRegA_12x();
+        DoIntDivide(self, shadow_frame, vregA, shadow_frame.GetVReg(vregA),
+                    shadow_frame.GetVReg(inst->VRegB_12x()));
+        inst = inst->Next_1xx();
+        break;
+      }
       case Instruction::REM_INT_2ADDR: {
         PREAMBLE();
         uint32_t vregA = inst->VRegA_12x();
@@ -2358,14 +2398,6 @@
         inst = inst->Next_1xx();
         break;
       }
-      case Instruction::DIV_INT_2ADDR: {
-        PREAMBLE();
-        uint32_t vregA = inst->VRegA_12x();
-        DoIntDivide(self, shadow_frame, vregA, shadow_frame.GetVReg(vregA),
-                    shadow_frame.GetVReg(inst->VRegB_12x()));
-        inst = inst->Next_1xx();
-        break;
-      }
       case Instruction::ADD_LONG_2ADDR: {
         PREAMBLE();
         uint32_t vregA = inst->VRegA_12x();
@@ -2692,10 +2724,25 @@
   }
 }
 
+static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                      ShadowFrame& shadow_frame, JValue result_register)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static inline JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
+                             ShadowFrame& shadow_frame, JValue result_register) {
+  if (shadow_frame.GetMethod()->IsPreverified()) {
+    // Enter the "without access check" interpreter.
+    return ExecuteImpl<false>(self, mh, code_item, shadow_frame, result_register);
+  } else {
+    // Enter the "with access check" interpreter.
+    return ExecuteImpl<true>(self, mh, code_item, shadow_frame, result_register);
+  }
+}
+
 void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
                                 uint32_t* args, JValue* result) {
   DCHECK_EQ(self, Thread::Current());
-  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
     ThrowStackOverflowError(self);
     return;
   }
@@ -2799,7 +2846,7 @@
                                 ShadowFrame& shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK_EQ(self, Thread::Current());
-  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
     ThrowStackOverflowError(self);
     return JValue();
   }
@@ -2807,9 +2854,11 @@
   return Execute(self, mh, code_item, shadow_frame, JValue());
 }
 
-void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                      const DexFile::CodeItem* code_item,
+                                      ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (__builtin_frame_address(0) < self->GetStackEnd()) {
+  if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
     ThrowStackOverflowError(self);
     return;
   }
@@ -2826,8 +2875,6 @@
 
   self->PushShadowFrame(shadow_frame);
 
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
   if (LIKELY(!method->IsNative())) {
     result->SetJ(Execute(self, mh, code_item, *shadow_frame, JValue()).GetJ());
   } else {
diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h
index 96fa050..20166ac 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -47,7 +47,9 @@
                                        ShadowFrame& shadow_frame)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-extern void EnterInterpreterFromInterpreter(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                const DexFile::CodeItem* code_item,
+                                                ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 }  // namespace interpreter
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 7c19025..2631845 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -28,7 +28,7 @@
 #include "base/stringpiece.h"
 #include "class_linker.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "invoke_arg_array_builder.h"
 #include "jni.h"
 #include "mirror/class-inl.h"
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 0f58444..c8b9eb9 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -16,6 +16,7 @@
 
 #include "jni_internal.h"
 
+#include <limits.h>
 #include <cfloat>
 #include <cmath>
 
diff --git a/src/locks.cc b/src/locks.cc
index eb0620c..51a40c3 100644
--- a/src/locks.cc
+++ b/src/locks.cc
@@ -22,7 +22,7 @@
 
 Mutex* Locks::abort_lock_ = NULL;
 Mutex* Locks::breakpoint_lock_ = NULL;
-Mutex* Locks::classlinker_classes_lock_ = NULL;
+ReaderWriterMutex* Locks::classlinker_classes_lock_ = NULL;
 ReaderWriterMutex* Locks::heap_bitmap_lock_ = NULL;
 Mutex* Locks::logging_lock_ = NULL;
 ReaderWriterMutex* Locks::mutator_lock_ = NULL;
@@ -52,7 +52,8 @@
     DCHECK(breakpoint_lock_ == NULL);
     breakpoint_lock_ = new Mutex("breakpoint lock", kBreakpointLock);
     DCHECK(classlinker_classes_lock_ == NULL);
-    classlinker_classes_lock_ = new Mutex("ClassLinker classes lock", kClassLinkerClassesLock);
+    classlinker_classes_lock_ = new ReaderWriterMutex("ClassLinker classes lock",
+                                                      kClassLinkerClassesLock);
     DCHECK(heap_bitmap_lock_ == NULL);
     heap_bitmap_lock_ = new ReaderWriterMutex("heap bitmap lock", kHeapBitmapLock);
     DCHECK(mutator_lock_ == NULL);
diff --git a/src/locks.h b/src/locks.h
index 431a148..ceb04b9 100644
--- a/src/locks.h
+++ b/src/locks.h
@@ -143,7 +143,7 @@
   static Mutex* trace_lock_ ACQUIRED_AFTER(breakpoint_lock_);
 
   // Guards lists of classes within the class linker.
-  static Mutex* classlinker_classes_lock_ ACQUIRED_AFTER(trace_lock_);
+  static ReaderWriterMutex* classlinker_classes_lock_ ACQUIRED_AFTER(trace_lock_);
 
   // When declaring any Mutex add DEFAULT_MUTEX_ACQUIRED_AFTER to use annotalysis to check the code
   // doesn't try to hold a higher level Mutex.
diff --git a/src/mirror/abstract_method-inl.h b/src/mirror/abstract_method-inl.h
index d4f0f2c..a823886 100644
--- a/src/mirror/abstract_method-inl.h
+++ b/src/mirror/abstract_method-inl.h
@@ -117,7 +117,8 @@
   if (GetEntryPointFromCompiledCode() == GetInterpreterEntryPoint()) {
     return;
   }
-  if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline()) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline(class_linker)) {
       return;
   }
   DCHECK(IsWithinCode(pc))
diff --git a/src/mirror/abstract_method.cc b/src/mirror/abstract_method.cc
index 5258795..88a9dc1 100644
--- a/src/mirror/abstract_method.cc
+++ b/src/mirror/abstract_method.cc
@@ -20,7 +20,7 @@
 #include "base/stringpiece.h"
 #include "class-inl.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "interpreter/interpreter.h"
 #include "jni_internal.h"
 #include "object-inl.h"
@@ -268,45 +268,28 @@
       result->SetJ(0);
     }
   } else {
-    bool interpret = runtime->GetInstrumentation()->InterpretOnly() && !IsNative() &&
-        !IsProxyMethod();
     const bool kLogInvocationStartAndReturn = false;
     if (GetEntryPointFromCompiledCode() != NULL) {
-      if (!interpret) {
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
-        }
+      if (kLogInvocationStartAndReturn) {
+        LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
+      }
 #ifdef ART_USE_PORTABLE_COMPILER
-        (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
+      (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
 #else
-        (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
+      (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
 #endif
-        if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
-          // Unusual case where we were running LLVM generated code and an
-          // exception was thrown to force the activations to be removed from the
-          // stack. Continue execution in the interpreter.
-          self->ClearException();
-          ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
-          self->SetTopOfStack(NULL, 0);
-          self->SetTopOfShadowStack(shadow_frame);
-          interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
-        }
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
-        }
-      } else {
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << "Interpreting " << PrettyMethod(this) << "'";
-        }
-        if (this->IsStatic()) {
-          art::interpreter::EnterInterpreterFromInvoke(self, this, NULL, args, result);
-        } else {
-          Object* receiver = reinterpret_cast<Object*>(args[0]);
-          art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
-        }
-        if (kLogInvocationStartAndReturn) {
-          LOG(INFO) << "Returned '" << PrettyMethod(this) << "'";
-        }
+      if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
+        // Unusual case where we were running LLVM generated code and an
+        // exception was thrown to force the activations to be removed from the
+        // stack. Continue execution in the interpreter.
+        self->ClearException();
+        ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
+        self->SetTopOfStack(NULL, 0);
+        self->SetTopOfShadowStack(shadow_frame);
+        interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
+      }
+      if (kLogInvocationStartAndReturn) {
+        LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
       }
     } else {
       LOG(INFO) << "Not invoking '" << PrettyMethod(this)
diff --git a/src/mirror/abstract_method.h b/src/mirror/abstract_method.h
index c8aa11e..339471d 100644
--- a/src/mirror/abstract_method.h
+++ b/src/mirror/abstract_method.h
@@ -18,6 +18,7 @@
 #define ART_SRC_MIRROR_METHOD_H_
 
 #include "class.h"
+#include "dex_file.h"
 #include "invoke_type.h"
 #include "locks.h"
 #include "modifiers.h"
@@ -29,6 +30,7 @@
 struct ConstructorMethodOffsets;
 union JValue;
 struct MethodClassOffsets;
+class MethodHelper;
 struct MethodOffsets;
 class StringPiece;
 class ShadowFrame;
@@ -37,7 +39,8 @@
 
 class StaticStorageBase;
 
-typedef void (EntryPointFromInterpreter)(Thread* self, ShadowFrame* shadow_frame, JValue* result);
+typedef void (EntryPointFromInterpreter)(Thread* self, MethodHelper& mh,
+    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, JValue* result);
 
 // C++ mirror of java.lang.reflect.Method and java.lang.reflect.Constructor
 class MANAGED AbstractMethod : public Object {
@@ -120,6 +123,14 @@
 
   bool IsProxyMethod() const;
 
+  bool IsPreverified() const {
+    return (GetAccessFlags() & kAccPreverified) != 0;
+  }
+
+  void SetPreverified() {
+    SetAccessFlags(GetAccessFlags() | kAccPreverified);
+  }
+
   bool CheckIncompatibleClassChange(InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint16_t GetMethodIndex() const;
diff --git a/src/mirror/array.cc b/src/mirror/array.cc
index 84c2dc6..e2e63a6 100644
--- a/src/mirror/array.cc
+++ b/src/mirror/array.cc
@@ -20,7 +20,7 @@
 #include "class-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
 #include "object_array.h"
 #include "object_array-inl.h"
@@ -51,7 +51,7 @@
     return NULL;
   }
 
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   Array* array = down_cast<Array*>(heap->AllocObject(self, array_class, size));
   if (array != NULL) {
     DCHECK(array->IsArrayInstance());
diff --git a/src/mirror/class.cc b/src/mirror/class.cc
index 15129ab..2d2130c 100644
--- a/src/mirror/class.cc
+++ b/src/mirror/class.cc
@@ -23,7 +23,7 @@
 #include "dex_cache.h"
 #include "dex_file-inl.h"
 #include "field-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
 #include "object_array-inl.h"
 #include "object_utils.h"
@@ -604,5 +604,22 @@
   return NULL;
 }
 
+static void SetPreverifiedFlagOnMethods(mirror::ObjectArray<mirror::AbstractMethod>* methods)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (methods != NULL) {
+    for (int32_t index = 0, end = methods->GetLength(); index < end; ++index) {
+      mirror::AbstractMethod* method = methods->GetWithoutChecks(index);
+      DCHECK(method != NULL);
+      method->SetPreverified();
+    }
+  }
+}
+
+void Class::SetPreverifiedFlagOnAllMethods() {
+  DCHECK(IsVerified());
+  SetPreverifiedFlagOnMethods(GetDirectMethods());
+  SetPreverifiedFlagOnMethods(GetVirtualMethods());
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/src/mirror/class.h b/src/mirror/class.h
index 0661b42..084aa24 100644
--- a/src/mirror/class.h
+++ b/src/mirror/class.h
@@ -235,6 +235,23 @@
     return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
   }
 
+  // Can references of this type be assigned to by things of another type? For non-array types
+  // this is a matter of whether sub-classes may exist - which they can't if the type is final.
+  // For array classes, where all the classes are final due to there being no sub-classes, an
+  // Object[] may be assigned to by a String[] but a String[] may not be assigned to by other
+  // types as the component is final.
+  bool CannotBeAssignedFromOtherTypes() const {
+    if (!IsArrayClass()) {
+      return IsFinal();
+    } else {
+      Class* component = GetComponentType();
+      if (component->IsPrimitive()) {
+        return false;
+      } else {
+        return component->CannotBeAssignedFromOtherTypes();
+      }
+    }
+  }
 
   String* GetName() const;  // Returns the cached name.
   void SetName(String* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);  // Sets the cached name.
@@ -726,6 +743,9 @@
   static void SetClassClass(Class* java_lang_Class);
   static void ResetClass();
 
+  // When class is verified, set the kAccPreverified flag on each method.
+  void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   void SetVerifyErrorClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/src/mirror/dex_cache-inl.h b/src/mirror/dex_cache-inl.h
new file mode 100644
index 0000000..3b17c42
--- /dev/null
+++ b/src/mirror/dex_cache-inl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_MIRROR_DEX_CACHE_INL_H_
+#define ART_SRC_MIRROR_DEX_CACHE_INL_H_
+
+#include "dex_cache.h"
+
+namespace art {
+namespace mirror {
+
+inline AbstractMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  AbstractMethod* method = GetResolvedMethods()->Get(method_idx);
+  // Hide resolution trampoline methods from the caller
+  if (method != NULL && method->IsRuntimeMethod()) {
+    DCHECK(method == Runtime::Current()->GetResolutionMethod());
+    return NULL;
+  } else {
+    return method;
+  }
+}
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_SRC_MIRROR_DEX_CACHE_INL_H_
diff --git a/src/mirror/dex_cache.cc b/src/mirror/dex_cache.cc
index 3009786..239dc5e 100644
--- a/src/mirror/dex_cache.cc
+++ b/src/mirror/dex_cache.cc
@@ -19,8 +19,8 @@
 #include "abstract_method-inl.h"
 #include "base/logging.h"
 #include "class_linker.h"
-#include "heap.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
 #include "globals.h"
 #include "object.h"
 #include "object-inl.h"
@@ -78,17 +78,5 @@
   }
 }
 
-AbstractMethod* DexCache::GetResolvedMethod(uint32_t method_idx) const
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  AbstractMethod* method = GetResolvedMethods()->Get(method_idx);
-  // Hide resolution trampoline methods from the caller
-  if (method != NULL && method->IsRuntimeMethod()) {
-    DCHECK(method == Runtime::Current()->GetResolutionMethod());
-    return NULL;
-  } else {
-    return method;
-  }
-}
-
 }  // namespace mirror
 }  // namespace art
diff --git a/src/mirror/dex_cache_test.cc b/src/mirror/dex_cache_test.cc
index 3d753e1..441c6da 100644
--- a/src/mirror/dex_cache_test.cc
+++ b/src/mirror/dex_cache_test.cc
@@ -17,7 +17,7 @@
 #include "class_linker.h"
 #include "common_test.h"
 #include "dex_cache.h"
-#include "heap.h"
+#include "gc/heap.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "sirt_ref.h"
diff --git a/src/mirror/field-inl.h b/src/mirror/field-inl.h
index cda461b..be5dcab 100644
--- a/src/mirror/field-inl.h
+++ b/src/mirror/field-inl.h
@@ -20,7 +20,7 @@
 #include "field.h"
 
 #include "base/logging.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "jvalue.h"
 #include "object-inl.h"
 #include "object_utils.h"
diff --git a/src/mirror/field.cc b/src/mirror/field.cc
index 6e2559a..a96e8c8 100644
--- a/src/mirror/field.cc
+++ b/src/mirror/field.cc
@@ -17,7 +17,7 @@
 #include "field.h"
 
 #include "field-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
 #include "object_utils.h"
 #include "runtime.h"
diff --git a/src/mirror/object.cc b/src/mirror/object.cc
index 4acb567..b2d6e71 100644
--- a/src/mirror/object.cc
+++ b/src/mirror/object.cc
@@ -22,8 +22,8 @@
 #include "class_linker-inl.h"
 #include "field.h"
 #include "field-inl.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
 #include "iftable-inl.h"
 #include "monitor.h"
 #include "object-inl.h"
@@ -44,7 +44,7 @@
   // Object::SizeOf gets the right size even if we're an array.
   // Using c->AllocObject() here would be wrong.
   size_t num_bytes = SizeOf();
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   SirtRef<Object> copy(self, heap->AllocObject(self, c, num_bytes));
   if (copy.get() == NULL) {
     return NULL;
diff --git a/src/mirror/object_array-inl.h b/src/mirror/object_array-inl.h
index 05bce95..b130dac 100644
--- a/src/mirror/object_array-inl.h
+++ b/src/mirror/object_array-inl.h
@@ -19,7 +19,7 @@
 
 #include "object_array.h"
 
-#include "heap.h"
+#include "gc/heap.h"
 #include "mirror/class.h"
 #include "mirror/field.h"
 #include "runtime.h"
@@ -101,7 +101,7 @@
     MemberOffset src_offset(DataOffset(sizeof(Object*)).Int32Value() + src_pos * sizeof(Object*));
     MemberOffset dst_offset(DataOffset(sizeof(Object*)).Int32Value() + dst_pos * sizeof(Object*));
     Class* array_class = dst->GetClass();
-    Heap* heap = Runtime::Current()->GetHeap();
+    gc::Heap* heap = Runtime::Current()->GetHeap();
     if (array_class == src->GetClass()) {
       // No need for array store checks if arrays are of the same type
       for (size_t i = 0; i < length; i++) {
diff --git a/src/mirror/object_test.cc b/src/mirror/object_test.cc
index abf6c29..53a1df9 100644
--- a/src/mirror/object_test.cc
+++ b/src/mirror/object_test.cc
@@ -27,8 +27,8 @@
 #include "common_test.h"
 #include "dex_file.h"
 #include "field-inl.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
 #include "iftable-inl.h"
 #include "abstract_method-inl.h"
 #include "object-inl.h"
@@ -283,7 +283,7 @@
   uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
 
   Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
-                                   sizeof(Object*));
+                                   sizeof(Object*), true);
   Object* s0 = field->GetObj(klass);
   EXPECT_TRUE(s0 != NULL);
 
diff --git a/src/mirror/stack_trace_element.cc b/src/mirror/stack_trace_element.cc
index 9d557ec..1ad0182 100644
--- a/src/mirror/stack_trace_element.cc
+++ b/src/mirror/stack_trace_element.cc
@@ -17,7 +17,7 @@
 #include "stack_trace_element.h"
 
 #include "class.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
 #include "string.h"
 
diff --git a/src/mirror/string.cc b/src/mirror/string.cc
index 45a6779..97126cb 100644
--- a/src/mirror/string.cc
+++ b/src/mirror/string.cc
@@ -17,7 +17,7 @@
 #include "string.h"
 
 #include "array.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "intern_table.h"
 #include "object-inl.h"
 #include "runtime.h"
diff --git a/src/mirror/throwable.cc b/src/mirror/throwable.cc
index bbff9c2..78b76dc 100644
--- a/src/mirror/throwable.cc
+++ b/src/mirror/throwable.cc
@@ -19,7 +19,7 @@
 #include "abstract_method-inl.h"
 #include "class-inl.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
 #include "object_array.h"
 #include "object_array-inl.h"
diff --git a/src/modifiers.h b/src/modifiers.h
index a15b096..85bc06d 100644
--- a/src/modifiers.h
+++ b/src/modifiers.h
@@ -46,7 +46,9 @@
 static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
 static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
 // TODO: JACK CLASS ACCESS (HACK TO BE REMOVED)
-static const uint32_t kAccClassJack = 0x000080000;  // class (dex only)
+static const uint32_t kAccClassJack = 0x00080000;  // class (dex only)
+
+static const uint32_t kAccPreverified = 0x00100000;  // method (dex only)
 
 // Special runtime-only flags.
 // Note: if only kAccClassIsReference is set, we have a soft reference.
diff --git a/src/native/dalvik_system_DexFile.cc b/src/native/dalvik_system_DexFile.cc
index e07339c..b9838f8 100644
--- a/src/native/dalvik_system_DexFile.cc
+++ b/src/native/dalvik_system_DexFile.cc
@@ -20,7 +20,8 @@
 #include "class_linker.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
-#include "gc/space.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
 #include "image.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
@@ -248,13 +249,14 @@
     return JNI_TRUE;
   }
 
-  Heap* heap = runtime->GetHeap();
-  const Spaces& spaces = heap->GetSpaces();
+  gc::Heap* heap = runtime->GetHeap();
+  const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
   // TODO: C++0x auto
-  for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
-    if ((*cur)->IsImageSpace()) {
+  typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+  for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+    if ((*it)->IsImageSpace()) {
       // TODO: Ensure this works with multiple image spaces.
-      const ImageHeader& image_header = (*cur)->AsImageSpace()->GetImageHeader();
+      const ImageHeader& image_header = (*it)->AsImageSpace()->GetImageHeader();
       if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() != image_header.GetOatChecksum()) {
         ScopedObjectAccess soa(env);
         LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
diff --git a/src/native/dalvik_system_VMRuntime.cc b/src/native/dalvik_system_VMRuntime.cc
index d2ef43c..0a2e1a6 100644
--- a/src/native/dalvik_system_VMRuntime.cc
+++ b/src/native/dalvik_system_VMRuntime.cc
@@ -20,13 +20,14 @@
 #include "common_throws.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "gc/allocator/dlmalloc.h"
+#include "gc/space/dlmalloc_space.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
 #include "mirror/object-inl.h"
 #include "object_utils.h"
 #include "scoped_thread_state_change.h"
-#include "gc/space.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "toStringArray.h"
@@ -164,11 +165,11 @@
   uint64_t start_ns = NanoTime();
 
   // Trim the managed heap.
-  Heap* heap = Runtime::Current()->GetHeap();
-  DlMallocSpace* alloc_space = heap->GetAllocSpace();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  gc::space::DlMallocSpace* alloc_space = heap->GetAllocSpace();
   size_t alloc_space_size = alloc_space->Size();
   float managed_utilization =
-      static_cast<float>(alloc_space->GetNumBytesAllocated()) / alloc_space_size;
+      static_cast<float>(alloc_space->GetBytesAllocated()) / alloc_space_size;
   size_t managed_reclaimed = heap->Trim();
 
   uint64_t gc_heap_end_ns = NanoTime();
@@ -176,7 +177,7 @@
   // Trim the native heap.
   dlmalloc_trim(0);
   size_t native_reclaimed = 0;
-  dlmalloc_inspect_all(MspaceMadviseCallback, &native_reclaimed);
+  dlmalloc_inspect_all(DlmallocMadviseCallback, &native_reclaimed);
 
   uint64_t end_ns = NanoTime();
 
diff --git a/src/native/java_lang_Runtime.cc b/src/native/java_lang_Runtime.cc
index 54ccddc..3642635 100644
--- a/src/native/java_lang_Runtime.cc
+++ b/src/native/java_lang_Runtime.cc
@@ -18,7 +18,7 @@
 #include <limits.h>
 #include <unistd.h>
 
-#include "heap.h"
+#include "gc/heap.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "runtime.h"
diff --git a/src/native/java_lang_System.cc b/src/native/java_lang_System.cc
index d8df9d9..2462f2f 100644
--- a/src/native/java_lang_System.cc
+++ b/src/native/java_lang_System.cc
@@ -15,7 +15,7 @@
  */
 
 #include "common_throws.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "jni_internal.h"
 #include "mirror/array.h"
 #include "mirror/class.h"
diff --git a/src/native/java_lang_Thread.cc b/src/native/java_lang_Thread.cc
index 7ccfaaa..8ef190a 100644
--- a/src/native/java_lang_Thread.cc
+++ b/src/native/java_lang_Thread.cc
@@ -74,6 +74,7 @@
     case kNative:                         return kJavaRunnable;
     case kWaitingForGcToComplete:         return kJavaWaiting;
     case kWaitingPerformingGc:            return kJavaWaiting;
+    case kWaitingForCheckPointsToRun:     return kJavaWaiting;
     case kWaitingForDebuggerSend:         return kJavaWaiting;
     case kWaitingForDebuggerToAttach:     return kJavaWaiting;
     case kWaitingInMainDebuggerLoop:      return kJavaWaiting;
diff --git a/src/native/sun_misc_Unsafe.cc b/src/native/sun_misc_Unsafe.cc
index abb0d5c..eece81a 100644
--- a/src/native/sun_misc_Unsafe.cc
+++ b/src/native/sun_misc_Unsafe.cc
@@ -15,7 +15,7 @@
  */
 
 #include "atomic.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "jni_internal.h"
 #include "mirror/object.h"
 #include "mirror/object-inl.h"
diff --git a/src/oat.cc b/src/oat.cc
index 4eb97f5..e606953 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '0', '5', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '0', '6', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
@@ -57,6 +57,10 @@
   UpdateChecksum(image_file_location.data(), image_file_location_size_);
 
   executable_offset_ = 0;
+  interpreter_to_interpreter_entry_offset_ = 0;
+  interpreter_to_quick_entry_offset_ = 0;
+  portable_resolution_trampoline_offset_ = 0;
+  quick_resolution_trampoline_offset_ = 0;
 }
 
 bool OatHeader::IsValid() const {
@@ -97,6 +101,92 @@
   return executable_offset_;
 }
 
+void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
+  DCHECK_ALIGNED(executable_offset, kPageSize);
+  CHECK_GT(executable_offset, sizeof(OatHeader));
+  DCHECK(IsValid());
+  DCHECK_EQ(executable_offset_, 0U);
+
+  executable_offset_ = executable_offset;
+  UpdateChecksum(&executable_offset_, sizeof(executable_offset));
+}
+
+const void* OatHeader::GetInterpreterToInterpreterEntry() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterEntryOffset();
+}
+
+uint32_t OatHeader::GetInterpreterToInterpreterEntryOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(interpreter_to_interpreter_entry_offset_, executable_offset_);
+  return interpreter_to_interpreter_entry_offset_;
+}
+
+void OatHeader::SetInterpreterToInterpreterEntryOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= executable_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(interpreter_to_interpreter_entry_offset_, 0U) << offset;
+
+  interpreter_to_interpreter_entry_offset_ = offset;
+  UpdateChecksum(&interpreter_to_interpreter_entry_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetInterpreterToQuickEntry() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToQuickEntryOffset();
+}
+
+uint32_t OatHeader::GetInterpreterToQuickEntryOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(interpreter_to_quick_entry_offset_, interpreter_to_interpreter_entry_offset_);
+  return interpreter_to_quick_entry_offset_;
+}
+
+void OatHeader::SetInterpreterToQuickEntryOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= interpreter_to_interpreter_entry_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(interpreter_to_quick_entry_offset_, 0U) << offset;
+
+  interpreter_to_quick_entry_offset_ = offset;
+  UpdateChecksum(&interpreter_to_quick_entry_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetPortableResolutionTrampoline() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
+}
+
+uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(portable_resolution_trampoline_offset_, interpreter_to_quick_entry_offset_);
+  return portable_resolution_trampoline_offset_;
+}
+
+void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= interpreter_to_quick_entry_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;
+
+  portable_resolution_trampoline_offset_ = offset;
+  UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
+}
+
+const void* OatHeader::GetQuickResolutionTrampoline() const {
+  return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
+}
+
+uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
+  DCHECK(IsValid());
+  CHECK_GE(quick_resolution_trampoline_offset_, portable_resolution_trampoline_offset_);
+  return quick_resolution_trampoline_offset_;
+}
+
+void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
+  CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
+  DCHECK(IsValid());
+  DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
+
+  quick_resolution_trampoline_offset_ = offset;
+  UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset));
+}
+
 uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
   CHECK(IsValid());
   return image_file_location_oat_checksum_;
@@ -123,16 +213,6 @@
                      GetImageFileLocationSize());
 }
 
-void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
-  DCHECK_ALIGNED(executable_offset, kPageSize);
-  CHECK_GT(executable_offset, sizeof(OatHeader));
-  DCHECK(IsValid());
-  DCHECK_EQ(executable_offset_, 0U);
-
-  executable_offset_ = executable_offset;
-  UpdateChecksum(&executable_offset_, sizeof(executable_offset));
-}
-
 OatMethodOffsets::OatMethodOffsets()
   : code_offset_(0),
     frame_size_in_bytes_(0),
diff --git a/src/oat.h b/src/oat.h
index cf98891..c67a1a6 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -43,8 +43,20 @@
     return dex_file_count_;
   }
   uint32_t GetExecutableOffset() const;
-  InstructionSet GetInstructionSet() const;
   void SetExecutableOffset(uint32_t executable_offset);
+  const void* GetInterpreterToInterpreterEntry() const;
+  uint32_t GetInterpreterToInterpreterEntryOffset() const;
+  void SetInterpreterToInterpreterEntryOffset(uint32_t offset);
+  const void* GetInterpreterToQuickEntry() const;
+  uint32_t GetInterpreterToQuickEntryOffset() const;
+  void SetInterpreterToQuickEntryOffset(uint32_t offset);
+  const void* GetPortableResolutionTrampoline() const;
+  uint32_t GetPortableResolutionTrampolineOffset() const;
+  void SetPortableResolutionTrampolineOffset(uint32_t offset);
+  const void* GetQuickResolutionTrampoline() const;
+  uint32_t GetQuickResolutionTrampolineOffset() const;
+  void SetQuickResolutionTrampolineOffset(uint32_t offset);
+  InstructionSet GetInstructionSet() const;
   uint32_t GetImageFileLocationOatChecksum() const;
   uint32_t GetImageFileLocationOatDataBegin() const;
   uint32_t GetImageFileLocationSize() const;
@@ -62,6 +74,10 @@
   InstructionSet instruction_set_;
   uint32_t dex_file_count_;
   uint32_t executable_offset_;
+  uint32_t interpreter_to_interpreter_entry_offset_;
+  uint32_t interpreter_to_quick_entry_offset_;
+  uint32_t portable_resolution_trampoline_offset_;
+  uint32_t quick_resolution_trampoline_offset_;
 
   uint32_t image_file_location_oat_checksum_;
   uint32_t image_file_location_oat_data_begin_;
diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
index 1a5fe47..2e9453c 100644
--- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
+++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc
@@ -91,12 +91,26 @@
 extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
 extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
 
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
 // Intrinsic entrypoints.
 extern "C" int32_t __memcmp16(void*, void*, int32_t);
 extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
 extern "C" int32_t art_quick_string_compareto(void*, void*);
 
 // Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
 extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -187,6 +201,10 @@
   points->pShrLong = art_quick_shr_long;
   points->pUshrLong = art_quick_ushr_long;
 
+  // Interpreter
+  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
   // Intrinsics
   points->pIndexOf = art_quick_indexof;
   points->pMemcmp16 = __memcmp16;
@@ -194,6 +212,8 @@
   points->pMemcpy = memcpy;
 
   // Invocation
+  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
   points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
   points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
   points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S
index 3578ba0..f19e8ba 100644
--- a/src/oat/runtime/arm/runtime_support_arm.S
+++ b/src/oat/runtime/arm/runtime_support_arm.S
@@ -246,48 +246,6 @@
 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
-     /*
-     * Portable resolution trampoline.
-     */
-     .extern artPortableResolutionTrampoline
-ENTRY art_portable_resolution_trampoline
-    push   {r0, r1, r2, r3, lr}           @ spill regs
-    .save  {r0, r1, r2, r3, lr}
-    .pad #20
-    .cfi_adjust_cfa_offset 20
-    sub    sp, #12                        @ pad stack pointer to align frame
-    .pad #12
-    .cfi_adjust_cfa_offset 12
-    mov    r2, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass stack pointer
-    blx    artPortableResolutionTrampoline   @ (method_idx, sp, Thread*)
-    mov    r12, r0                        @ save method code pointer result
-    add    sp, #12                        @ remove padding from stack pointer
-    .cfi_adjust_cfa_offset -12
-    pop    {r0, r1, r2, r3, lr}           @ restore regs
-    .cfi_adjust_cfa_offset -20
-    cmp    r12, #0                        @ is method code null?
-    bxne   r12                            @ if non-null, tail call to method's code
-    bx     lr                             @ otherwise, return to caller to handle exception
-END art_portable_resolution_trampoline
-
-    /*
-     * Quick resolution trampoline.
-     */
-     .extern artQuickResolutionTrampoline
-ENTRY art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
-    mov    r2, r9                         @ pass Thread::Current
-    mov    r1, sp                         @ pass stack pointer
-    blx    artQuickResolutionTrampoline   @ (method_idx, sp, Thread*)
-    mov    r12, r0                        @ save method code pointer result
-    add    sp, #4                         @ set up stack pointer
-    .cfi_adjust_cfa_offset -4
-    pop    {r0-r3, r5-r8, r10-r11, lr}    @ 11 words, r0 will hold method*
-    .cfi_adjust_cfa_offset -44
-    bx     r12                            @ leaf call to method code
-END art_quick_resolution_trampoline
-
     /*
      * Portable invocation stub.
      * On entry:
diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
index eb82c42..8e06611 100644
--- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
+++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc
@@ -93,12 +93,26 @@
 extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t);
 extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t);
 
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
 // Intrinsic entrypoints.
 extern "C" int32_t __memcmp16(void*, void*, int32_t);
 extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
 extern "C" int32_t art_quick_string_compareto(void*, void*);
 
 // Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
 extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -188,6 +202,10 @@
   points->pShrLong = art_quick_shr_long;
   points->pUshrLong = art_quick_ushr_long;
 
+  // Interpreter
+  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
   // Intrinsics
   points->pIndexOf = art_quick_indexof;
   points->pMemcmp16 = __memcmp16;
@@ -195,6 +213,8 @@
   points->pMemcpy = memcpy;
 
   // Invocation
+  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
   points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
   points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
   points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S
index 2144e34..45d583e 100644
--- a/src/oat/runtime/mips/runtime_support_mips.S
+++ b/src/oat/runtime/mips/runtime_support_mips.S
@@ -413,71 +413,6 @@
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
     /*
-     * Portable resolution trampoline.
-     */
-    .extern artPortableResolutionTrampoline
-ENTRY art_portable_resolution_trampoline
-    GENERATE_GLOBAL_POINTER
-    addiu $sp, $sp, -32          # leave room for $a0, $a1, $a2, $a3, and $ra
-    .cfi_adjust_cfa_offset 32
-    sw     $ra, 16($sp)
-    .cfi_rel_offset 31, 16
-    sw     $a3, 12($sp)
-    .cfi_rel_offset 7, 12
-    sw     $a2, 8($sp)
-    .cfi_rel_offset 6, 8
-    sw     $a1, 4($sp)
-    .cfi_rel_offset 5, 4
-    sw     $a0, 0($sp)
-    .cfi_rel_offset 4, 0
-    move  $a2, $s1              # pass Thread::Current()
-    jal   artPortableResolutionTrampoline  # (method_idx, sp, Thread*)
-    move  $a1, $sp              # pass stack pointer
-    lw    $a0, 0($sp)           # restore registers from stack
-    lw    $a1, 4($sp)
-    lw    $a2, 8($sp)
-    lw    $a3, 12($sp)
-    lw    $ra, 16($sp)
-    beq   $v0, $zero, resolve_fail
-    addiu $sp, $sp, 32          # restore the stack
-    .cfi_adjust_cfa_offset -32
-    jr    $t9                   # leaf call to method's code
-    move  $t9, $v0              # put method code result in $t9
-resolve_fail:
-    jr    $ra
-    nop
-END art_portable_resolution_trampoline
-
-    /*
-     * Quick resolution trampoline.
-     */
-    .extern artQuickResolutionTrampoline
-ENTRY art_quick_resolution_trampoline
-    GENERATE_GLOBAL_POINTER
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    move  $a2, $s1              # pass Thread::Current()
-    jal   artQuickResolutionTrampoline  # (method_idx, sp, Thread*)
-    move  $a1, $sp              # pass stack pointer
-    move  $t9, $v0              # put method code result in $t9
-    lw    $a0, 0($sp)           # restore registers from stack
-    lw    $a1, 4($sp)
-    lw    $a2, 8($sp)
-    lw    $a3, 12($sp)
-    lw    $s2, 28($sp)
-    lw    $s3, 32($sp)
-    lw    $s4, 36($sp)
-    lw    $s5, 40($sp)
-    lw    $s6, 44($sp)
-    lw    $s7, 48($sp)
-    lw    $gp, 52($sp)
-    lw    $fp, 56($sp)
-    lw    $ra, 60($sp)
-    jr    $t9                   # leaf call to method's code
-    addiu $sp, $sp, 64          # restore the stack
-    .cfi_adjust_cfa_offset -64
-END art_quick_resolution_trampoline
-
-    /*
      * Common invocation stub for portable and quick.
      * On entry:
      *   a0 = method pointer
diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h
index 72d5348..c1a2587 100644
--- a/src/oat/runtime/oat_support_entrypoints.h
+++ b/src/oat/runtime/oat_support_entrypoints.h
@@ -17,6 +17,7 @@
 #ifndef ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
 #define ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_
 
+#include "dex_file-inl.h"
 #include "runtime.h"
 
 #define ENTRYPOINT_OFFSET(x) \
@@ -30,6 +31,8 @@
 class Object;
 }  // namespace mirror
 class DvmDex;
+class MethodHelper;
+class ShadowFrame;
 class Thread;
 
 struct PACKED(4) EntryPoints {
@@ -104,6 +107,14 @@
   uint64_t (*pShrLong)(uint64_t, uint32_t);
   uint64_t (*pUshrLong)(uint64_t, uint32_t);
 
+  // Interpreter
+  void (*pInterpreterToInterpreterEntry)(Thread* self, MethodHelper& mh,
+                                         const DexFile::CodeItem* code_item,
+                                         ShadowFrame* shadow_frame, JValue* result);
+  void (*pInterpreterToQuickEntry)(Thread* self, MethodHelper& mh,
+                                   const DexFile::CodeItem* code_item,
+                                   ShadowFrame* shadow_frame, JValue* result);
+
   // Intrinsics
   int32_t (*pIndexOf)(void*, uint32_t, uint32_t, uint32_t);
   int32_t (*pMemcmp16)(void*, void*, int32_t);
@@ -111,6 +122,10 @@
   void* (*pMemcpy)(void*, const void*, size_t);
 
   // Invocation
+  const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+                                                       mirror::AbstractMethod**, Thread*);
+  const void* (*pQuickResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*,
+                                                    mirror::AbstractMethod**, Thread*);
   void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
   void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
   void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
@@ -131,24 +146,25 @@
   void (*pThrowStackOverflowFromCode)(void*);
 };
 
+
 // JNI entrypoints.
 extern uint32_t JniMethodStart(Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    UNLOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
-    UNLOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    UNLOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
                                      Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
                                                  Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 
 extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
                                                              uint32_t saved_local_ref_cookie,
                                                              jobject locked, Thread* self)
-    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) __attribute__ ((hot));
+    SHARED_LOCK_FUNCTION(Locks::mutator_lock_) HOT_ATTR;
 
 // Initialize an entry point data structure.
 void InitEntryPoints(EntryPoints* points);
diff --git a/src/oat/runtime/support_dexcache.cc b/src/oat/runtime/support_dexcache.cc
index 3e8ebc6..0af7a62 100644
--- a/src/oat/runtime/support_dexcache.cc
+++ b/src/oat/runtime/support_dexcache.cc
@@ -15,7 +15,7 @@
  */
 
 #include "callee_save_frame.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "mirror/abstract_method-inl.h"
diff --git a/src/oat/runtime/support_field.cc b/src/oat/runtime/support_field.cc
index 5821063..c20326c 100644
--- a/src/oat/runtime/support_field.cc
+++ b/src/oat/runtime/support_field.cc
@@ -34,7 +34,7 @@
     return field->Get32(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get32(field->GetDeclaringClass());
   }
@@ -50,7 +50,7 @@
     return field->Get64(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveRead, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     return field->Get64(field->GetDeclaringClass());
   }
@@ -67,7 +67,7 @@
     return field->GetObj(field->GetDeclaringClass());
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     return field->GetObj(field->GetDeclaringClass());
   }
@@ -83,7 +83,7 @@
     return field->Get32(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -104,7 +104,7 @@
     return field->Get64(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveRead, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -126,7 +126,7 @@
     return field->GetObj(obj);
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectRead, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -148,7 +148,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     field->Set32(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -165,7 +165,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticPrimitiveWrite, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     field->Set64(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -186,7 +186,7 @@
     }
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*));
+  field = FindFieldFromCode(field_idx, referrer, self, StaticObjectWrite, sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     field->SetObj(field->GetDeclaringClass(), new_value);
     return 0;  // success
@@ -204,7 +204,7 @@
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int32_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -231,7 +231,7 @@
   }
   *sp = callee_save;
   self->SetTopOfStack(sp, 0);
-  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t));
+  field = FindFieldFromCode(field_idx, referrer, self, InstancePrimitiveWrite, sizeof(int64_t), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -257,7 +257,7 @@
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode(field_idx, referrer, self, InstanceObjectWrite,
-                            sizeof(mirror::Object*));
+                            sizeof(mirror::Object*), true);
   if (LIKELY(field != NULL)) {
     if (UNLIKELY(obj == NULL)) {
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
diff --git a/src/oat/runtime/support_interpreter.cc b/src/oat/runtime/support_interpreter.cc
index a5d6fa3..55be54f 100644
--- a/src/oat/runtime/support_interpreter.cc
+++ b/src/oat/runtime/support_interpreter.cc
@@ -110,12 +110,11 @@
   return result.GetJ();
 }
 
-void artInterpreterToQuickEntry(Thread* self, ShadowFrame* shadow_frame, JValue* result)
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::AbstractMethod* method = shadow_frame->GetMethod();
-  MethodHelper mh(method);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
-
   uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(shadow_frame, arg_offset);
diff --git a/src/oat/runtime/support_invoke.cc b/src/oat/runtime/support_invoke.cc
index a96555d..6a95f3c 100644
--- a/src/oat/runtime/support_invoke.cc
+++ b/src/oat/runtime/support_invoke.cc
@@ -17,6 +17,7 @@
 #include "callee_save_frame.h"
 #include "dex_instruction-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index df2dda2..71b67d0 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -32,6 +32,7 @@
 
 // Lazily resolve a method for portable. Called by stub code.
 extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
                                                        mirror::AbstractMethod** called_addr,
                                                        Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -79,6 +80,14 @@
         invoke_type = kVirtual;
         is_range = true;
         break;
+      case Instruction::INVOKE_INTERFACE:
+        invoke_type = kInterface;
+        is_range = false;
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+        invoke_type = kInterface;
+        is_range = true;
+        break;
       default:
         LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
         // Avoid used uninitialized warnings.
@@ -87,6 +96,12 @@
     }
     uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
     called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
+    // Refine called method based on receiver.
+    if (invoke_type == kVirtual) {
+      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+    } else if (invoke_type == kInterface) {
+      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+    }
   } else {
     CHECK(called->IsStatic()) << PrettyMethod(called);
     invoke_type = kStatic;
@@ -129,7 +144,7 @@
     // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
     // Don't want infinite recursion.
-    DCHECK(code != GetResolutionTrampoline());
+    DCHECK(code != GetResolutionTrampoline(linker));
     // Set up entry into main method
     *called_addr = called;
   }
@@ -138,6 +153,7 @@
 
 // Lazily resolve a method for quick. Called by stub code.
 extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
                                                     mirror::AbstractMethod** sp, Thread* thread)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
 #if defined(__arm__)
@@ -261,6 +277,14 @@
         invoke_type = kVirtual;
         is_range = true;
         break;
+      case Instruction::INVOKE_INTERFACE:
+        invoke_type = kInterface;
+        is_range = false;
+        break;
+      case Instruction::INVOKE_INTERFACE_RANGE:
+        invoke_type = kInterface;
+        is_range = true;
+        break;
       default:
         LOG(FATAL) << "Unexpected call into trampoline: " << instr->DumpString(NULL);
         // Avoid used uninitialized warnings.
@@ -334,6 +358,12 @@
   if (LIKELY(!thread->IsExceptionPending())) {
     // Incompatible class change should have been handled in resolve method.
     CHECK(!called->CheckIncompatibleClassChange(invoke_type));
+    // Refine called method based on receiver.
+    if (invoke_type == kVirtual) {
+      called = receiver->GetClass()->FindVirtualMethodForVirtual(called);
+    } else if (invoke_type == kInterface) {
+      called = receiver->GetClass()->FindVirtualMethodForInterface(called);
+    }
     // Ensure that the called method's class is initialized.
     mirror::Class* called_class = called->GetDeclaringClass();
     linker->EnsureInitialized(called_class, true, true);
@@ -363,7 +393,7 @@
     // Expect class to at least be initializing.
     DCHECK(called->GetDeclaringClass()->IsInitializing());
     // Don't want infinite recursion.
-    DCHECK(code != GetResolutionTrampoline());
+    DCHECK(code != GetResolutionTrampoline(linker));
     // Set up entry into main method
     regs[0] = reinterpret_cast<uintptr_t>(called);
   }
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 357bbe0..a90a583 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -75,6 +75,14 @@
 extern "C" uint64_t art_quick_lshr_from_code(uint64_t, uint32_t);
 extern "C" uint64_t art_quick_lushr_from_code(uint64_t, uint32_t);
 
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
 // Intrinsic entrypoints.
 extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t);
 extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
@@ -82,6 +90,12 @@
 extern "C" void* art_quick_memcpy(void*, const void*, size_t);
 
 // Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
 extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
 extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
@@ -171,6 +185,10 @@
   points->pShrLong = art_quick_lshr_from_code;
   points->pUshrLong = art_quick_lushr_from_code;
 
+  // Interpreter
+  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
   // Intrinsics
   points->pIndexOf = art_quick_indexof;
   points->pMemcmp16 = art_quick_memcmp16;
@@ -178,6 +196,8 @@
   points->pMemcpy = art_quick_memcpy;
 
   // Invocation
+  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
   points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
   points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
   points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index d3a1fb7..ee6db0c 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -301,55 +301,6 @@
 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
-     /*
-     * Portable resolution trampoline.
-     */
-DEFINE_FUNCTION art_portable_resolution_trampoline
-    PUSH ebp                      // stash %ebp
-    movl %esp, %ebp               // save %esp
-    .cfi_def_cfa_register ebp
-    subl LITERAL(8), %esp         // align stack
-    movl 8(%ebp), %eax            // load the called method* into %eax
-    leal 8(%ebp), %edx            // put the called method* address in %edx
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    PUSH edx                      // pass called method* address
-    PUSH eax                      // pass method*
-    call SYMBOL(artPortableResolutionTrampoline)  // (method_idx, sp, Thread*)
-    leave                         // restore the stack and %ebp
-    .cfi_def_cfa esp, 4
-    .cfi_restore ebp
-    cmpl LITERAL(0), %eax         // check if returned method code is null
-    je resolve_fail               // if null, jump to return to handle
-    jmp *%eax                     // otherwise, tail call to intended method
-resolve_fail:
-    ret
-END_FUNCTION art_portable_resolution_trampoline
-
-    /*
-     * Quick resolution trampoline.
-     */
-DEFINE_FUNCTION art_quick_resolution_trampoline
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    movl %esp, %ecx               // save stack pointer
-    PUSH eax                      // align stack
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    .cfi_adjust_cfa_offset 4
-    PUSH ecx                      // pass stack pointer
-    PUSH eax                      // pass method*
-    call SYMBOL(artQuickResolutionTrampoline)  // (method_idx, sp, Thread*)
-    movl %eax, %edi               // save returned code pointer in %edi
-    addl LITERAL(16), %esp        // pop arguments
-    .cfi_adjust_cfa_offset -16
-    POP eax                       // restore registers
-    POP ecx
-    POP edx
-    POP ebx
-    POP ebp
-    POP esi
-    xchgl %edi, (%esp)            // swap %edi and code pointer
-    ret                           // tail call to intended method
-END_FUNCTION art_quick_resolution_trampoline
-
     /*
      * Portable invocation stub.
      * On entry:
diff --git a/src/oat_test.cc b/src/oat_test.cc
index dd336d9..29e2891 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -68,16 +68,16 @@
   const bool compile = false;  // DISABLED_ due to the time to compile libcore
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
+  // TODO: make selectable
+#if defined(ART_USE_PORTABLE_COMPILER)
+  CompilerBackend compiler_backend = kPortable;
+#else
+  CompilerBackend compiler_backend = kQuick;
+#endif
+  compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, NULL, 2, false,
+                                            true, true));
   jobject class_loader = NULL;
   if (compile) {
-    // TODO: make selectable
-#if defined(ART_USE_PORTABLE_COMPILER)
-    CompilerBackend compiler_backend = kPortable;
-#else
-    CompilerBackend compiler_backend = kQuick;
-#endif
-    compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false,
-                                              NULL, true, true));
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
   }
 
@@ -143,7 +143,7 @@
 TEST_F(OatTest, OatHeaderSizeCheck) {
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
-  EXPECT_EQ(36U, sizeof(OatHeader));
+  EXPECT_EQ(52U, sizeof(OatHeader));
   EXPECT_EQ(28U, sizeof(OatMethodOffsets));
 }
 
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 8acbfe9..1d249d6 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -22,6 +22,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
 #include "dex_file-inl.h"
+#include "gc/space/space.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/array.h"
 #include "mirror/class_loader.h"
@@ -30,7 +31,6 @@
 #include "output_stream.h"
 #include "safe_map.h"
 #include "scoped_thread_state_change.h"
-#include "gc/space.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
@@ -54,13 +54,35 @@
                      uint32_t image_file_location_oat_begin,
                      const std::string& image_file_location,
                      const CompilerDriver* compiler)
-    : compiler_driver_(compiler) {
-  image_file_location_oat_checksum_ = image_file_location_oat_checksum;
-  image_file_location_oat_begin_ = image_file_location_oat_begin;
-  image_file_location_ = image_file_location;
-  dex_files_ = &dex_files;
-  oat_header_ = NULL;
-  executable_offset_padding_length_ = 0;
+  : compiler_driver_(compiler),
+    dex_files_(&dex_files),
+    image_file_location_oat_checksum_(image_file_location_oat_checksum),
+    image_file_location_oat_begin_(image_file_location_oat_begin),
+    image_file_location_(image_file_location),
+    oat_header_(NULL),
+    size_dex_file_alignment_(0),
+    size_executable_offset_alignment_(0),
+    size_oat_header_(0),
+    size_oat_header_image_file_location_(0),
+    size_dex_file_(0),
+    size_interpreter_to_interpreter_entry_(0),
+    size_interpreter_to_quick_entry_(0),
+    size_portable_resolution_trampoline_(0),
+    size_quick_resolution_trampoline_(0),
+    size_stubs_alignment_(0),
+    size_code_size_(0),
+    size_code_(0),
+    size_code_alignment_(0),
+    size_mapping_table_(0),
+    size_vmap_table_(0),
+    size_gc_map_(0),
+    size_oat_dex_file_location_size_(0),
+    size_oat_dex_file_location_data_(0),
+    size_oat_dex_file_location_checksum_(0),
+    size_oat_dex_file_offset_(0),
+    size_oat_dex_file_methods_offsets_(0),
+    size_oat_class_status_(0),
+    size_oat_class_method_offsets_(0) {
 
   size_t offset = InitOatHeader();
   offset = InitOatDexFiles(offset);
@@ -70,6 +92,7 @@
   offset = InitOatCodeDexFiles(offset);
 
   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
+  CHECK(image_file_location.empty() == compiler->IsImage());
 }
 
 OatWriter::~OatWriter() {
@@ -106,7 +129,9 @@
   // calculate the offsets within OatDexFiles to the DexFiles
   for (size_t i = 0; i != dex_files_->size(); ++i) {
     // dex files are required to be 4 byte aligned
+    size_t original_offset = offset;
     offset = RoundUp(offset, 4);
+    size_dex_file_alignment_ += offset - original_offset;
 
     // set offset in OatDexFile to DexFile
     oat_dex_files_[i]->dex_file_offset_ = offset;
@@ -162,7 +187,33 @@
   // required to be on a new page boundary
   offset = RoundUp(offset, kPageSize);
   oat_header_->SetExecutableOffset(offset);
-  executable_offset_padding_length_ = offset - old_offset;
+  size_executable_offset_alignment_ = offset - old_offset;
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    oat_header_->SetInterpreterToInterpreterEntryOffset(offset);
+    interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry());
+    offset += interpreter_to_interpreter_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetInterpreterToQuickEntryOffset(offset);
+    interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry());
+    offset += interpreter_to_quick_entry_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetPortableResolutionTrampolineOffset(offset);
+    portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline());
+    offset += portable_resolution_trampoline_->size();
+
+    offset = CompiledCode::AlignCode(offset, instruction_set);
+    oat_header_->SetQuickResolutionTrampolineOffset(offset);
+    quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline());
+    offset += quick_resolution_trampoline_->size();
+  } else {
+    oat_header_->SetInterpreterToInterpreterEntryOffset(0);
+    oat_header_->SetInterpreterToQuickEntryOffset(0);
+    oat_header_->SetPortableResolutionTrampolineOffset(0);
+    oat_header_->SetQuickResolutionTrampolineOffset(0);
+  }
   return offset;
 }
 
@@ -389,11 +440,13 @@
     PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
     return false;
   }
+  size_oat_header_ += sizeof(*oat_header_);
 
   if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
     PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
     return false;
   }
+  size_oat_header_image_file_location_ += image_file_location_.size();
 
   if (!WriteTables(out)) {
     LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
@@ -412,12 +465,47 @@
     return false;
   }
 
+  if (kIsDebugBuild) {
+    uint32_t size_total = 0;
+    #define DO_STAT(x) \
+      LOG(INFO) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
+      size_total += x;
+
+    DO_STAT(size_dex_file_alignment_);
+    DO_STAT(size_executable_offset_alignment_);
+    DO_STAT(size_oat_header_);
+    DO_STAT(size_oat_header_image_file_location_);
+    DO_STAT(size_dex_file_);
+    DO_STAT(size_interpreter_to_interpreter_entry_);
+    DO_STAT(size_interpreter_to_quick_entry_);
+    DO_STAT(size_portable_resolution_trampoline_);
+    DO_STAT(size_quick_resolution_trampoline_);
+    DO_STAT(size_stubs_alignment_);
+    DO_STAT(size_code_size_);
+    DO_STAT(size_code_);
+    DO_STAT(size_code_alignment_);
+    DO_STAT(size_mapping_table_);
+    DO_STAT(size_vmap_table_);
+    DO_STAT(size_gc_map_);
+    DO_STAT(size_oat_dex_file_location_size_);
+    DO_STAT(size_oat_dex_file_location_data_);
+    DO_STAT(size_oat_dex_file_location_checksum_);
+    DO_STAT(size_oat_dex_file_offset_);
+    DO_STAT(size_oat_dex_file_methods_offsets_);
+    DO_STAT(size_oat_class_status_);
+    DO_STAT(size_oat_class_method_offsets_);
+    #undef DO_STAT
+
+    LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
+    CHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
+  }
+
   return true;
 }
 
 bool OatWriter::WriteTables(OutputStream& out) {
   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
-    if (!oat_dex_files_[i]->Write(out)) {
+    if (!oat_dex_files_[i]->Write(this, out)) {
       PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
       return false;
     }
@@ -436,9 +524,10 @@
       PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation();
       return false;
     }
+    size_dex_file_ += dex_file->GetHeader().file_size_;
   }
   for (size_t i = 0; i != oat_classes_.size(); ++i) {
-    if (!oat_classes_[i]->Write(out)) {
+    if (!oat_classes_[i]->Write(this, out)) {
       PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
       return false;
     }
@@ -448,13 +537,59 @@
 
 size_t OatWriter::WriteCode(OutputStream& out) {
   uint32_t offset = oat_header_->GetExecutableOffset();
-  off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent);
+  off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
   if (static_cast<uint32_t>(new_offset) != offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
                 << " Expected: " << offset << " File: " << out.GetLocation();
     return 0;
   }
   DCHECK_OFFSET();
+  if (compiler_driver_->IsImage()) {
+    InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
+    if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size();
+    offset += interpreter_to_interpreter_entry_->size();
+    DCHECK_OFFSET();
+
+    uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    uint32_t alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) {
+      PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation();
+      return false;
+    }
+    size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size();
+    offset += alignment_padding + interpreter_to_quick_entry_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) {
+      PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation();
+      return false;
+    }
+    size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size();
+    offset += alignment_padding + portable_resolution_trampoline_->size();
+    DCHECK_OFFSET();
+
+    aligned_offset = CompiledCode::AlignCode(offset, instruction_set);
+    alignment_padding = aligned_offset - offset;
+    out.Seek(alignment_padding, kSeekCurrent);
+    size_stubs_alignment_ += alignment_padding;
+    if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) {
+      PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation();
+      return false;
+    }
+    size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size();
+    offset += alignment_padding + quick_resolution_trampoline_->size();
+    DCHECK_OFFSET();
+  }
   return offset;
 }
 
@@ -547,6 +682,7 @@
     uint32_t aligned_code_delta = aligned_offset - offset;
     if (aligned_code_delta != 0) {
       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
+      size_code_alignment_ += aligned_code_delta;
       if (static_cast<uint32_t>(new_offset) != aligned_offset) {
         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
                     << " Expected: " << aligned_offset << " File: " << out.GetLocation();
@@ -572,12 +708,14 @@
         ReportWriteFailure("method code size", method_idx, dex_file, out);
         return 0;
       }
+      size_code_size_ += sizeof(code_size);
       offset += sizeof(code_size);
       DCHECK_OFFSET();
       if (!out.WriteFully(&code[0], code_size)) {
         ReportWriteFailure("method code", method_idx, dex_file, out);
         return 0;
       }
+      size_code_ += code_size;
       offset += code_size;
     }
     DCHECK_OFFSET();
@@ -602,6 +740,7 @@
         ReportWriteFailure("mapping table", method_idx, dex_file, out);
         return 0;
       }
+      size_mapping_table_ += mapping_table_size;
       offset += mapping_table_size;
     }
     DCHECK_OFFSET();
@@ -625,6 +764,7 @@
         ReportWriteFailure("vmap table", method_idx, dex_file, out);
         return 0;
       }
+      size_vmap_table_ += vmap_table_size;
       offset += vmap_table_size;
     }
     DCHECK_OFFSET();
@@ -648,6 +788,7 @@
         ReportWriteFailure("GC map", method_idx, dex_file, out);
         return 0;
       }
+      size_gc_map_ += gc_map_size;
       offset += gc_map_size;
     }
     DCHECK_OFFSET();
@@ -683,29 +824,35 @@
                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
 }
 
-bool OatWriter::OatDexFile::Write(OutputStream& out) const {
+bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const {
   DCHECK_OFFSET_();
   if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
     PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
   if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
     PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
   if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
     PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
   if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
     PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
   if (!out.WriteFully(&methods_offsets_[0],
                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
     PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_dex_file_methods_offsets_ +=
+      sizeof(methods_offsets_[0]) * methods_offsets_.size();
   return true;
 }
 
@@ -736,12 +883,13 @@
                             sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
-bool OatWriter::OatClass::Write(OutputStream& out) const {
+bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const {
   DCHECK_OFFSET_();
   if (!out.WriteFully(&status_, sizeof(status_))) {
     PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_class_status_ += sizeof(status_);
   DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)),
             out.Seek(0, kSeekCurrent));
   if (!out.WriteFully(&method_offsets_[0],
@@ -749,6 +897,7 @@
     PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
     return false;
   }
+  oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
   DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
             out.Seek(0, kSeekCurrent));
   return true;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index e1d76f4..b201d6b 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -83,7 +83,8 @@
   size_t InitOatDexFiles(size_t offset);
   size_t InitDexFiles(size_t offset);
   size_t InitOatClasses(size_t offset);
-  size_t InitOatCode(size_t offset);
+  size_t InitOatCode(size_t offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   size_t InitOatCodeDexFiles(size_t offset)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   size_t InitOatCodeDexFile(size_t offset,
@@ -120,7 +121,7 @@
     explicit OatDexFile(size_t offset, const DexFile& dex_file);
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OutputStream& out) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out) const;
 
     // Offset of start of OatDexFile from beginning of OatHeader. It is
     // used to validate file position when writing.
@@ -144,7 +145,7 @@
     size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const;
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
-    bool Write(OutputStream& out) const;
+    bool Write(OatWriter* oat_writer, OutputStream& out) const;
 
     // Offset of start of OatClass from beginning of OatHeader. It is
     // used to validate file position when writing. For Portable, it
@@ -175,7 +176,35 @@
   OatHeader* oat_header_;
   std::vector<OatDexFile*> oat_dex_files_;
   std::vector<OatClass*> oat_classes_;
-  uint32_t executable_offset_padding_length_;
+  UniquePtr<const std::vector<uint8_t> > interpreter_to_interpreter_entry_;
+  UniquePtr<const std::vector<uint8_t> > interpreter_to_quick_entry_;
+  UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_;
+  UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_;
+
+  // output stats
+  uint32_t size_dex_file_alignment_;
+  uint32_t size_executable_offset_alignment_;
+  uint32_t size_oat_header_;
+  uint32_t size_oat_header_image_file_location_;
+  uint32_t size_dex_file_;
+  uint32_t size_interpreter_to_interpreter_entry_;
+  uint32_t size_interpreter_to_quick_entry_;
+  uint32_t size_portable_resolution_trampoline_;
+  uint32_t size_quick_resolution_trampoline_;
+  uint32_t size_stubs_alignment_;
+  uint32_t size_code_size_;
+  uint32_t size_code_;
+  uint32_t size_code_alignment_;
+  uint32_t size_mapping_table_;
+  uint32_t size_vmap_table_;
+  uint32_t size_gc_map_;
+  uint32_t size_oat_dex_file_location_size_;
+  uint32_t size_oat_dex_file_location_data_;
+  uint32_t size_oat_dex_file_location_checksum_;
+  uint32_t size_oat_dex_file_offset_;
+  uint32_t size_oat_dex_file_methods_offsets_;
+  uint32_t size_oat_class_status_;
+  uint32_t size_oat_class_method_offsets_;
 
   template <class T> struct MapCompare {
    public:
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 7a99f8d..f9caa9d 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -30,8 +30,9 @@
 #include "dex_instruction.h"
 #include "disassembler.h"
 #include "gc_map.h"
-#include "gc/large_object_space.h"
-#include "gc/space.h"
+#include "gc/space/image_space.h"
+#include "gc/space/large_object_space.h"
+#include "gc/space/space-inl.h"
 #include "image.h"
 #include "indenter.h"
 #include "mirror/abstract_method-inl.h"
@@ -679,7 +680,7 @@
 class ImageDumper {
  public:
   explicit ImageDumper(std::ostream* os, const std::string& image_filename,
-                       const std::string& host_prefix, Space& image_space,
+                       const std::string& host_prefix, gc::space::ImageSpace& image_space,
                        const ImageHeader& image_header)
       : os_(os), image_filename_(image_filename), host_prefix_(host_prefix),
         image_space_(image_space), image_header_(image_header) {}
@@ -763,8 +764,8 @@
     os << "OBJECTS:\n" << std::flush;
 
     // Loop through all the image spaces and dump their objects.
-    Heap* heap = Runtime::Current()->GetHeap();
-    const Spaces& spaces = heap->GetSpaces();
+    gc::Heap* heap = Runtime::Current()->GetHeap();
+    const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
     Thread* self = Thread::Current();
     {
       WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
@@ -777,10 +778,11 @@
       os_ = &indent_os;
       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
       // TODO: C++0x auto
-      for (Spaces::const_iterator it = spaces.begin(); it != spaces.end(); ++it) {
-        Space* space = *it;
+      typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
+      for (It it = spaces.begin(), end = spaces.end(); it != end; ++it) {
+        gc::space::Space* space = *it;
         if (space->IsImageSpace()) {
-          ImageSpace* image_space = space->AsImageSpace();
+          gc::space::ImageSpace* image_space = space->AsImageSpace();
           image_space->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
           indent_os << "\n";
         }
@@ -853,7 +855,13 @@
       if (value == NULL) {
         os << StringPrintf("null   %s\n", PrettyDescriptor(descriptor).c_str());
       } else {
-        PrettyObjectValue(os, fh.GetType(), value);
+        // Grab the field type without causing resolution.
+        mirror::Class* field_type = fh.GetType(false);
+        if (field_type != NULL) {
+          PrettyObjectValue(os, field_type, value);
+        } else {
+          os << StringPrintf("%p   %s\n", value, PrettyDescriptor(descriptor).c_str());
+        }
       }
     }
   }
@@ -880,7 +888,7 @@
   const void* GetOatCodeBegin(mirror::AbstractMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const void* code = m->GetEntryPointFromCompiledCode();
-    if (code == GetResolutionTrampoline()) {
+    if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
       code = oat_dumper_->GetOatCode(m);
     }
     if (oat_dumper_->GetInstructionSet() == kThumb2) {
@@ -1337,7 +1345,7 @@
   std::ostream* os_;
   const std::string image_filename_;
   const std::string host_prefix_;
-  Space& image_space_;
+  gc::space::ImageSpace& image_space_;
   const ImageHeader& image_header_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
@@ -1448,8 +1456,8 @@
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   ScopedObjectAccess soa(Thread::Current());
 
-  Heap* heap = Runtime::Current()->GetHeap();
-  ImageSpace* image_space = heap->GetImageSpace();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
+  gc::space::ImageSpace* image_space = heap->GetImageSpace();
   CHECK(image_space != NULL);
   const ImageHeader& image_header = image_space->GetImageHeader();
   if (!image_header.IsValid()) {
diff --git a/src/object_utils.h b/src/object_utils.h
index 6c6f60b..6a07425 100644
--- a/src/object_utils.h
+++ b/src/object_utils.h
@@ -282,13 +282,13 @@
       return field_index == 0 ? "interfaces" : "throws";
     }
   }
-  mirror::Class* GetType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     uint32_t field_index = field_->GetDexFieldIndex();
     if (!field_->GetDeclaringClass()->IsProxyClass()) {
       const DexFile& dex_file = GetDexFile();
       const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index);
       mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_);
-      if (type == NULL) {
+      if (resolve && (type == NULL)) {
         type = GetClassLinker()->ResolveType(field_id.type_idx_, field_);
         CHECK(type != NULL || Thread::Current()->IsExceptionPending());
       }
diff --git a/src/output_stream_test.cc b/src/output_stream_test.cc
index 0e02825..c9e0ede 100644
--- a/src/output_stream_test.cc
+++ b/src/output_stream_test.cc
@@ -25,7 +25,7 @@
  protected:
   void CheckOffset(off_t expected) {
     off_t actual = output_stream_->Seek(0, kSeekCurrent);
-    CHECK_EQ(expected, actual);
+    EXPECT_EQ(expected, actual);
   }
 
   void SetOutputStream(OutputStream& output_stream) {
@@ -33,16 +33,16 @@
   }
 
   void GenerateTestOutput() {
-    CHECK_EQ(3, output_stream_->Seek(3, kSeekCurrent));
+    EXPECT_EQ(3, output_stream_->Seek(3, kSeekCurrent));
     CheckOffset(3);
-    CHECK_EQ(2, output_stream_->Seek(2, kSeekSet));
+    EXPECT_EQ(2, output_stream_->Seek(2, kSeekSet));
     CheckOffset(2);
     uint8_t buf[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-    CHECK(output_stream_->WriteFully(buf, 2));
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 2));
     CheckOffset(4);
-    CHECK_EQ(6, output_stream_->Seek(2, kSeekEnd));
+    EXPECT_EQ(6, output_stream_->Seek(2, kSeekEnd));
     CheckOffset(6);
-    CHECK(output_stream_->WriteFully(buf, 4));
+    EXPECT_TRUE(output_stream_->WriteFully(buf, 4));
     CheckOffset(10);
   }
 
@@ -50,8 +50,8 @@
     uint8_t expected[] = {
         0, 0, 1, 2, 0, 0, 1, 2, 3, 4
     };
-    CHECK_EQ(sizeof(expected), actual.size());
-    CHECK_EQ(0, memcmp(expected, &actual[0], actual.size()));
+    EXPECT_EQ(sizeof(expected), actual.size());
+    EXPECT_EQ(0, memcmp(expected, &actual[0], actual.size()));
   }
 
   OutputStream* output_stream_;
@@ -63,10 +63,10 @@
   SetOutputStream(output_stream);
   GenerateTestOutput();
   UniquePtr<File> in(OS::OpenFile(tmp.GetFilename().c_str(), false));
-  CHECK(in.get() != NULL);
+  EXPECT_TRUE(in.get() != NULL);
   std::vector<uint8_t> actual(in->GetLength());
   bool readSuccess = in->ReadFully(&actual[0], actual.size());
-  CHECK(readSuccess);
+  EXPECT_TRUE(readSuccess);
   CheckTestOutput(actual);
 }
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 186f208..1889d88 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -34,8 +34,9 @@
 #include "constants_mips.h"
 #include "constants_x86.h"
 #include "debugger.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
 #include "image.h"
 #include "instrumentation.h"
 #include "intern_table.h"
@@ -55,7 +56,6 @@
 #include "signal_catcher.h"
 #include "signal_set.h"
 #include "sirt_ref.h"
-#include "gc/space.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "trace.h"
@@ -210,29 +210,18 @@
     LOG(INTERNAL_FATAL) << "Unexpectedly returned from abort hook!";
   }
 
-#if defined(__BIONIC__)
-  // TODO: finish merging patches to fix abort(3) in bionic, then lose this!
-  // Bionic doesn't implement POSIX semantics for abort(3) in a multi-threaded
-  // process, so if we call abort(3) on a device, all threads in the process
-  // receive SIGABRT.  debuggerd dumps the stack trace of the main
-  // thread, whether or not that was the thread that failed.  By
-  // stuffing a value into a bogus address, we cause a segmentation
-  // fault in the current thread, and get a useful log from debuggerd.
-  // We can also trivially tell the difference between a crash and
-  // a deliberate abort by looking at the fault address.
-  *reinterpret_cast<char*>(0xdeadd00d) = 38;
-#elif defined(__APPLE__)
-  // TODO: check that this actually gives good stack traces on the Mac!
-  pthread_kill(pthread_self(), SIGABRT);
-#else
+#if defined(__GLIBC__)
   // TODO: we ought to be able to use pthread_kill(3) here (or abort(3),
   // which POSIX defines in terms of raise(3), which POSIX defines in terms
   // of pthread_kill(3)). On Linux, though, libcorkscrew can't unwind through
   // libpthread, which means the stacks we dump would be useless. Calling
   // tgkill(2) directly avoids that.
   syscall(__NR_tgkill, getpid(), GetTid(), SIGABRT);
-  // TODO: LLVM installs it's own SIGABRT handler so exit to be safe... Can we disable that?
+  // TODO: LLVM installs it's own SIGABRT handler so exit to be safe... Can we disable that in LLVM?
+  // If not, we could use sigaction(3) before calling tgkill(2) and lose this call to exit(3).
   exit(1);
+#else
+  abort();
 #endif
   // notreached
 }
@@ -343,11 +332,11 @@
   // -Xcheck:jni is off by default for regular builds but on by default in debug builds.
   parsed->check_jni_ = kIsDebugBuild;
 
-  parsed->heap_initial_size_ = Heap::kDefaultInitialSize;
-  parsed->heap_maximum_size_ = Heap::kDefaultMaximumSize;
-  parsed->heap_min_free_ = Heap::kDefaultMinFree;
-  parsed->heap_max_free_ = Heap::kDefaultMaxFree;
-  parsed->heap_target_utilization_ = Heap::kDefaultTargetUtilization;
+  parsed->heap_initial_size_ = gc::Heap::kDefaultInitialSize;
+  parsed->heap_maximum_size_ = gc::Heap::kDefaultMaximumSize;
+  parsed->heap_min_free_ = gc::Heap::kDefaultMinFree;
+  parsed->heap_max_free_ = gc::Heap::kDefaultMaxFree;
+  parsed->heap_target_utilization_ = gc::Heap::kDefaultTargetUtilization;
   parsed->heap_growth_limit_ = 0;  // 0 means no growth limit.
   parsed->stack_size_ = 0; // 0 means default.
 
@@ -821,14 +810,14 @@
     GetInstrumentation()->ForceInterpretOnly();
   }
 
-  heap_ = new Heap(options->heap_initial_size_,
-                   options->heap_growth_limit_,
-                   options->heap_min_free_,
-                   options->heap_max_free_,
-                   options->heap_target_utilization_,
-                   options->heap_maximum_size_,
-                   options->image_,
-                   options->is_concurrent_gc_enabled_);
+  heap_ = new gc::Heap(options->heap_initial_size_,
+                       options->heap_growth_limit_,
+                       options->heap_min_free_,
+                       options->heap_max_free_,
+                       options->heap_target_utilization_,
+                       options->heap_maximum_size_,
+                       options->image_,
+                       options->is_concurrent_gc_enabled_);
 
   BlockSignals();
   InitPlatformSignalHandlers();
@@ -850,8 +839,8 @@
   // Now we're attached, we can take the heap lock and validate the heap.
   GetHeap()->EnableObjectValidation();
 
-  CHECK_GE(GetHeap()->GetSpaces().size(), 1U);
-  if (GetHeap()->GetSpaces()[0]->IsImageSpace()) {
+  CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
+  if (GetHeap()->GetContinuousSpaces()[0]->IsImageSpace()) {
     class_linker_ = ClassLinker::CreateFromImage(intern_table_);
   } else {
     CHECK(options->boot_class_path_ != NULL);
@@ -1063,12 +1052,13 @@
   thread_list_->Unregister(self);
 }
 
-void Runtime::VisitConcurrentRoots(RootVisitor* visitor, void* arg) {
-  if (intern_table_->IsDirty()) {
-    intern_table_->VisitRoots(visitor, arg);
+void Runtime::VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty,
+                                   bool clean_dirty) {
+  if (!only_dirty || intern_table_->IsDirty()) {
+    intern_table_->VisitRoots(visitor, arg, clean_dirty);
   }
-  if (class_linker_->IsDirty()) {
-    class_linker_->VisitRoots(visitor, arg);
+  if (!only_dirty || class_linker_->IsDirty()) {
+    class_linker_->VisitRoots(visitor, arg, clean_dirty);
   }
 }
 
@@ -1088,15 +1078,8 @@
   VisitNonThreadRoots(visitor, arg);
 }
 
-void Runtime::DirtyRoots() {
-  CHECK(intern_table_ != NULL);
-  intern_table_->Dirty();
-  CHECK(class_linker_ != NULL);
-  class_linker_->Dirty();
-}
-
-void Runtime::VisitRoots(RootVisitor* visitor, void* arg) {
-  VisitConcurrentRoots(visitor, arg);
+void Runtime::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty) {
+  VisitConcurrentRoots(visitor, arg, only_dirty, clean_dirty);
   VisitNonConcurrentRoots(visitor, arg);
 }
 
@@ -1109,7 +1092,9 @@
   // TODO: use a special method for resolution method saves
   method->SetDexMethodIndex(DexFile::kDexNoIndex16);
   // When compiling, the code pointer will get set later when the image is loaded.
-  method->SetEntryPointFromCompiledCode(Runtime::Current()->IsCompiler() ? NULL : GetResolutionTrampoline());
+  Runtime* r = Runtime::Current();
+  ClassLinker* cl = r->GetClassLinker();
+  method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetResolutionTrampoline(cl));
   return method.get();
 }
 
diff --git a/src/runtime.h b/src/runtime.h
index 6f03fe0..dfcd647 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -27,8 +27,8 @@
 
 #include "base/macros.h"
 #include "base/stringpiece.h"
+#include "gc/heap.h"
 #include "globals.h"
-#include "heap.h"
 #include "instruction_set.h"
 #include "instrumentation.h"
 #include "jobject_comparator.h"
@@ -39,17 +39,19 @@
 
 namespace art {
 
+namespace gc {
+  class Heap;
+}
 namespace mirror {
-class AbstractMethod;
-class ClassLoader;
-template<class T> class PrimitiveArray;
-typedef PrimitiveArray<int8_t> ByteArray;
-class String;
-class Throwable;
+  class AbstractMethod;
+  class ClassLoader;
+  template<class T> class PrimitiveArray;
+  typedef PrimitiveArray<int8_t> ByteArray;
+  class String;
+  class Throwable;
 }  // namespace mirror
 class ClassLinker;
 class DexFile;
-class Heap;
 class InternTable;
 struct JavaVMExt;
 class MonitorList;
@@ -63,11 +65,13 @@
 
   // In small mode, apps with fewer than this number of methods will be compiled 
   // anyways.
+  // TODO: come up with a reasonable default.
   static const size_t kDefaultSmallModeMethodThreshold = 0;
 
   // In small mode, methods smaller than this dex op count limit will get compiled
   // anyways.
-  static const size_t kDefaultSmallModeMethodDexSizeLimit = 0;
+  // TODO: come up with a reasonable default.
+  static const size_t kDefaultSmallModeMethodDexSizeLimit = 300;
 
   class ParsedOptions {
    public:
@@ -222,7 +226,7 @@
     return default_stack_size_;
   }
 
-  Heap* GetHeap() const {
+  gc::Heap* GetHeap() const {
     return heap_;
   }
 
@@ -254,14 +258,13 @@
     return "2.0.0";
   }
 
-  // Force all the roots which can be marked concurrently to be dirty.
-  void DirtyRoots();
-
-  // Visit all the roots.
-  void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // Visit all the roots. If only_dirty is true then non-dirty roots won't be visited. If
+  // clean_dirty is true then dirty roots will be marked as non-dirty after visiting.
+  void VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Visit all of the roots we can do safely do concurrently.
-  void VisitConcurrentRoots(RootVisitor* visitor, void* arg);
+  void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty);
 
   // Visit all of the non thread roots, we can do this with mutators unpaused.
   void VisitNonThreadRoots(RootVisitor* visitor, void* arg);
@@ -390,7 +393,7 @@
   // The default stack size for managed threads created by the runtime.
   size_t default_stack_size_;
 
-  Heap* heap_;
+  gc::Heap* heap_;
 
   MonitorList* monitor_list_;
 
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 9242c87..c933621 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -18,7 +18,7 @@
 
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/field-inl.h"
@@ -142,7 +142,8 @@
 }
 
 mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
-                                 Thread* self, FindFieldType type, size_t expected_size) {
+                                 Thread* self, FindFieldType type, size_t expected_size,
+                                 bool access_check) {
   bool is_primitive;
   bool is_set;
   bool is_static;
@@ -162,12 +163,13 @@
   if (UNLIKELY(resolved_field == NULL)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return NULL;  // Failure.
-  } else {
+  }
+  mirror::Class* fields_class = resolved_field->GetDeclaringClass();
+  if (access_check) {
     if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
       ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
       return NULL;
     }
-    mirror::Class* fields_class = resolved_field->GetDeclaringClass();
     mirror::Class* referring_class = referrer->GetDeclaringClass();
     if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
                  !referring_class->CanAccessMember(fields_class,
@@ -203,23 +205,24 @@
                                  is_primitive ? "primitive" : "non-primitive",
                                  PrettyField(resolved_field, true).c_str());
         return NULL;  // failure
-      } else if (!is_static) {
-        // instance fields must be being accessed on an initialized class
-        return resolved_field;
-      } else {
-        // If the class is initialized we're done.
-        if (fields_class->IsInitialized()) {
-          return resolved_field;
-        } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
-          // Otherwise let's ensure the class is initialized before resolving the field.
-          return resolved_field;
-        } else {
-          DCHECK(self->IsExceptionPending());  // Throw exception and unwind
-          return NULL;  // failure
-        }
       }
     }
   }
+  if (!is_static) {
+    // instance fields must be being accessed on an initialized class
+    return resolved_field;
+  } else {
+    // If the class is initialized we're done.
+    if (fields_class->IsInitialized()) {
+      return resolved_field;
+    } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
+      // Otherwise let's ensure the class is initialized before resolving the field.
+      return resolved_field;
+    } else {
+      DCHECK(self->IsExceptionPending());  // Throw exception and unwind
+      return NULL;  // failure
+    }
+  }
 }
 
 // Slow path method resolution
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 5fc8da5..0cb82a5 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -34,14 +34,12 @@
 extern "C" void art_jni_dlsym_lookup_stub();
 extern "C" void art_portable_abstract_method_error_stub();
 extern "C" void art_portable_proxy_invoke_handler();
-extern "C" void art_portable_resolution_trampoline();
 extern "C" void art_quick_abstract_method_error_stub();
 extern "C" void art_quick_deoptimize();
 extern "C" void art_quick_instrumentation_entry_from_code(void*);
 extern "C" void art_quick_instrumentation_exit_from_code();
 extern "C" void art_quick_interpreter_entry(void*);
 extern "C" void art_quick_proxy_invoke_handler();
-extern "C" void art_quick_resolution_trampoline();
 extern "C" void art_work_around_app_jni_bugs();
 
 extern "C" double art_l2d(int64_t l);
@@ -146,7 +144,8 @@
 
 // Slow field find that can initialize classes and may throw exceptions.
 extern mirror::Field* FindFieldFromCode(uint32_t field_idx, const mirror::AbstractMethod* referrer,
-                                        Thread* self, FindFieldType type, size_t expected_size)
+                                        Thread* self, FindFieldType type, size_t expected_size,
+                                        bool access_check)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 // Fast path field resolution that can't initialize classes or throw exceptions.
@@ -373,22 +372,20 @@
   return reinterpret_cast<void*>(art_quick_interpreter_entry);
 }
 
-// Return address of portable resolution trampoline stub.
-static inline void* GetPortableResolutionTrampoline() {
-  return reinterpret_cast<void*>(art_portable_resolution_trampoline);
+static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) {
+  return class_linker->GetPortableResolutionTrampoline();
 }
 
-// Return address of quick resolution trampoline stub.
-static inline void* GetQuickResolutionTrampoline() {
-  return reinterpret_cast<void*>(art_quick_resolution_trampoline);
+static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) {
+  return class_linker->GetQuickResolutionTrampoline();
 }
 
 // Return address of resolution trampoline stub for defined compiler.
-static inline void* GetResolutionTrampoline() {
+static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) {
 #if defined(ART_USE_PORTABLE_COMPILER)
-  return GetPortableResolutionTrampoline();
+  return GetPortableResolutionTrampoline(class_linker);
 #else
-  return GetQuickResolutionTrampoline();
+  return GetQuickResolutionTrampoline(class_linker);
 #endif
 }
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index c021dd1..a630db8 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -27,7 +27,7 @@
 
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
-#include "heap.h"
+#include "gc/heap.h"
 #include "os.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
diff --git a/src/stack.cc b/src/stack.cc
index 8690a36..8672975 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -42,6 +42,15 @@
   }
 }
 
+mirror::Object* ShadowFrame::GetThisObject(uint16_t num_ins) const {
+  mirror::AbstractMethod* m = GetMethod();
+  if (m->IsStatic()) {
+    return NULL;
+  } else {
+    return GetVRegReference(NumberOfVRegs() - num_ins);
+  }
+}
+
 ThrowLocation ShadowFrame::GetCurrentLocationForThrow() const {
   return ThrowLocation(GetThisObject(), GetMethod(), GetDexPC());
 }
diff --git a/src/stack.h b/src/stack.h
index 1b4d285..fbfacb1 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -202,6 +202,8 @@
 
   mirror::Object* GetThisObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  mirror::Object* GetThisObject(uint16_t num_ins) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   ThrowLocation GetCurrentLocationForThrow() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetMethod(mirror::AbstractMethod* method) {
@@ -254,13 +256,9 @@
       CHECK_LT(num_vregs, static_cast<uint32_t>(kHasReferenceArray));
       number_of_vregs_ |= kHasReferenceArray;
 #endif
-      for (size_t i = 0; i < num_vregs; ++i) {
-        SetVRegReference(i, NULL);
-      }
+      memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(mirror::Object*)));
     } else {
-      for (size_t i = 0; i < num_vregs; ++i) {
-        SetVReg(i, 0);
-      }
+      memset(vregs_, 0, num_vregs * sizeof(uint32_t));
     }
   }
 
diff --git a/src/thread-inl.h b/src/thread-inl.h
index 6c1ae59..2fc5987 100644
--- a/src/thread-inl.h
+++ b/src/thread-inl.h
@@ -125,7 +125,7 @@
 }
 
 inline void Thread::VerifyStack() {
-  Heap* heap = Runtime::Current()->GetHeap();
+  gc::Heap* heap = Runtime::Current()->GetHeap();
   if (heap->IsObjectValidationEnabled()) {
     VerifyStackImpl();
   }
diff --git a/src/thread.cc b/src/thread.cc
index c5bfb20..2deb7a5 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -35,8 +35,9 @@
 #include "debugger.h"
 #include "dex_file-inl.h"
 #include "gc_map.h"
-#include "gc/card_table-inl.h"
-#include "heap.h"
+#include "gc/accounting/card_table-inl.h"
+#include "gc/heap.h"
+#include "gc/space/space.h"
 #include "invoke_arg_array_builder.h"
 #include "jni_internal.h"
 #include "mirror/abstract_method-inl.h"
@@ -53,8 +54,8 @@
 #include "runtime_support.h"
 #include "scoped_thread_state_change.h"
 #include "ScopedLocalRef.h"
+#include "ScopedUtfChars.h"
 #include "sirt_ref.h"
-#include "gc/space.h"
 #include "stack.h"
 #include "stack_indirect_reference_table.h"
 #include "thread-inl.h"
@@ -169,7 +170,7 @@
 
 Thread* Thread::FromManagedThread(const ScopedObjectAccessUnchecked& soa,
                                   mirror::Object* thread_peer) {
-  mirror::Field* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_vmData);
+  mirror::Field* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer);
   Thread* result = reinterpret_cast<Thread*>(static_cast<uintptr_t>(f->GetInt(thread_peer)));
   // Sanity check that if we have a result it is either suspended or we hold the thread_list_lock_
   // to stop it from going away.
@@ -275,9 +276,9 @@
   child_thread->jpeer_ = env->NewGlobalRef(java_peer);
   stack_size = FixStackSize(stack_size);
 
-  // Thread.start is synchronized, so we know that vmData is 0, and know that we're not racing to
+  // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing to
   // assign it.
-  env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_vmData,
+  env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer,
                    reinterpret_cast<jint>(child_thread));
 
   pthread_t new_pthread;
@@ -300,7 +301,7 @@
     delete child_thread;
     child_thread = NULL;
     // TODO: remove from thread group?
-    env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_vmData, 0);
+    env->SetIntField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0);
     {
       std::string msg(StringPrintf("pthread_create (%s stack) failed: %s",
                                    PrettySize(stack_size).c_str(), strerror(pthread_create_result)));
@@ -405,7 +406,7 @@
 
   Thread* self = this;
   DCHECK_EQ(self, Thread::Current());
-  jni_env_->SetIntField(peer.get(), WellKnownClasses::java_lang_Thread_vmData,
+  jni_env_->SetIntField(peer.get(), WellKnownClasses::java_lang_Thread_nativePeer,
                         reinterpret_cast<jint>(self));
 
   ScopedObjectAccess soa(self);
@@ -605,10 +606,22 @@
     Thread* thread;
     {
       ScopedObjectAccess soa(Thread::Current());
-      MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+      Thread* self = soa.Self();
+      MutexLock mu(self, *Locks::thread_list_lock_);
       thread = Thread::FromManagedThread(soa, peer);
       if (thread == NULL) {
-        LOG(WARNING) << "No such thread for suspend: " << peer;
+        JNIEnv* env = self->GetJniEnv();
+        ScopedLocalRef<jstring> scoped_name_string(env,
+                                                   (jstring)env->GetObjectField(peer,
+                                                              WellKnownClasses::java_lang_Thread_name));
+        ScopedUtfChars scoped_name_chars(env,scoped_name_string.get());
+        if (scoped_name_chars.c_str() == NULL) {
+            LOG(WARNING) << "No such thread for suspend: " << peer;
+            env->ExceptionClear();
+        } else {
+            LOG(WARNING) << "No such thread for suspend: " << peer << ":" << scoped_name_chars.c_str();
+        }
+
         return NULL;
       }
       {
@@ -865,9 +878,10 @@
   // TODO: we call this code when dying but may not have suspended the thread ourself. The
   //       IsSuspended check is therefore racy with the use for dumping (normally we inhibit
   //       the race with the thread_suspend_count_lock_).
-  if (this == Thread::Current() || IsSuspended()) {
+  bool dump_for_abort = (gAborting > 0);
+  if (this == Thread::Current() || IsSuspended() || dump_for_abort) {
     // If we're currently in native code, dump that stack before dumping the managed stack.
-    if (ShouldShowNativeStack(this)) {
+    if (dump_for_abort || ShouldShowNativeStack(this)) {
       DumpKernelStack(os, GetTid(), "  kernel: ", false);
       DumpNativeStack(os, GetTid(), "  native: ", false);
     }
@@ -1013,8 +1027,8 @@
     HandleUncaughtExceptions(soa);
     RemoveFromThreadGroup(soa);
 
-    // this.vmData = 0;
-    soa.DecodeField(WellKnownClasses::java_lang_Thread_vmData)->SetInt(opeer_, 0);
+    // this.nativePeer = 0;
+    soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetInt(opeer_, 0);
     Dbg::PostThreadDeath(self);
 
     // Thread.join() is implemented as an Object.wait() on the Thread.lock object. Signal anyone
@@ -1643,10 +1657,14 @@
   ENTRY_POINT_INFO(pShlLong),
   ENTRY_POINT_INFO(pShrLong),
   ENTRY_POINT_INFO(pUshrLong),
+  ENTRY_POINT_INFO(pInterpreterToInterpreterEntry),
+  ENTRY_POINT_INFO(pInterpreterToQuickEntry),
   ENTRY_POINT_INFO(pIndexOf),
   ENTRY_POINT_INFO(pMemcmp16),
   ENTRY_POINT_INFO(pStringCompareTo),
   ENTRY_POINT_INFO(pMemcpy),
+  ENTRY_POINT_INFO(pPortableResolutionTrampolineFromCode),
+  ENTRY_POINT_INFO(pQuickResolutionTrampolineFromCode),
   ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck),
   ENTRY_POINT_INFO(pInvokeInterfaceTrampoline),
   ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck),
@@ -2180,7 +2198,7 @@
 }
 
 static void VerifyObject(const mirror::Object* root, void* arg) {
-  Heap* heap = reinterpret_cast<Heap*>(arg);
+  gc::Heap* heap = reinterpret_cast<gc::Heap*>(arg);
   heap->VerifyObject(root);
 }
 
diff --git a/src/thread_list.cc b/src/thread_list.cc
index ebb63dd..eacd848 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -466,10 +466,8 @@
     all_threads_are_daemons = true;
     MutexLock mu(self, *Locks::thread_list_lock_);
     for (It it = list_.begin(), end = list_.end(); it != end; ++it) {
-      // TODO: there's a race here with thread exit that's being worked around by checking if the
-      // thread has a peer.
       Thread* thread = *it;
-      if (thread != self && thread->HasPeer() && !thread->IsDaemon()) {
+      if (thread != self && !thread->IsDaemon()) {
         all_threads_are_daemons = false;
         break;
       }
diff --git a/src/thread_pool.cc b/src/thread_pool.cc
index 370e4bc..f0f6f18 100644
--- a/src/thread_pool.cc
+++ b/src/thread_pool.cc
@@ -154,17 +154,22 @@
   return NULL;
 }
 
-void ThreadPool::Wait(Thread* self, bool do_work) {
-  Task* task = NULL;
-  while ((task = TryGetTask(self)) != NULL) {
-    task->Run(self);
-    task->Finalize();
+void ThreadPool::Wait(Thread* self, bool do_work, bool may_hold_locks) {
+  if (do_work) {
+    Task* task = NULL;
+    while ((task = TryGetTask(self)) != NULL) {
+      task->Run(self);
+      task->Finalize();
+    }
   }
-
   // Wait until each thread is waiting and the task list is empty.
   MutexLock mu(self, task_queue_lock_);
   while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) {
-    completion_condition_.Wait(self);
+    if (!may_hold_locks) {
+      completion_condition_.Wait(self);
+    } else {
+      completion_condition_.WaitHoldingLocks(self);
+    }
   }
 }
 
diff --git a/src/thread_pool.h b/src/thread_pool.h
index 18af97d..814e654 100644
--- a/src/thread_pool.h
+++ b/src/thread_pool.h
@@ -80,7 +80,7 @@
   virtual ~ThreadPool();
 
   // Wait for all tasks currently on queue to get completed.
-  void Wait(Thread* self, bool do_work = true);
+  void Wait(Thread* self, bool do_work, bool may_hold_locks);
 
   size_t GetTaskCount(Thread* self);
 
diff --git a/src/thread_pool_test.cc b/src/thread_pool_test.cc
index e056935..e2a32f5 100644
--- a/src/thread_pool_test.cc
+++ b/src/thread_pool_test.cc
@@ -68,7 +68,7 @@
   }
   thread_pool.StartWorkers(self);
   // Wait for tasks to complete.
-  thread_pool.Wait(self);
+  thread_pool.Wait(self, true, false);
   // Make sure that we finished all the work.
   EXPECT_EQ(num_tasks, count);
 }
@@ -137,7 +137,7 @@
   static const int depth = 8;
   thread_pool.AddTask(self, new TreeTask(&thread_pool, &count, depth));
   thread_pool.StartWorkers(self);
-  thread_pool.Wait(self);
+  thread_pool.Wait(self, true, false);
   EXPECT_EQ((1 << depth) - 1, count);
 }
 
diff --git a/src/thread_state.h b/src/thread_state.h
index 7c4a16f..52f092e 100644
--- a/src/thread_state.h
+++ b/src/thread_state.h
@@ -28,6 +28,7 @@
   kBlocked,                        // BLOCKED        TS_MONITOR   blocked on a monitor
   kWaiting,                        // WAITING        TS_WAIT      in Object.wait()
   kWaitingForGcToComplete,         // WAITING        TS_WAIT      blocked waiting for GC
+  kWaitingForCheckPointsToRun,     // WAITING        TS_WAIT      GC waiting for checkpoints to run
   kWaitingPerformingGc,            // WAITING        TS_WAIT      performing GC
   kWaitingForDebuggerSend,         // WAITING        TS_WAIT      blocked waiting for events to be sent
   kWaitingForDebuggerToAttach,     // WAITING        TS_WAIT      blocked waiting for debugger to attach
diff --git a/src/utf.cc b/src/utf.cc
index 8d3547e..1add7d9 100644
--- a/src/utf.cc
+++ b/src/utf.cc
@@ -119,6 +119,23 @@
   }
 }
 
+int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2) {
+  for (;;) {
+    if (*utf8_1 == '\0') {
+      return (*utf8_2 == '\0') ? 0 : -1;
+    } else if (*utf8_2 == '\0') {
+      return 1;
+    }
+
+    int c1 = GetUtf16FromUtf8(&utf8_1);
+    int c2 = *utf8_2;
+
+    if (c1 != c2) {
+      return c1 > c2 ? 1 : -1;
+    }
+  }
+}
+
 size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
   size_t result = 0;
   while (char_count--) {
diff --git a/src/utf.h b/src/utf.h
index 44899bf..57c811f 100644
--- a/src/utf.h
+++ b/src/utf.h
@@ -56,6 +56,12 @@
 int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1, const char* utf8_2);
 
 /*
+ * Compare a modified UTF-8 string with a UTF-16 string as code point values in a non-locale
+ * sensitive manner.
+ */
+int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8_1, const uint16_t* utf8_2);
+
+/*
  * Convert from UTF-16 to Modified UTF-8. Note that the output is _not_
  * NUL-terminated. You probably need to call CountUtf8Bytes before calling
  * this anyway, so if you want a NUL-terminated string, you know where to
diff --git a/src/vector_output_stream.cc b/src/vector_output_stream.cc
index 96154ee..e5ff729 100644
--- a/src/vector_output_stream.cc
+++ b/src/vector_output_stream.cc
@@ -16,8 +16,6 @@
 
 #include "vector_output_stream.h"
 
-#include <string.h>
-
 #include "base/logging.h"
 
 namespace art {
@@ -25,14 +23,6 @@
 VectorOutputStream::VectorOutputStream(const std::string& location, std::vector<uint8_t>& vector)
   : OutputStream(location), offset_(vector.size()), vector_(vector) {}
 
-bool VectorOutputStream::WriteFully(const void* buffer, int64_t byte_count) {
-  off_t new_offset = offset_ + byte_count;
-  EnsureCapacity(new_offset);
-  memcpy(&vector_[offset_], buffer, byte_count);
-  offset_ = new_offset;
-  return true;
-}
-
 off_t VectorOutputStream::Seek(off_t offset, Whence whence) {
   CHECK(whence == kSeekSet || whence == kSeekCurrent || whence == kSeekEnd) << whence;
   off_t new_offset = 0;
@@ -55,10 +45,4 @@
   return offset_;
 }
 
-void VectorOutputStream::EnsureCapacity(off_t new_offset) {
-  if (new_offset > static_cast<off_t>(vector_.size())) {
-    vector_.resize(new_offset);
-  }
-}
-
 }  // namespace art
diff --git a/src/vector_output_stream.h b/src/vector_output_stream.h
index a99128e..3546c8d 100644
--- a/src/vector_output_stream.h
+++ b/src/vector_output_stream.h
@@ -20,6 +20,7 @@
 #include "output_stream.h"
 
 #include <string>
+#include <string.h>
 #include <vector>
 
 namespace art {
@@ -30,12 +31,28 @@
 
   virtual ~VectorOutputStream() {}
 
-  virtual bool WriteFully(const void* buffer, int64_t byte_count);
+  bool WriteFully(const void* buffer, int64_t byte_count) {
+    if (static_cast<size_t>(offset_) == vector_.size()) {
+      const uint8_t* start = reinterpret_cast<const uint8_t*>(buffer);
+      vector_.insert(vector_.end(), &start[0], &start[byte_count]);
+      offset_ += byte_count;
+    } else {
+      off_t new_offset = offset_ + byte_count;
+      EnsureCapacity(new_offset);
+      memcpy(&vector_[offset_], buffer, byte_count);
+      offset_ = new_offset;
+    }
+    return true;
+  }
 
-  virtual off_t Seek(off_t offset, Whence whence);
+  off_t Seek(off_t offset, Whence whence);
 
  private:
-  void EnsureCapacity(off_t new_offset);
+  void EnsureCapacity(off_t new_offset) {
+    if (new_offset > static_cast<off_t>(vector_.size())) {
+      vector_.resize(new_offset);
+    }
+  }
 
   off_t offset_;
   std::vector<uint8_t>& vector_;
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 2eb0c20..021e984 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -19,24 +19,26 @@
 #include <iostream>
 
 #include "base/logging.h"
+#include "base/mutex-inl.h"
 #include "base/stringpiece.h"
 #include "class_linker.h"
 #include "compiler/driver/compiler_driver.h"
 #include "dex_file-inl.h"
-#include "dex_instruction.h"
+#include "dex_instruction-inl.h"
 #include "dex_instruction_visitor.h"
-#include "gc/card_table-inl.h"
+#include "gc/accounting/card_table-inl.h"
 #include "indenter.h"
 #include "intern_table.h"
 #include "leb128.h"
 #include "mirror/abstract_method-inl.h"
 #include "mirror/class.h"
 #include "mirror/class-inl.h"
-#include "mirror/dex_cache.h"
+#include "mirror/dex_cache-inl.h"
 #include "mirror/field-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
+#include "register_line-inl.h"
 #include "runtime.h"
 #include "verifier/dex_gc_map.h"
 
@@ -266,13 +268,14 @@
     : reg_types_(can_load_classes),
       work_insn_idx_(-1),
       dex_method_idx_(dex_method_idx),
-      foo_method_(method),
+      mirror_method_(method),
       method_access_flags_(method_access_flags),
       dex_file_(dex_file),
       dex_cache_(dex_cache),
       class_loader_(class_loader),
       class_def_idx_(class_def_idx),
       code_item_(code_item),
+      declaring_class_(NULL),
       interesting_dex_pc_(-1),
       monitor_enter_dex_pcs_(NULL),
       have_pending_hard_failure_(false),
@@ -895,6 +898,7 @@
 
 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);
   length_prefixed_gc_map->push_back((gc_map.size() & 0x00ff0000) >> 16);
   length_prefixed_gc_map->push_back((gc_map.size() & 0x0000ff00) >> 8);
@@ -949,15 +953,20 @@
     DCHECK_NE(failures_.size(), 0U);
     return false;  // Not a real failure, but a failure to encode
   }
-#ifndef NDEBUG
-  VerifyGcMap(*map);
-#endif
+  if (kIsDebugBuild) {
+    VerifyGcMap(*map);
+  }
   const std::vector<uint8_t>* dex_gc_map = CreateLengthPrefixedDexGcMap(*(map.get()));
   verifier::MethodVerifier::SetDexGcMap(ref, *dex_gc_map);
 
-  MethodVerifier::PcToConreteMethod* pc_to_conrete_method = GenerateDevirtMap();
-  if(pc_to_conrete_method != NULL ) {
-    SetDevirtMap(ref, pc_to_conrete_method);
+  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);
   }
   return true;
 }
@@ -1244,6 +1253,11 @@
     if (dead_start >= 0) {
       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_) ==
+    //     "boolean java.lang.String.equals(java.lang.Object)") {
+    //   LOG(INFO) << info_messages_.str();
+    // }
   }
   return true;
 }
@@ -1280,7 +1294,6 @@
    */
   const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
   const Instruction* inst = Instruction::At(insns);
-  DecodedInstruction dec_insn(inst);
   int opcode_flags = Instruction::FlagsOf(inst->Opcode());
 
   int32_t branch_target = 0;
@@ -1306,32 +1319,51 @@
 #endif
   }
 
-  switch (dec_insn.opcode) {
+
+  // We need to ensure the work line is consistent while performing validation. When we spot a
+  // peephole pattern we compute a new line for either the fallthrough instruction or the
+  // branch target.
+  UniquePtr<RegisterLine> branch_line;
+  UniquePtr<RegisterLine> fallthrough_line;
+
+  switch (inst->Opcode()) {
     case Instruction::NOP:
       /*
        * A "pure" NOP has no effect on anything. Data tables start with
        * a signature that looks like a NOP; if we see one of these in
        * the course of executing code then we have a problem.
        */
-      if (dec_insn.vA != 0) {
+      if (inst->VRegA_10x() != 0) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "encountered data table in instruction stream";
       }
       break;
 
     case Instruction::MOVE:
+      work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategory1nr);
+      break;
     case Instruction::MOVE_FROM16:
+      work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategory1nr);
+      break;
     case Instruction::MOVE_16:
-      work_line_->CopyRegister1(dec_insn.vA, dec_insn.vB, kTypeCategory1nr);
+      work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategory1nr);
       break;
     case Instruction::MOVE_WIDE:
+      work_line_->CopyRegister2(inst->VRegA_12x(), inst->VRegB_12x());
+      break;
     case Instruction::MOVE_WIDE_FROM16:
+      work_line_->CopyRegister2(inst->VRegA_22x(), inst->VRegB_22x());
+      break;
     case Instruction::MOVE_WIDE_16:
-      work_line_->CopyRegister2(dec_insn.vA, dec_insn.vB);
+      work_line_->CopyRegister2(inst->VRegA_32x(), inst->VRegB_32x());
       break;
     case Instruction::MOVE_OBJECT:
+      work_line_->CopyRegister1(inst->VRegA_12x(), inst->VRegB_12x(), kTypeCategoryRef);
+      break;
     case Instruction::MOVE_OBJECT_FROM16:
+      work_line_->CopyRegister1(inst->VRegA_22x(), inst->VRegB_22x(), kTypeCategoryRef);
+      break;
     case Instruction::MOVE_OBJECT_16:
-      work_line_->CopyRegister1(dec_insn.vA, dec_insn.vB, kTypeCategoryRef);
+      work_line_->CopyRegister1(inst->VRegA_32x(), inst->VRegB_32x(), kTypeCategoryRef);
       break;
 
     /*
@@ -1346,13 +1378,13 @@
      * easier to read in some cases.)
      */
     case Instruction::MOVE_RESULT:
-      work_line_->CopyResultRegister1(dec_insn.vA, false);
+      work_line_->CopyResultRegister1(inst->VRegA_11x(), false);
       break;
     case Instruction::MOVE_RESULT_WIDE:
-      work_line_->CopyResultRegister2(dec_insn.vA);
+      work_line_->CopyResultRegister2(inst->VRegA_11x());
       break;
     case Instruction::MOVE_RESULT_OBJECT:
-      work_line_->CopyResultRegister1(dec_insn.vA, true);
+      work_line_->CopyResultRegister1(inst->VRegA_11x(), true);
       break;
 
     case Instruction::MOVE_EXCEPTION: {
@@ -1361,7 +1393,7 @@
        * that as part of extracting the exception type from the catch block list.
        */
       const RegType& res_type = GetCaughtExceptionType();
-      work_line_->SetRegisterType(dec_insn.vA, res_type);
+      work_line_->SetRegisterType(inst->VRegA_11x(), res_type);
       break;
     }
     case Instruction::RETURN_VOID:
@@ -1380,16 +1412,17 @@
         } 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.
-          const RegType& src_type = work_line_->GetRegisterType(dec_insn.vA);
+          const uint32_t vregA = inst->VRegA_11x();
+          const RegType& src_type = work_line_->GetRegisterType(vregA);
           bool use_src = ((return_type.IsBoolean() && src_type.IsByte()) ||
                           ((return_type.IsBoolean() || return_type.IsByte() ||
                            return_type.IsShort() || return_type.IsChar()) &&
                            src_type.IsInteger()));
           /* check the register contents */
           bool success =
-              work_line_->VerifyRegisterType(dec_insn.vA, use_src ? src_type : return_type);
+              work_line_->VerifyRegisterType(vregA, use_src ? src_type : return_type);
           if (!success) {
-            AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", dec_insn.vA));
+            AppendToLastFailMessage(StringPrintf(" return-1nr on invalid register v%d", vregA));
           }
         }
       }
@@ -1402,9 +1435,10 @@
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-wide not expected";
         } else {
           /* check the register contents */
-          bool success = work_line_->VerifyRegisterType(dec_insn.vA, return_type);
+          const uint32_t vregA = inst->VRegA_11x();
+          bool success = work_line_->VerifyRegisterType(vregA, return_type);
           if (!success) {
-            AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", dec_insn.vA));
+            AppendToLastFailMessage(StringPrintf(" return-wide on invalid register v%d", vregA));
           }
         }
       }
@@ -1418,7 +1452,8 @@
           /* return_type is the *expected* return type, not register value */
           DCHECK(!return_type.IsZero());
           DCHECK(!return_type.IsUninitializedReference());
-          const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+          const uint32_t vregA = inst->VRegA_11x();
+          const RegType& reg_type = work_line_->GetRegisterType(vregA);
           // Disallow returning uninitialized values and verify that the reference in vAA is an
           // instance of the "return_type"
           if (reg_type.IsUninitializedTypes()) {
@@ -1432,66 +1467,71 @@
       break;
 
       /* could be boolean, int, float, or a null reference */
-    case Instruction::CONST_4:
-      work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(static_cast<int32_t>(dec_insn.vB << 28) >> 28, true));
+    case Instruction::CONST_4: {
+      int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
+      work_line_->SetRegisterType(inst->VRegA_11n(), reg_types_.FromCat1Const(val, true));
       break;
-    case Instruction::CONST_16:
-      work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB), true));
+    }
+    case Instruction::CONST_16: {
+      int16_t val = static_cast<int16_t>(inst->VRegB_21s());
+      work_line_->SetRegisterType(inst->VRegA_21s(), reg_types_.FromCat1Const(val, true));
       break;
+    }
     case Instruction::CONST:
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB, true));
+      work_line_->SetRegisterType(inst->VRegA_31i(),
+                                  reg_types_.FromCat1Const(inst->VRegB_31i(), true));
       break;
     case Instruction::CONST_HIGH16:
-      work_line_->SetRegisterType(dec_insn.vA,
-                                  reg_types_.FromCat1Const(dec_insn.vB << 16, true));
+      work_line_->SetRegisterType(inst->VRegA_21h(),
+                                  reg_types_.FromCat1Const(inst->VRegB_21h() << 16, true));
       break;
       /* could be long or double; resolved upon use */
     case Instruction::CONST_WIDE_16: {
-      int64_t val = static_cast<int16_t>(dec_insn.vB);
+      int64_t val = static_cast<int16_t>(inst->VRegB_21s());
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_21s(), lo, hi);
       break;
     }
     case Instruction::CONST_WIDE_32: {
-      int64_t val = static_cast<int32_t>(dec_insn.vB);
+      int64_t val = static_cast<int32_t>(inst->VRegB_31i());
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_31i(), lo, hi);
       break;
     }
     case Instruction::CONST_WIDE: {
-      int64_t val = dec_insn.vB_wide;
+      int64_t val = inst->VRegB_51l();
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_51l(), lo, hi);
       break;
     }
     case Instruction::CONST_WIDE_HIGH16: {
-      int64_t val = static_cast<uint64_t>(dec_insn.vB) << 48;
+      int64_t val = static_cast<uint64_t>(inst->VRegB_21h()) << 48;
       const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
       const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
-      work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+      work_line_->SetRegisterTypeWide(inst->VRegA_21h(), lo, hi);
       break;
     }
     case Instruction::CONST_STRING:
+      work_line_->SetRegisterType(inst->VRegA_21c(), reg_types_.JavaLangString());
+      break;
     case Instruction::CONST_STRING_JUMBO:
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.JavaLangString());
+      work_line_->SetRegisterType(inst->VRegA_31c(), reg_types_.JavaLangString());
       break;
     case Instruction::CONST_CLASS: {
       // Get type from instruction if unresolved then we need an access check
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
-      const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
+      const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
       // Register holds class, ie its type is class, on error it will hold Conflict.
-      work_line_->SetRegisterType(dec_insn.vA,
+      work_line_->SetRegisterType(inst->VRegA_21c(),
                                   res_type.IsConflict() ? res_type
                                                         : reg_types_.JavaLangClass(true));
       break;
     }
     case Instruction::MONITOR_ENTER:
-      work_line_->PushMonitor(dec_insn.vA, work_insn_idx_);
+      work_line_->PushMonitor(inst->VRegA_11x(), work_insn_idx_);
       break;
     case Instruction::MONITOR_EXIT:
       /*
@@ -1515,7 +1555,7 @@
        * "live" so we still need to check it.
        */
       opcode_flags &= ~Instruction::kThrow;
-      work_line_->PopMonitor(dec_insn.vA);
+      work_line_->PopMonitor(inst->VRegA_11x());
       break;
 
     case Instruction::CHECK_CAST:
@@ -1527,45 +1567,53 @@
        * If it fails, an exception is thrown, which we deal with later by ignoring the update to
        * dec_insn.vA when branching to a handler.
        */
-      bool is_checkcast = dec_insn.opcode == Instruction::CHECK_CAST;
-      const RegType& res_type =
-          ResolveClassAndCheckAccess(is_checkcast ? dec_insn.vB : dec_insn.vC);
+      const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
+      const uint32_t type_idx = (is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c();
+      const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
       if (res_type.IsConflict()) {
         DCHECK_NE(failures_.size(), 0U);
         if (!is_checkcast) {
-          work_line_->SetRegisterType(dec_insn.vA, reg_types_.Boolean());
+          work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
         }
         break;  // bad class
       }
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
-      const RegType& orig_type =
-          work_line_->GetRegisterType(is_checkcast ? dec_insn.vA : dec_insn.vB);
+      uint32_t orig_type_reg = (is_checkcast) ? inst->VRegA_21c() : inst->VRegB_22c();
+      const RegType& orig_type = work_line_->GetRegisterType(orig_type_reg);
       if (!res_type.IsNonZeroReferenceTypes()) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
+        if (is_checkcast) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on unexpected class " << res_type;
+        } else {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance-of on unexpected class " << res_type;
+        }
       } else if (!orig_type.IsReferenceTypes()) {
-        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on non-reference in v" << dec_insn.vA;
+        if (is_checkcast) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "check-cast on non-reference in v" << orig_type_reg;
+        } else {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "instance-of on non-reference in v" << orig_type_reg;
+        }
       } else {
         if (is_checkcast) {
-          work_line_->SetRegisterType(dec_insn.vA, res_type);
+          work_line_->SetRegisterType(inst->VRegA_21c(), res_type);
         } else {
-          work_line_->SetRegisterType(dec_insn.vA, reg_types_.Boolean());
+          work_line_->SetRegisterType(inst->VRegA_22c(), reg_types_.Boolean());
         }
       }
       break;
     }
     case Instruction::ARRAY_LENGTH: {
-      const RegType& res_type = work_line_->GetRegisterType(dec_insn.vB);
+      const RegType& res_type = work_line_->GetRegisterType(inst->VRegB_12x());
       if (res_type.IsReferenceTypes()) {
         if (!res_type.IsArrayTypes() && !res_type.IsZero()) {  // ie not an array or null
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array-length on non-array " << res_type;
         } else {
-          work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+          work_line_->SetRegisterType(inst->VRegA_12x(), reg_types_.Integer());
         }
       }
       break;
     }
     case Instruction::NEW_INSTANCE: {
-      const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB);
+      const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
       if (res_type.IsConflict()) {
         DCHECK_NE(failures_.size(), 0U);
         break;  // bad class
@@ -1582,55 +1630,55 @@
       // initialized must be marked invalid.
       work_line_->MarkUninitRefsAsInvalid(uninit_type);
       // add the new uninitialized reference to the register state
-      work_line_->SetRegisterType(dec_insn.vA, uninit_type);
+      work_line_->SetRegisterType(inst->VRegA_21c(), uninit_type);
       break;
     }
     case Instruction::NEW_ARRAY:
-      VerifyNewArray(dec_insn, false, false);
+      VerifyNewArray(inst, false, false);
       break;
     case Instruction::FILLED_NEW_ARRAY:
-      VerifyNewArray(dec_insn, true, false);
+      VerifyNewArray(inst, true, false);
       just_set_result = true;  // Filled new array sets result register
       break;
     case Instruction::FILLED_NEW_ARRAY_RANGE:
-      VerifyNewArray(dec_insn, true, true);
+      VerifyNewArray(inst, true, true);
       just_set_result = true;  // Filled new array range sets result register
       break;
     case Instruction::CMPL_FLOAT:
     case Instruction::CMPG_FLOAT:
-      if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Float())) {
+      if (!work_line_->VerifyRegisterType(inst->VRegB_23x(), reg_types_.Float())) {
         break;
       }
-      if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Float())) {
+      if (!work_line_->VerifyRegisterType(inst->VRegC_23x(), reg_types_.Float())) {
         break;
       }
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
       break;
     case Instruction::CMPL_DOUBLE:
     case Instruction::CMPG_DOUBLE:
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.DoubleLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.DoubleLo(),
                                               reg_types_.DoubleHi())) {
         break;
       }
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.DoubleLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.DoubleLo(),
                                               reg_types_.DoubleHi())) {
         break;
       }
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
       break;
     case Instruction::CMP_LONG:
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.LongLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegB_23x(), reg_types_.LongLo(),
                                               reg_types_.LongHi())) {
         break;
       }
-      if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.LongLo(),
+      if (!work_line_->VerifyRegisterTypeWide(inst->VRegC_23x(), reg_types_.LongLo(),
                                               reg_types_.LongHi())) {
         break;
       }
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Integer());
       break;
     case Instruction::THROW: {
-      const RegType& res_type = work_line_->GetRegisterType(dec_insn.vA);
+      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";
       }
@@ -1645,12 +1693,12 @@
     case Instruction::PACKED_SWITCH:
     case Instruction::SPARSE_SWITCH:
       /* verify that vAA is an integer, or can be converted to one */
-      work_line_->VerifyRegisterType(dec_insn.vA, reg_types_.Integer());
+      work_line_->VerifyRegisterType(inst->VRegA_31t(), reg_types_.Integer());
       break;
 
     case Instruction::FILL_ARRAY_DATA: {
       /* Similar to the verification done for APUT */
-      const RegType& array_type = work_line_->GetRegisterType(dec_insn.vA);
+      const RegType& array_type = work_line_->GetRegisterType(inst->VRegA_31t());
       /* array_type can be null if the reg type is Zero */
       if (!array_type.IsZero()) {
         if (!array_type.IsArrayTypes()) {
@@ -1683,8 +1731,8 @@
     }
     case Instruction::IF_EQ:
     case Instruction::IF_NE: {
-      const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA);
-      const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB);
+      const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
+      const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
       bool mismatch = false;
       if (reg_type1.IsZero()) {  // zero then integral or reference expected
         mismatch = !reg_type2.IsReferenceTypes() && !reg_type2.IsIntegralTypes();
@@ -1703,8 +1751,8 @@
     case Instruction::IF_GE:
     case Instruction::IF_GT:
     case Instruction::IF_LE: {
-      const RegType& reg_type1 = work_line_->GetRegisterType(dec_insn.vA);
-      const RegType& reg_type2 = work_line_->GetRegisterType(dec_insn.vB);
+      const RegType& reg_type1 = work_line_->GetRegisterType(inst->VRegA_22t());
+      const RegType& reg_type2 = work_line_->GetRegisterType(inst->VRegB_22t());
       if (!reg_type1.IsIntegralTypes() || !reg_type2.IsIntegralTypes()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "args to 'if' (" << reg_type1 << ","
                                           << reg_type2 << ") must be integral";
@@ -1713,17 +1761,94 @@
     }
     case Instruction::IF_EQZ:
     case Instruction::IF_NEZ: {
-      const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+      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";
       }
+
+      // Find previous instruction - its existence is a precondition to peephole optimization.
+      uint32_t instance_of_idx = 0;
+      if (0 != work_insn_idx_) {
+        instance_of_idx = work_insn_idx_ - 1;
+        while(0 != instance_of_idx && !insn_flags_[instance_of_idx].IsOpcode()) {
+          instance_of_idx--;
+        }
+        CHECK(insn_flags_[instance_of_idx].IsOpcode());
+      } else {
+        break;
+      }
+
+      const Instruction* instance_of_inst = Instruction::At(code_item_->insns_ + instance_of_idx);
+
+      /* Check for peep-hole pattern of:
+       *    ...;
+       *    instance-of vX, vY, T;
+       *    ifXXX vX, label ;
+       *    ...;
+       * label:
+       *    ...;
+       * and sharpen the type of vY to be type T.
+       * Note, this pattern can't be if:
+       *  - if there are other branches to this branch,
+       *  - when vX == vY.
+       */
+      if (!CurrentInsnFlags()->IsBranchTarget() &&
+          (Instruction::INSTANCE_OF == instance_of_inst->Opcode()) &&
+          (inst->VRegA_21t() == instance_of_inst->VRegA_22c()) &&
+          (instance_of_inst->VRegA_22c() != instance_of_inst->VRegB_22c())) {
+        // Check that the we are not attempting conversion to interface types,
+        // which is not done because of the multiple inheritance implications.
+        const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
+
+        if(!cast_type.IsUnresolvedTypes() && !cast_type.GetClass()->IsInterface()) {
+          RegisterLine* update_line = new RegisterLine(code_item_->registers_size_, this);
+          if (inst->Opcode() == Instruction::IF_EQZ) {
+            fallthrough_line.reset(update_line);
+          } else {
+            branch_line.reset(update_line);
+          }
+          update_line->CopyFromLine(work_line_.get());
+          update_line->SetRegisterType(instance_of_inst->VRegB_22c(), cast_type);
+          if (!insn_flags_[instance_of_idx].IsBranchTarget() && 0 != instance_of_idx) {
+            // See if instance-of was preceded by a move-object operation, common due to the small
+            // register encoding space of instance-of, and propagate type information to the source
+            // of the move-object.
+            uint32_t move_idx = instance_of_idx - 1;
+            while(0 != move_idx && !insn_flags_[move_idx].IsOpcode()) {
+              move_idx--;
+            }
+            CHECK(insn_flags_[move_idx].IsOpcode());
+            const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx);
+            switch (move_inst->Opcode()) {
+              case Instruction::MOVE_OBJECT:
+                if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) {
+                  update_line->SetRegisterType(move_inst->VRegB_12x(), cast_type);
+                }
+                break;
+              case Instruction::MOVE_OBJECT_FROM16:
+                if (move_inst->VRegA_22x() == instance_of_inst->VRegB_22c()) {
+                  update_line->SetRegisterType(move_inst->VRegB_22x(), cast_type);
+                }
+                break;
+              case Instruction::MOVE_OBJECT_16:
+                if (move_inst->VRegA_32x() == instance_of_inst->VRegB_22c()) {
+                  update_line->SetRegisterType(move_inst->VRegB_32x(), cast_type);
+                }
+                break;
+              default:
+                break;
+            }
+          }
+        }
+      }
+
       break;
     }
     case Instruction::IF_LTZ:
     case Instruction::IF_GEZ:
     case Instruction::IF_GTZ:
     case Instruction::IF_LEZ: {
-      const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA);
+      const RegType& reg_type = work_line_->GetRegisterType(inst->VRegA_21t());
       if (!reg_type.IsIntegralTypes()) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "type " << reg_type
                                           << " unexpected as arg to if-ltz/if-gez/if-gtz/if-lez";
@@ -1731,150 +1856,150 @@
       break;
     }
     case Instruction::AGET_BOOLEAN:
-      VerifyAGet(dec_insn, reg_types_.Boolean(), true);
+      VerifyAGet(inst, reg_types_.Boolean(), true);
       break;
     case Instruction::AGET_BYTE:
-      VerifyAGet(dec_insn, reg_types_.Byte(), true);
+      VerifyAGet(inst, reg_types_.Byte(), true);
       break;
     case Instruction::AGET_CHAR:
-      VerifyAGet(dec_insn, reg_types_.Char(), true);
+      VerifyAGet(inst, reg_types_.Char(), true);
       break;
     case Instruction::AGET_SHORT:
-      VerifyAGet(dec_insn, reg_types_.Short(), true);
+      VerifyAGet(inst, reg_types_.Short(), true);
       break;
     case Instruction::AGET:
-      VerifyAGet(dec_insn, reg_types_.Integer(), true);
+      VerifyAGet(inst, reg_types_.Integer(), true);
       break;
     case Instruction::AGET_WIDE:
-      VerifyAGet(dec_insn, reg_types_.LongLo(), true);
+      VerifyAGet(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::AGET_OBJECT:
-      VerifyAGet(dec_insn, reg_types_.JavaLangObject(false), false);
+      VerifyAGet(inst, reg_types_.JavaLangObject(false), false);
       break;
 
     case Instruction::APUT_BOOLEAN:
-      VerifyAPut(dec_insn, reg_types_.Boolean(), true);
+      VerifyAPut(inst, reg_types_.Boolean(), true);
       break;
     case Instruction::APUT_BYTE:
-      VerifyAPut(dec_insn, reg_types_.Byte(), true);
+      VerifyAPut(inst, reg_types_.Byte(), true);
       break;
     case Instruction::APUT_CHAR:
-      VerifyAPut(dec_insn, reg_types_.Char(), true);
+      VerifyAPut(inst, reg_types_.Char(), true);
       break;
     case Instruction::APUT_SHORT:
-      VerifyAPut(dec_insn, reg_types_.Short(), true);
+      VerifyAPut(inst, reg_types_.Short(), true);
       break;
     case Instruction::APUT:
-      VerifyAPut(dec_insn, reg_types_.Integer(), true);
+      VerifyAPut(inst, reg_types_.Integer(), true);
       break;
     case Instruction::APUT_WIDE:
-      VerifyAPut(dec_insn, reg_types_.LongLo(), true);
+      VerifyAPut(inst, reg_types_.LongLo(), true);
       break;
     case Instruction::APUT_OBJECT:
-      VerifyAPut(dec_insn, reg_types_.JavaLangObject(false), false);
+      VerifyAPut(inst, reg_types_.JavaLangObject(false), false);
       break;
 
     case Instruction::IGET_BOOLEAN:
-      VerifyISGet(dec_insn, reg_types_.Boolean(), true, false);
+      VerifyISGet(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IGET_BYTE:
-      VerifyISGet(dec_insn, reg_types_.Byte(), true, false);
+      VerifyISGet(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IGET_CHAR:
-      VerifyISGet(dec_insn, reg_types_.Char(), true, false);
+      VerifyISGet(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IGET_SHORT:
-      VerifyISGet(dec_insn, reg_types_.Short(), true, false);
+      VerifyISGet(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IGET:
-      VerifyISGet(dec_insn, reg_types_.Integer(), true, false);
+      VerifyISGet(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IGET_WIDE:
-      VerifyISGet(dec_insn, reg_types_.LongLo(), true, false);
+      VerifyISGet(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IGET_OBJECT:
-      VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, false);
+      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, false);
       break;
 
     case Instruction::IPUT_BOOLEAN:
-      VerifyISPut(dec_insn, reg_types_.Boolean(), true, false);
+      VerifyISPut(inst, reg_types_.Boolean(), true, false);
       break;
     case Instruction::IPUT_BYTE:
-      VerifyISPut(dec_insn, reg_types_.Byte(), true, false);
+      VerifyISPut(inst, reg_types_.Byte(), true, false);
       break;
     case Instruction::IPUT_CHAR:
-      VerifyISPut(dec_insn, reg_types_.Char(), true, false);
+      VerifyISPut(inst, reg_types_.Char(), true, false);
       break;
     case Instruction::IPUT_SHORT:
-      VerifyISPut(dec_insn, reg_types_.Short(), true, false);
+      VerifyISPut(inst, reg_types_.Short(), true, false);
       break;
     case Instruction::IPUT:
-      VerifyISPut(dec_insn, reg_types_.Integer(), true, false);
+      VerifyISPut(inst, reg_types_.Integer(), true, false);
       break;
     case Instruction::IPUT_WIDE:
-      VerifyISPut(dec_insn, reg_types_.LongLo(), true, false);
+      VerifyISPut(inst, reg_types_.LongLo(), true, false);
       break;
     case Instruction::IPUT_OBJECT:
-      VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, false);
+      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, false);
       break;
 
     case Instruction::SGET_BOOLEAN:
-      VerifyISGet(dec_insn, reg_types_.Boolean(), true, true);
+      VerifyISGet(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SGET_BYTE:
-      VerifyISGet(dec_insn, reg_types_.Byte(), true, true);
+      VerifyISGet(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SGET_CHAR:
-      VerifyISGet(dec_insn, reg_types_.Char(), true, true);
+      VerifyISGet(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SGET_SHORT:
-      VerifyISGet(dec_insn, reg_types_.Short(), true, true);
+      VerifyISGet(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SGET:
-      VerifyISGet(dec_insn, reg_types_.Integer(), true, true);
+      VerifyISGet(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SGET_WIDE:
-      VerifyISGet(dec_insn, reg_types_.LongLo(), true, true);
+      VerifyISGet(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SGET_OBJECT:
-      VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, true);
+      VerifyISGet(inst, reg_types_.JavaLangObject(false), false, true);
       break;
 
     case Instruction::SPUT_BOOLEAN:
-      VerifyISPut(dec_insn, reg_types_.Boolean(), true, true);
+      VerifyISPut(inst, reg_types_.Boolean(), true, true);
       break;
     case Instruction::SPUT_BYTE:
-      VerifyISPut(dec_insn, reg_types_.Byte(), true, true);
+      VerifyISPut(inst, reg_types_.Byte(), true, true);
       break;
     case Instruction::SPUT_CHAR:
-      VerifyISPut(dec_insn, reg_types_.Char(), true, true);
+      VerifyISPut(inst, reg_types_.Char(), true, true);
       break;
     case Instruction::SPUT_SHORT:
-      VerifyISPut(dec_insn, reg_types_.Short(), true, true);
+      VerifyISPut(inst, reg_types_.Short(), true, true);
       break;
     case Instruction::SPUT:
-      VerifyISPut(dec_insn, reg_types_.Integer(), true, true);
+      VerifyISPut(inst, reg_types_.Integer(), true, true);
       break;
     case Instruction::SPUT_WIDE:
-      VerifyISPut(dec_insn, reg_types_.LongLo(), true, true);
+      VerifyISPut(inst, reg_types_.LongLo(), true, true);
       break;
     case Instruction::SPUT_OBJECT:
-      VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, true);
+      VerifyISPut(inst, reg_types_.JavaLangObject(false), false, true);
       break;
 
     case Instruction::INVOKE_VIRTUAL:
     case Instruction::INVOKE_VIRTUAL_RANGE:
     case Instruction::INVOKE_SUPER:
     case Instruction::INVOKE_SUPER_RANGE: {
-      bool is_range = (dec_insn.opcode == Instruction::INVOKE_VIRTUAL_RANGE ||
-                       dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
-      bool is_super =  (dec_insn.opcode == Instruction::INVOKE_SUPER ||
-                        dec_insn.opcode == Instruction::INVOKE_SUPER_RANGE);
-      mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_VIRTUAL,
+      bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
+                       inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+      bool is_super =  (inst->Opcode() == Instruction::INVOKE_SUPER ||
+                        inst->Opcode() == Instruction::INVOKE_SUPER_RANGE);
+      mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL,
                                                                    is_range, is_super);
       const char* descriptor;
       if (called_method == NULL) {
-        uint32_t method_idx = dec_insn.vB;
+        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
@@ -1892,13 +2017,13 @@
     }
     case Instruction::INVOKE_DIRECT:
     case Instruction::INVOKE_DIRECT_RANGE: {
-      bool is_range = (dec_insn.opcode == Instruction::INVOKE_DIRECT_RANGE);
-      mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_DIRECT,
+      bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
+      mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_DIRECT,
                                                                    is_range, false);
       const char* return_type_descriptor;
       bool is_constructor;
       if (called_method == NULL) {
-        uint32_t method_idx = dec_insn.vB;
+        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         is_constructor = StringPiece(dex_file_->GetMethodName(method_id)) == "<init>";
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
@@ -1915,7 +2040,7 @@
          * allowing the latter only if the "this" argument is the same as the "this" argument to
          * this method (which implies that we're in a constructor ourselves).
          */
-        const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+        const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
         if (this_type.IsConflict())  // failure.
           break;
 
@@ -1959,11 +2084,11 @@
     }
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE: {
-        bool is_range = (dec_insn.opcode == Instruction::INVOKE_STATIC_RANGE);
-        mirror::AbstractMethod* called_method = VerifyInvocationArgs(dec_insn, METHOD_STATIC, is_range, false);
+        bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
+        mirror::AbstractMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range, false);
         const char* descriptor;
         if (called_method == NULL) {
-          uint32_t method_idx = dec_insn.vB;
+          uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
           const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
           uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
@@ -1981,8 +2106,8 @@
       break;
     case Instruction::INVOKE_INTERFACE:
     case Instruction::INVOKE_INTERFACE_RANGE: {
-      bool is_range =  (dec_insn.opcode == Instruction::INVOKE_INTERFACE_RANGE);
-      mirror::AbstractMethod* abs_method = VerifyInvocationArgs(dec_insn, METHOD_INTERFACE, is_range, false);
+      bool is_range =  (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+      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()) {
@@ -1994,7 +2119,7 @@
       /* Get the type of the "this" arg, which should either be a sub-interface of called
        * interface or Object (see comments in RegType::JoinClass).
        */
-      const RegType& this_type = work_line_->GetInvocationThis(dec_insn);
+      const RegType& this_type = work_line_->GetInvocationThis(inst, is_range);
       if (this_type.IsZero()) {
         /* null pointer always passes (and always fails at runtime) */
       } else {
@@ -2017,7 +2142,7 @@
        */
       const char* descriptor;
       if (abs_method == NULL) {
-        uint32_t method_idx = dec_insn.vB;
+        uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
@@ -2035,74 +2160,74 @@
     }
     case Instruction::NEG_INT:
     case Instruction::NOT_INT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Integer());
       break;
     case Instruction::NEG_LONG:
     case Instruction::NOT_LONG:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                    reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::NEG_FLOAT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Float());
+      work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Float());
       break;
     case Instruction::NEG_DOUBLE:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                    reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::INT_TO_LONG:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                      reg_types_.Integer());
       break;
     case Instruction::INT_TO_FLOAT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Float(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_DOUBLE:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                      reg_types_.Integer());
       break;
     case Instruction::LONG_TO_INT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
                                        reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::LONG_TO_FLOAT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
                                        reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::LONG_TO_DOUBLE:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                    reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::FLOAT_TO_INT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Float());
+      work_line_->CheckUnaryOp(inst, reg_types_.Integer(), reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_LONG:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                      reg_types_.Float());
       break;
     case Instruction::FLOAT_TO_DOUBLE:
-      work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckUnaryOpToWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                      reg_types_.Float());
       break;
     case Instruction::DOUBLE_TO_INT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Integer(),
                                        reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::DOUBLE_TO_LONG:
-      work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckUnaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                    reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::DOUBLE_TO_FLOAT:
-      work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+      work_line_->CheckUnaryOpFromWide(inst, reg_types_.Float(),
                                        reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
     case Instruction::INT_TO_BYTE:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Byte(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Byte(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_CHAR:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Char(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Char(), reg_types_.Integer());
       break;
     case Instruction::INT_TO_SHORT:
-      work_line_->CheckUnaryOp(dec_insn, reg_types_.Short(), reg_types_.Integer());
+      work_line_->CheckUnaryOp(inst, reg_types_.Short(), reg_types_.Integer());
       break;
 
     case Instruction::ADD_INT:
@@ -2113,13 +2238,13 @@
     case Instruction::SHL_INT:
     case Instruction::SHR_INT:
     case Instruction::USHR_INT:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+      work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
                                 reg_types_.Integer(), false);
       break;
     case Instruction::AND_INT:
     case Instruction::OR_INT:
     case Instruction::XOR_INT:
-      work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+      work_line_->CheckBinaryOp(inst, reg_types_.Integer(), reg_types_.Integer(),
                                 reg_types_.Integer(), true);
       break;
     case Instruction::ADD_LONG:
@@ -2130,7 +2255,7 @@
     case Instruction::AND_LONG:
     case Instruction::OR_LONG:
     case Instruction::XOR_LONG:
-      work_line_->CheckBinaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOpWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                     reg_types_.LongLo(), reg_types_.LongHi(),
                                     reg_types_.LongLo(), reg_types_.LongHi());
       break;
@@ -2138,7 +2263,7 @@
     case Instruction::SHR_LONG:
     case Instruction::USHR_LONG:
       /* shift distance is Int, making these different from other binary operations */
-      work_line_->CheckBinaryOpWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOpWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                          reg_types_.Integer());
       break;
     case Instruction::ADD_FLOAT:
@@ -2146,14 +2271,14 @@
     case Instruction::MUL_FLOAT:
     case Instruction::DIV_FLOAT:
     case Instruction::REM_FLOAT:
-      work_line_->CheckBinaryOp(dec_insn, 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:
     case Instruction::MUL_DOUBLE:
     case Instruction::DIV_DOUBLE:
     case Instruction::REM_DOUBLE:
-      work_line_->CheckBinaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckBinaryOpWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                     reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                     reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
@@ -2164,15 +2289,15 @@
     case Instruction::SHL_INT_2ADDR:
     case Instruction::SHR_INT_2ADDR:
     case Instruction::USHR_INT_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, 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(dec_insn, 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(dec_insn, 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:
@@ -2182,14 +2307,14 @@
     case Instruction::AND_LONG_2ADDR:
     case Instruction::OR_LONG_2ADDR:
     case Instruction::XOR_LONG_2ADDR:
-      work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOp2addrWide(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                          reg_types_.LongLo(), reg_types_.LongHi(),
                                          reg_types_.LongLo(), reg_types_.LongHi());
       break;
     case Instruction::SHL_LONG_2ADDR:
     case Instruction::SHR_LONG_2ADDR:
     case Instruction::USHR_LONG_2ADDR:
-      work_line_->CheckBinaryOp2addrWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+      work_line_->CheckBinaryOp2addrWideShift(inst, reg_types_.LongLo(), reg_types_.LongHi(),
                                               reg_types_.Integer());
       break;
     case Instruction::ADD_FLOAT_2ADDR:
@@ -2197,14 +2322,14 @@
     case Instruction::MUL_FLOAT_2ADDR:
     case Instruction::DIV_FLOAT_2ADDR:
     case Instruction::REM_FLOAT_2ADDR:
-      work_line_->CheckBinaryOp2addr(dec_insn, 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:
     case Instruction::MUL_DOUBLE_2ADDR:
     case Instruction::DIV_DOUBLE_2ADDR:
     case Instruction::REM_DOUBLE_2ADDR:
-      work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+      work_line_->CheckBinaryOp2addrWide(inst, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
                                          reg_types_.DoubleLo(),  reg_types_.DoubleHi(),
                                          reg_types_.DoubleLo(), reg_types_.DoubleHi());
       break;
@@ -2213,12 +2338,12 @@
     case Instruction::MUL_INT_LIT16:
     case Instruction::DIV_INT_LIT16:
     case Instruction::REM_INT_LIT16:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, true);
       break;
     case Instruction::AND_INT_LIT16:
     case Instruction::OR_INT_LIT16:
     case Instruction::XOR_INT_LIT16:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, true);
       break;
     case Instruction::ADD_INT_LIT8:
     case Instruction::RSUB_INT_LIT8:
@@ -2228,12 +2353,12 @@
     case Instruction::SHL_INT_LIT8:
     case Instruction::SHR_INT_LIT8:
     case Instruction::USHR_INT_LIT8:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), false);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), false, false);
       break;
     case Instruction::AND_INT_LIT8:
     case Instruction::OR_INT_LIT8:
     case Instruction::XOR_INT_LIT8:
-      work_line_->CheckLiteralOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), true);
+      work_line_->CheckLiteralOp(inst, reg_types_.Integer(), reg_types_.Integer(), true, false);
       break;
 
     /* These should never appear during verification. */
@@ -2305,33 +2430,7 @@
     work_line_->SetResultTypeToUnknown();
   }
 
-  /* Handle "continue". Tag the next consecutive instruction. */
-  if ((opcode_flags & Instruction::kContinue) != 0) {
-    uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
-    if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
-      return false;
-    }
-    // The only way to get to a move-exception instruction is to get thrown there. Make sure the
-    // next instruction isn't one.
-    if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
-      return false;
-    }
-    RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
-    if (next_line != NULL) {
-      // Merge registers into what we have for the next instruction, and set the "changed" flag if
-      // needed.
-      if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
-        return false;
-      }
-    } else {
-      /*
-       * We're not recording register data for the next instruction, so we don't know what the prior
-       * state was. We have to assume that something has changed and re-evaluate it.
-       */
-      insn_flags_[next_insn_idx].SetChanged();
-    }
-  }
+
 
   /*
    * Handle "branch". Tag the branch target.
@@ -2357,8 +2456,14 @@
       return false;
     }
     /* update branch target, set "changed" if appropriate */
-    if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
-      return false;
+    if (NULL != branch_line.get()) {
+      if (!UpdateRegisters(work_insn_idx_ + branch_target, branch_line.get())) {
+        return false;
+      }
+    } else {
+      if (!UpdateRegisters(work_insn_idx_ + branch_target, work_line_.get())) {
+        return false;
+      }
     }
   }
 
@@ -2433,7 +2538,7 @@
        * monitor-enter and the monitor stack was empty, we don't need a catch-all (if it throws,
        * it will do so before grabbing the lock).
        */
-      if (dec_insn.opcode != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
+      if (inst->Opcode() != Instruction::MONITOR_ENTER || work_line_->MonitorStackDepth() != 1) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD)
             << "expected to be within a catch-all for an instruction where a monitor is held";
         return false;
@@ -2441,6 +2546,42 @@
     }
   }
 
+  /* Handle "continue". Tag the next consecutive instruction.
+   *  Note: Keep the code handling "continue" case below the "branch" and "switch" cases,
+   *        because it changes work_line_ when performing peephole optimization
+   *        and this change should not be used in those cases.
+   */
+    if ((opcode_flags & Instruction::kContinue) != 0) {
+      uint32_t next_insn_idx = work_insn_idx_ + CurrentInsnFlags()->GetLengthInCodeUnits();
+      if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
+        return false;
+      }
+      // The only way to get to a move-exception instruction is to get thrown there. Make sure the
+      // next instruction isn't one.
+      if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
+        return false;
+      }
+      if (NULL != fallthrough_line.get()) {
+        // Make workline consistent with fallthrough computed from peephole optimization.
+        work_line_->CopyFromLine(fallthrough_line.get());
+      }
+      RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
+      if (next_line != NULL) {
+        // Merge registers into what we have for the next instruction,
+        // and set the "changed" flag if needed.
+        if (!UpdateRegisters(next_insn_idx, work_line_.get())) {
+          return false;
+        }
+      } else {
+        /*
+         * We're not recording register data for the next instruction, so we don't know what the
+         * prior state was. We have to assume that something has changed and re-evaluate it.
+         */
+        insn_flags_[next_insn_idx].SetChanged();
+      }
+    }
+
   /* If we're returning from the method, make sure monitor stack is empty. */
   if ((opcode_flags & Instruction::kReturn) != 0) {
     if (!work_line_->VerifyMonitorStackEmpty()) {
@@ -2472,7 +2613,8 @@
   const RegType& referrer = GetDeclaringClass();
   mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
   const RegType& result =
-      klass != NULL ? reg_types_.FromClass(klass, klass->IsFinal())
+      klass != NULL ? reg_types_.FromClass(descriptor, klass,
+                                           klass->CannotBeAssignedFromOtherTypes())
                     : reg_types_.FromDescriptor(class_loader_, descriptor, false);
   if (result.IsConflict()) {
     Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "accessing broken descriptor '" << descriptor
@@ -2625,12 +2767,14 @@
   return res_method;
 }
 
-mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const DecodedInstruction& dec_insn,
-                                                             MethodType method_type, bool is_range,
+mirror::AbstractMethod* MethodVerifier::VerifyInvocationArgs(const Instruction* inst,
+                                                             MethodType method_type,
+                                                             bool is_range,
                                                              bool is_super) {
   // Resolve the method. This could be an abstract or concrete method depending on what sort of call
   // we're making.
-  mirror::AbstractMethod* res_method = ResolveMethodAndCheckAccess(dec_insn.vB, method_type);
+  const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+  mirror::AbstractMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
   if (res_method == NULL) {  // error or class is unresolved
     return NULL;
   }
@@ -2660,7 +2804,7 @@
   // We use vAA as our expected arg count, rather than res_method->insSize, because we need to
   // match the call to the signature. Also, we might might be calling through an abstract method
   // definition (which doesn't have register count values).
-  size_t expected_args = dec_insn.vA;
+  const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
   /* caught by static verifier */
   DCHECK(is_range || expected_args <= 5);
   if (expected_args > code_item_->outs_size_) {
@@ -2676,7 +2820,7 @@
    */
   size_t actual_args = 0;
   if (!res_method->IsStatic()) {
-    const RegType& actual_arg_type = work_line_->GetInvocationThis(dec_insn);
+    const RegType& actual_arg_type = work_line_->GetInvocationThis(inst, is_range);
     if (actual_arg_type.IsConflict()) {  // GetInvocationThis failed.
       return NULL;
     }
@@ -2686,7 +2830,9 @@
     }
     if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
       mirror::Class* klass = res_method->GetDeclaringClass();
-      const RegType& res_method_class = reg_types_.FromClass(klass, klass->IsFinal());
+      const RegType& res_method_class =
+          reg_types_.FromClass(ClassHelper(klass).GetDescriptor(), klass,
+                               klass->CannotBeAssignedFromOtherTypes());
       if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
         Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "'this' argument '" << actual_arg_type
             << "' not instance of '" << res_method_class << "'";
@@ -2702,6 +2848,10 @@
   MethodHelper mh(res_method);
   const DexFile::TypeList* params = mh.GetParameterTypeList();
   size_t params_size = params == NULL ? 0 : params->Size();
+  uint32_t arg[5];
+  if (!is_range) {
+    inst->GetArgs(arg);
+  }
   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)
@@ -2717,7 +2867,7 @@
       return NULL;
     }
     const RegType& reg_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
-    uint32_t get_reg = is_range ? dec_insn.vC + actual_args : dec_insn.arg[actual_args];
+    uint32_t get_reg = is_range ? inst->VRegC_3rc() + actual_args : arg[actual_args];
     if (!work_line_->VerifyRegisterType(get_reg, reg_type)) {
       return res_method;
     }
@@ -2732,9 +2882,19 @@
   }
 }
 
-void MethodVerifier::VerifyNewArray(const DecodedInstruction& dec_insn, bool is_filled,
-                                 bool is_range) {
-  const RegType& res_type = ResolveClassAndCheckAccess(is_filled ? dec_insn.vB : dec_insn.vC);
+void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range) {
+  uint32_t type_idx;
+  if (!is_filled) {
+    DCHECK_EQ(inst->Opcode(), Instruction::NEW_ARRAY);
+    type_idx = inst->VRegC_22c();
+  } else if (!is_range) {
+    DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
+    type_idx = inst->VRegB_35c();
+  } else {
+    DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
+    type_idx = inst->VRegB_3rc();
+  }
+  const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
   if (res_type.IsConflict()) {  // bad class
     DCHECK_NE(failures_.size(), 0U);
   } else {
@@ -2743,43 +2903,49 @@
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "new-array on non-array class " << res_type;
     } else if (!is_filled) {
       /* make sure "size" register is valid type */
-      work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Integer());
+      work_line_->VerifyRegisterType(inst->VRegB_22c(), reg_types_.Integer());
       /* set register type to array class */
-      work_line_->SetRegisterType(dec_insn.vA, res_type);
+      const RegType& precise_type = reg_types_.FromUninitialized(res_type);
+      work_line_->SetRegisterType(inst->VRegA_22c(), precise_type);
     } else {
       // Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of
       // the list and fail. It's legal, if silly, for arg_count to be zero.
       const RegType& expected_type = reg_types_.GetComponentType(res_type, class_loader_);
-      uint32_t arg_count = dec_insn.vA;
+      uint32_t arg_count = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
+      uint32_t arg[5];
+      if (!is_range) {
+        inst->GetArgs(arg);
+      }
       for (size_t ui = 0; ui < arg_count; ui++) {
-        uint32_t get_reg = is_range ? dec_insn.vC + ui : dec_insn.arg[ui];
+        uint32_t get_reg = is_range ? inst->VRegC_3rc() + ui : arg[ui];
         if (!work_line_->VerifyRegisterType(get_reg, expected_type)) {
           work_line_->SetResultRegisterType(reg_types_.Conflict());
           return;
         }
       }
       // filled-array result goes into "result" register
-      work_line_->SetResultRegisterType(res_type);
+      const RegType& precise_type = reg_types_.FromUninitialized(res_type);
+      work_line_->SetResultRegisterType(precise_type);
     }
   }
 }
 
-void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
+void MethodVerifier::VerifyAGet(const Instruction* inst,
                                 const RegType& insn_type, bool is_primitive) {
-  const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
+  const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
   if (!index_type.IsArrayIndexTypes()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
   } else {
-    const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
     if (array_type.IsZero()) {
       // Null array class; this code path will fail at runtime. Infer a merge-able type from the
       // instruction type. TODO: have a proper notion of bottom here.
       if (!is_primitive || insn_type.IsCategory1Types()) {
         // Reference or category 1
-        work_line_->SetRegisterType(dec_insn.vA, reg_types_.Zero());
+        work_line_->SetRegisterType(inst->VRegA_23x(), reg_types_.Zero());
       } else {
         // Category 2
-        work_line_->SetRegisterTypeWide(dec_insn.vA, reg_types_.FromCat2ConstLo(0, false),
+        work_line_->SetRegisterTypeWide(inst->VRegA_23x(), reg_types_.FromCat2ConstLo(0, false),
                                         reg_types_.FromCat2ConstHi(0, false));
       }
     } else if (!array_type.IsArrayTypes()) {
@@ -2803,9 +2969,9 @@
         // instruction, which can't differentiate object types and ints from floats, longs from
         // doubles.
         if (!component_type.IsLowHalf()) {
-          work_line_->SetRegisterType(dec_insn.vA, component_type);
+          work_line_->SetRegisterType(inst->VRegA_23x(), component_type);
         } else {
-          work_line_->SetRegisterTypeWide(dec_insn.vA, component_type,
+          work_line_->SetRegisterTypeWide(inst->VRegA_23x(), component_type,
                                           component_type.HighHalf(&reg_types_));
         }
       }
@@ -2813,13 +2979,13 @@
   }
 }
 
-void MethodVerifier::VerifyAPut(const DecodedInstruction& dec_insn,
+void MethodVerifier::VerifyAPut(const Instruction* inst,
                              const RegType& insn_type, bool is_primitive) {
-  const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
+  const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
   if (!index_type.IsArrayIndexTypes()) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
   } else {
-    const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& array_type = work_line_->GetRegisterType(inst->VRegB_23x());
     if (array_type.IsZero()) {
       // Null array type; this code path will fail at runtime. Infer a merge-able type from the
       // instruction type.
@@ -2843,7 +3009,7 @@
         // 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(dec_insn.vA, is_primitive ? component_type : insn_type);
+        work_line_->VerifyRegisterType(inst->VRegA_23x(), is_primitive ? component_type : insn_type);
       }
     }
   }
@@ -2865,7 +3031,7 @@
   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 << " ("
+    LOG(INFO) << "Unable to resolve static field " << field_idx << " ("
               << dex_file_->GetFieldName(field_id) << ") in "
               << dex_file_->GetFieldDeclaringClassDescriptor(field_id);
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -2900,7 +3066,7 @@
   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 << " ("
+    LOG(INFO) << "Unable to resolve instance field " << field_idx << " ("
               << dex_file_->GetFieldName(field_id) << ") in "
               << dex_file_->GetFieldDeclaringClassDescriptor(field_id);
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -2920,7 +3086,9 @@
     return field;
   } else {
     mirror::Class* klass = field->GetDeclaringClass();
-    const RegType& field_klass = reg_types_.FromClass(klass, klass->IsFinal());
+    const RegType& field_klass =
+        reg_types_.FromClass(dex_file_->GetFieldDeclaringClassDescriptor(field_id),
+                             klass, klass->CannotBeAssignedFromOtherTypes());
     if (obj_type.IsUninitializedTypes() &&
         (!IsConstructor() || GetDeclaringClass().Equals(obj_type) ||
             !field_klass.Equals(GetDeclaringClass()))) {
@@ -2943,14 +3111,14 @@
   }
 }
 
-void MethodVerifier::VerifyISGet(const DecodedInstruction& dec_insn,
-                              const RegType& insn_type, bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC;
+void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_type,
+                                 bool is_primitive, bool is_static) {
+  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   mirror::Field* field;
   if (is_static) {
     field = GetStaticField(field_idx);
   } else {
-    const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
     field = GetInstanceField(object_type, field_idx);
   }
   const char* descriptor;
@@ -2964,6 +3132,7 @@
     loader = class_loader_;
   }
   const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false);
+  const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
   if (is_primitive) {
     if (field_type.Equals(insn_type) ||
         (field_type.IsFloat() && insn_type.IsIntegralTypes()) ||
@@ -2985,25 +3154,25 @@
                                         << " to be compatible with type '" << insn_type
                                         << "' but found type '" << field_type
                                         << "' in get-object";
-      work_line_->SetRegisterType(dec_insn.vA, reg_types_.Conflict());
+      work_line_->SetRegisterType(vregA, reg_types_.Conflict());
       return;
     }
   }
   if (!field_type.IsLowHalf()) {
-    work_line_->SetRegisterType(dec_insn.vA, field_type);
+    work_line_->SetRegisterType(vregA, field_type);
   } else {
-    work_line_->SetRegisterTypeWide(dec_insn.vA, field_type, field_type.HighHalf(&reg_types_));
+    work_line_->SetRegisterTypeWide(vregA, field_type, field_type.HighHalf(&reg_types_));
   }
 }
 
-void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
-                              const RegType& insn_type, bool is_primitive, bool is_static) {
-  uint32_t field_idx = is_static ? dec_insn.vB : dec_insn.vC;
+void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_type,
+                                 bool is_primitive, bool is_static) {
+  uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
   mirror::Field* field;
   if (is_static) {
     field = GetStaticField(field_idx);
   } else {
-    const RegType& object_type = work_line_->GetRegisterType(dec_insn.vB);
+    const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c());
     field = GetInstanceField(object_type, field_idx);
   }
   const char* descriptor;
@@ -3024,11 +3193,12 @@
       return;
     }
   }
+  const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
   if (is_primitive) {
     // Primitive field assignability rules are weaker than regular assignability rules
     bool instruction_compatible;
     bool value_compatible;
-    const RegType& value_type = work_line_->GetRegisterType(dec_insn.vA);
+    const RegType& value_type = work_line_->GetRegisterType(vregA);
     if (field_type.IsIntegralTypes()) {
       instruction_compatible = insn_type.IsIntegralTypes();
       value_compatible = value_type.IsIntegralTypes();
@@ -3056,7 +3226,7 @@
       return;
     }
     if (!value_compatible) {
-      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << dec_insn.vA
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
           << " of type " << value_type
           << " but expected " << field_type
           << " for store to " << PrettyField(field) << " in put";
@@ -3070,7 +3240,7 @@
                                         << "' in put-object";
       return;
     }
-    work_line_->VerifyRegisterType(dec_insn.vA, field_type);
+    work_line_->VerifyRegisterType(vregA, field_type);
   }
 }
 
@@ -3128,14 +3298,18 @@
 }
 
 const RegType& MethodVerifier::GetDeclaringClass() {
-  if (foo_method_ != NULL) {
-    mirror::Class* klass = foo_method_->GetDeclaringClass();
-    return reg_types_.FromClass(klass, klass->IsFinal());
-  } else {
+  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_));
-    return reg_types_.FromDescriptor(class_loader_, descriptor, false);
+    if (mirror_method_ != NULL) {
+      mirror::Class* klass = mirror_method_->GetDeclaringClass();
+      declaring_class_ = &reg_types_.FromClass(descriptor, klass,
+                                               klass->CannotBeAssignedFromOtherTypes());
+    } else {
+      declaring_class_ = &reg_types_.FromDescriptor(class_loader_, descriptor, false);
+    }
   }
+  return *declaring_class_;
 }
 
 void MethodVerifier::ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits,
@@ -3160,7 +3334,39 @@
   *log2_max_gc_pc = i;
 }
 
-MethodVerifier::PcToConreteMethod* MethodVerifier::GenerateDevirtMap() {
+MethodVerifier::MethodSafeCastSet* MethodVerifier::GenerateSafeCastSet() {
+  /*
+   * Walks over the method code and adds any cast instructions in which
+   * the type cast is implicit to a set, which is used in the code generation
+   * to elide these casts.
+   */
+  if (!failure_messages_.empty()) {
+    return NULL;
+  }
+  UniquePtr<MethodSafeCastSet> mscs;
+  const Instruction* inst = Instruction::At(code_item_->insns_);
+  const Instruction* end = Instruction::At(code_item_->insns_ +
+                                           code_item_->insns_size_in_code_units_);
+
+  for (; inst < end; inst = inst->Next()) {
+    if (Instruction::CHECK_CAST != inst->Opcode()) {
+      continue;
+    }
+    uint32_t dex_pc = inst->GetDexPc(code_item_->insns_);
+    RegisterLine* line = reg_table_.GetLine(dex_pc);
+    const RegType& reg_type(line->GetRegisterType(inst->VRegA_21c()));
+    const RegType& cast_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+    if (cast_type.IsStrictlyAssignableFrom(reg_type)) {
+      if (mscs.get() == NULL) {
+        mscs.reset(new MethodSafeCastSet());
+      }
+      mscs->insert(dex_pc);
+    }
+  }
+  return mscs.release();
+}
+
+MethodVerifier::PcToConcreteMethodMap* MethodVerifier::GenerateDevirtMap() {
 
   // It is risky to rely on reg_types for sharpening in cases of soft
   // verification, we might end up sharpening to a wrong implementation. Just abort.
@@ -3168,39 +3374,43 @@
     return NULL;
   }
 
-  PcToConreteMethod* pc_to_concrete_method = new PcToConreteMethod();
-  uint32_t dex_pc = 0;
+  UniquePtr<PcToConcreteMethodMap> pc_to_concrete_method_map;
   const uint16_t* insns = code_item_->insns_ ;
   const Instruction* inst = Instruction::At(insns);
+  const Instruction* end = Instruction::At(insns + code_item_->insns_size_in_code_units_);
 
-  for (; dex_pc < code_item_->insns_size_in_code_units_;
-         dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits(), inst = inst->Next()) {
-
+  for (; inst < end; inst = inst->Next()) {
     bool is_virtual   = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
         (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE);
     bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
         (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
 
-   if(!(is_interface || is_virtual))
-     continue;
-
-    // Check if vC ("this" pointer in the instruction) has a precise type.
-    RegisterLine* line = reg_table_.GetLine(dex_pc);
-    DecodedInstruction dec_insn(inst);
-    const RegType& reg_type(line->GetRegisterType(dec_insn.vC));
-
-    if (!reg_type.IsPreciseReference()) {
-       continue;
+    if(!is_interface && !is_virtual) {
+      continue;
     }
+    // Get reg type for register holding the reference to the object that will be dispatched upon.
+    uint32_t dex_pc = inst->GetDexPc(insns);
+    RegisterLine* line = reg_table_.GetLine(dex_pc);
+    bool is_range = (inst->Opcode() ==  Instruction::INVOKE_VIRTUAL_RANGE) ||
+        (inst->Opcode() ==  Instruction::INVOKE_INTERFACE_RANGE);
+    const RegType&
+        reg_type(line->GetRegisterType(is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
 
-    CHECK(!(reg_type.GetClass()->IsInterface()));
-    // If the class is an array class, it can be both Abstract and final and so
-    // the reg_type will be created as precise.
-    CHECK(!(reg_type.GetClass()->IsAbstract()) || reg_type.GetClass()->IsArrayClass());
-    // Find the abstract method.
-    // vB has the method index.
-    mirror::AbstractMethod* abstract_method =  NULL ;
-    abstract_method =  dex_cache_->GetResolvedMethod(dec_insn.vB);
+    if (!reg_type.HasClass()) {
+      // We will compute devirtualization information only when we know the Class of the reg type.
+      continue;
+    }
+    mirror::Class* reg_class = reg_type.GetClass();
+    if (reg_class->IsInterface()) {
+      // We can't devirtualize when the known type of the register is an interface.
+      continue;
+    }
+    if (reg_class->IsAbstract() && !reg_class->IsArrayClass()) {
+      // We can't devirtualize abstract classes except on arrays of abstract classes.
+      continue;
+    }
+    mirror::AbstractMethod* abstract_method =
+        dex_cache_->GetResolvedMethod(is_range ? inst->VRegB_3rc() : inst->VRegB_35c());
     if(abstract_method == NULL) {
       // If the method is not found in the cache this means that it was never found
       // by ResolveMethodAndCheckAccess() called when verifying invoke_*.
@@ -3214,28 +3424,24 @@
     if (is_virtual) {
       concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
     }
-
-    if(concrete_method == NULL) {
-      // In cases where concrete_method is not found continue to the next invoke instead
-      // of crashing.
+    if (concrete_method == NULL || concrete_method->IsAbstract()) {
+      // In cases where concrete_method is not found, or is abstract, continue to the next invoke.
       continue;
     }
-
-    CHECK(!concrete_method->IsAbstract()) << PrettyMethod(concrete_method);
-    // Build method reference.
-    CompilerDriver::MethodReference concrete_ref(
-        concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
-        concrete_method->GetDexMethodIndex());
-    // Now Save the current PC and the concrete method reference to be used
-    // in compiler driver.
-    pc_to_concrete_method->Put(dex_pc, concrete_ref );
+    if (reg_type.IsPreciseReference() || concrete_method->IsFinal() ||
+        concrete_method->GetDeclaringClass()->IsFinal()) {
+      // If we knew exactly the class being dispatched upon, or if the target method cannot be
+      // overridden record the target to be used in the compiler driver.
+      if (pc_to_concrete_method_map.get() == NULL) {
+        pc_to_concrete_method_map.reset(new PcToConcreteMethodMap());
+      }
+      CompilerDriver::MethodReference concrete_ref(
+          concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
+          concrete_method->GetDexMethodIndex());
+      pc_to_concrete_method_map->Put(dex_pc, concrete_ref);
     }
-
-  if (pc_to_concrete_method->size() == 0) {
-    delete pc_to_concrete_method;
-    return NULL ;
   }
-  return pc_to_concrete_method;
+  return pc_to_concrete_method_map.release();
 }
 
 const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
@@ -3276,6 +3482,7 @@
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Failed to encode GC map (size=" << table_size << ")";
     return NULL;
   }
+  table->reserve(table_size);
   // Write table header
   table->push_back(format | ((ref_bitmap_bytes >> DexPcToReferenceMap::kRegMapFormatShift) &
                              ~DexPcToReferenceMap::kRegMapFormatMask));
@@ -3326,9 +3533,10 @@
   }
 }
 
-void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& gc_map) {
+void MethodVerifier::SetDexGcMap(CompilerDriver::MethodReference ref,
+                                 const std::vector<uint8_t>& gc_map) {
   {
-    MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
+    WriterMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
     DexGcMapTable::iterator it = dex_gc_maps_->find(ref);
     if (it != dex_gc_maps_->end()) {
       delete it->second;
@@ -3336,12 +3544,49 @@
     }
     dex_gc_maps_->Put(ref, &gc_map);
   }
-  CHECK(GetDexGcMap(ref) != NULL);
+  DCHECK(GetDexGcMap(ref) != NULL);
 }
 
-void  MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* devirt_map) {
 
-  MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+void  MethodVerifier::SetSafeCastMap(CompilerDriver::MethodReference ref,
+                                     const MethodSafeCastSet* cast_set) {
+  MutexLock mu(Thread::Current(), *safecast_map_lock_);
+  SafeCastMap::iterator it = safecast_map_->find(ref);
+  if (it != safecast_map_->end()) {
+    delete it->second;
+    safecast_map_->erase(it);
+  }
+
+  safecast_map_->Put(ref, cast_set);
+  CHECK(safecast_map_->find(ref) != safecast_map_->end());
+}
+
+bool MethodVerifier::IsSafeCast(CompilerDriver::MethodReference ref, uint32_t pc) {
+  MutexLock mu(Thread::Current(), *safecast_map_lock_);
+  SafeCastMap::const_iterator it = safecast_map_->find(ref);
+  if (it == safecast_map_->end()) {
+    return false;
+  }
+
+  // Look up the cast address in the set of safe casts
+  MethodVerifier::MethodSafeCastSet::const_iterator cast_it = it->second->find(pc);
+  return cast_it != it->second->end();
+}
+
+const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodReference ref) {
+  ReaderMutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
+  DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
+  if (it == dex_gc_maps_->end()) {
+    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.dex_method_index, *ref.dex_file);
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
+}
+
+void  MethodVerifier::SetDevirtMap(CompilerDriver::MethodReference ref,
+                                   const PcToConcreteMethodMap* devirt_map) {
+  WriterMutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::iterator it = devirt_maps_->find(ref);
   if (it != devirt_maps_->end()) {
     delete it->second;
@@ -3352,26 +3597,16 @@
   CHECK(devirt_maps_->find(ref) != devirt_maps_->end());
 }
 
-const std::vector<uint8_t>* MethodVerifier::GetDexGcMap(CompilerDriver::MethodReference ref) {
-  MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
-  DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
-  if (it == dex_gc_maps_->end()) {
-    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.second, *ref.first);
-    return NULL;
-  }
-  CHECK(it->second != NULL);
-  return it->second;
-}
-
-const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc) {
-  MutexLock mu(Thread::Current(), *devirt_maps_lock_);
+const CompilerDriver::MethodReference* MethodVerifier::GetDevirtMap(const CompilerDriver::MethodReference& ref,
+                                                                    uint32_t dex_pc) {
+  ReaderMutexLock mu(Thread::Current(), *devirt_maps_lock_);
   DevirtualizationMapTable::const_iterator it = devirt_maps_->find(ref);
   if (it == devirt_maps_->end()) {
     return NULL;
   }
 
   // Look up the PC in the map, get the concrete method to execute and return its reference.
-  MethodVerifier::PcToConreteMethod::const_iterator pc_to_concrete_method = it->second->find(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 {
@@ -3423,26 +3658,36 @@
   return result;
 }
 
-Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
+ReaderWriterMutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
 MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;
 
-Mutex* MethodVerifier::devirt_maps_lock_ = NULL;
+Mutex* MethodVerifier::safecast_map_lock_ = NULL;
+MethodVerifier::SafeCastMap* MethodVerifier::safecast_map_ = NULL;
+
+ReaderWriterMutex* MethodVerifier::devirt_maps_lock_ = NULL;
 MethodVerifier::DevirtualizationMapTable* MethodVerifier::devirt_maps_ = NULL;
 
 Mutex* MethodVerifier::rejected_classes_lock_ = NULL;
 MethodVerifier::RejectedClassesTable* MethodVerifier::rejected_classes_ = NULL;
 
 void MethodVerifier::Init() {
-  dex_gc_maps_lock_ = new Mutex("verifier GC maps lock");
+  dex_gc_maps_lock_ = new ReaderWriterMutex("verifier GC maps lock");
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, *dex_gc_maps_lock_);
+    WriterMutexLock mu(self, *dex_gc_maps_lock_);
     dex_gc_maps_ = new MethodVerifier::DexGcMapTable;
   }
 
-  devirt_maps_lock_ = new Mutex("verifier Devirtualization lock");
+  safecast_map_lock_ = new Mutex("verifier Cast Elision lock");
   {
-    MutexLock mu(self, *devirt_maps_lock_);
+    MutexLock mu(self, *safecast_map_lock_);
+    safecast_map_ = new MethodVerifier::SafeCastMap();
+  }
+
+  devirt_maps_lock_ = new ReaderWriterMutex("verifier Devirtualization lock");
+
+  {
+    WriterMutexLock mu(self, *devirt_maps_lock_);
     devirt_maps_ = new MethodVerifier::DevirtualizationMapTable();
   }
 
@@ -3457,7 +3702,7 @@
 void MethodVerifier::Shutdown() {
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, *dex_gc_maps_lock_);
+    WriterMutexLock mu(self, *dex_gc_maps_lock_);
     STLDeleteValues(dex_gc_maps_);
     delete dex_gc_maps_;
     dex_gc_maps_ = NULL;
@@ -3466,7 +3711,7 @@
   dex_gc_maps_lock_ = NULL;
 
   {
-    MutexLock mu(self, *devirt_maps_lock_);
+    WriterMutexLock mu(self, *devirt_maps_lock_);
     STLDeleteValues(devirt_maps_);
     delete devirt_maps_;
     devirt_maps_ = NULL;
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index ab7e3cc..198d8cb 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -187,9 +187,15 @@
   static const std::vector<uint8_t>* GetDexGcMap(CompilerDriver::MethodReference ref)
       LOCKS_EXCLUDED(dex_gc_maps_lock_);
 
-  static const CompilerDriver::MethodReference* GetDevirtMap(CompilerDriver::MethodReference ref, uint32_t pc)
+  static const CompilerDriver::MethodReference* GetDevirtMap(const CompilerDriver::MethodReference& ref,
+                                                             uint32_t dex_pc)
       LOCKS_EXCLUDED(devirt_maps_lock_);
 
+  // Returns true if the cast can statically be verified to be redundant
+  // by using the check-cast elision peephole optimization in the verifier
+  static bool IsSafeCast(CompilerDriver::MethodReference ref, uint32_t pc)
+        LOCKS_EXCLUDED(safecast_map_lock_);
+
   // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
   // to the locks held at 'dex_pc' in 'm'.
   static void FindLocksAtDexPc(mirror::AbstractMethod* m, uint32_t dex_pc,
@@ -447,19 +453,18 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of a new array instruction
-  void VerifyNewArray(const DecodedInstruction& dec_insn, bool is_filled,
-                      bool is_range)
+  void VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an aget instruction. The destination register's type will be set to
   // be that of component type of the array unless the array type is unknown, in which case a
   // bottom type inferred from the type of instruction is used. is_primitive is false for an
   // aget-object.
-  void VerifyAGet(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyAGet(const Instruction* inst, const RegType& insn_type,
                   bool is_primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an aput instruction.
-  void VerifyAPut(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyAPut(const Instruction* inst, const RegType& insn_type,
                   bool is_primitive) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Lookup instance field and fail for resolution violations
@@ -470,12 +475,12 @@
   mirror::Field* GetStaticField(int field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an iget or sget instruction.
-  void VerifyISGet(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyISGet(const Instruction* inst, const RegType& insn_type,
                    bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Perform verification of an iput or sput instruction.
-  void VerifyISPut(const DecodedInstruction& insn, const RegType& insn_type,
+  void VerifyISPut(const Instruction* inst, const RegType& insn_type,
                    bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -522,8 +527,9 @@
    * Returns the resolved method on success, NULL on failure (with *failure
    * set appropriately).
    */
-  mirror::AbstractMethod* VerifyInvocationArgs(const DecodedInstruction& dec_insn,
-                               MethodType method_type, bool is_range, bool is_super)
+  mirror::AbstractMethod* VerifyInvocationArgs(const Instruction* inst,
+                                               MethodType method_type,
+                                               bool is_range, bool is_super)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
@@ -574,23 +580,36 @@
   InstructionFlags* CurrentInsnFlags();
 
   // All the GC maps that the verifier has created
-  typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*> DexGcMapTable;
-  static Mutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  typedef SafeMap<const CompilerDriver::MethodReference, const std::vector<uint8_t>*,
+      CompilerDriver::MethodReferenceComparator> DexGcMapTable;
+  static ReaderWriterMutex* dex_gc_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   static DexGcMapTable* dex_gc_maps_ GUARDED_BY(dex_gc_maps_lock_);
   static void SetDexGcMap(CompilerDriver::MethodReference ref, const std::vector<uint8_t>& dex_gc_map)
       LOCKS_EXCLUDED(dex_gc_maps_lock_);
 
 
+  // Cast elision types.
+  typedef std::set<uint32_t> MethodSafeCastSet;
+  typedef SafeMap<const CompilerDriver::MethodReference, const MethodSafeCastSet*,
+      CompilerDriver::MethodReferenceComparator> SafeCastMap;
+  MethodVerifier::MethodSafeCastSet* GenerateSafeCastSet()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static void SetSafeCastMap(CompilerDriver::MethodReference ref, const MethodSafeCastSet* mscs);
+      LOCKS_EXCLUDED(safecast_map_lock_);
+  static Mutex* safecast_map_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  static SafeCastMap* safecast_map_ GUARDED_BY(safecast_map_lock_);
+
   // Devirtualization map.
-  typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConreteMethod;
-  typedef SafeMap<const CompilerDriver::MethodReference, const PcToConreteMethod*>
-      DevirtualizationMapTable;
-  MethodVerifier::PcToConreteMethod* GenerateDevirtMap()
+  typedef SafeMap<const uint32_t, CompilerDriver::MethodReference> PcToConcreteMethodMap;
+  typedef SafeMap<const CompilerDriver::MethodReference, const PcToConcreteMethodMap*,
+      CompilerDriver::MethodReferenceComparator> DevirtualizationMapTable;
+  MethodVerifier::PcToConcreteMethodMap* GenerateDevirtMap()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Mutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  static ReaderWriterMutex* devirt_maps_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   static DevirtualizationMapTable* devirt_maps_ GUARDED_BY(devirt_maps_lock_);
-  static void SetDevirtMap(CompilerDriver::MethodReference ref, const PcToConreteMethod* pc_method_map);
+  static void SetDevirtMap(CompilerDriver::MethodReference ref,
+                           const PcToConcreteMethodMap* pc_method_map)
         LOCKS_EXCLUDED(devirt_maps_lock_);
   typedef std::set<CompilerDriver::ClassReference> RejectedClassesTable;
   static Mutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -613,20 +632,20 @@
   // Storage for the register status we're saving for later.
   UniquePtr<RegisterLine> saved_line_;
 
-  uint32_t dex_method_idx_;  // The method we're working on.
+  const uint32_t dex_method_idx_;  // The method we're working on.
   // Its object representation if known.
-  mirror::AbstractMethod* foo_method_ GUARDED_BY(Locks::mutator_lock_);
-  uint32_t method_access_flags_;  // Method's access flags.
-  const DexFile* dex_file_;  // The dex file containing the method.
+  mirror::AbstractMethod* mirror_method_ GUARDED_BY(Locks::mutator_lock_);
+  const uint32_t method_access_flags_;  // Method's access flags.
+  const DexFile* const dex_file_;  // The dex file containing the method.
   // The dex_cache for the declaring class of the method.
   mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_);
   // The class loader for the declaring class of the method.
   mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_);
-  uint32_t class_def_idx_;  // The class def index of the declaring class of the method.
-  const DexFile::CodeItem* code_item_;  // The code item containing the code for the method.
+  const uint32_t class_def_idx_;  // The class def index of the declaring class of the method.
+  const DexFile::CodeItem* const code_item_;  // The code item containing the code for the method.
+  const RegType* declaring_class_;  // Lazily computed reg type of the method's declaring class.
   // Instruction widths and flags, one entry per code unit.
   UniquePtr<InstructionFlags[]> insn_flags_;
-
   // The dex PC of a FindLocksAtDexPc request, -1 otherwise.
   uint32_t interesting_dex_pc_;
   // The container into which FindLocksAtDexPc should write the registers containing held locks,
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index 32679f6..1c61a29 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -25,6 +25,7 @@
 #include "mirror/object_array-inl.h"
 #include "object_utils.h"
 #include "reg_type_cache-inl.h"
+#include "scoped_thread_state_change.h"
 
 #include <limits>
 #include <sstream>
@@ -32,7 +33,6 @@
 namespace art {
 namespace verifier {
 
-static const bool kIsDebugBuild = false;
 UndefinedType* UndefinedType::instance_ = NULL;
 ConflictType* ConflictType::instance_ = NULL;
 BooleanType* BooleanType::instance = NULL;
@@ -46,6 +46,41 @@
 DoubleHiType* DoubleHiType::instance_ = NULL;
 IntegerType* IntegerType::instance_ = NULL;
 
+int32_t RegType::ConstantValue() const {
+  ScopedObjectAccess soa(Thread::Current());
+  LOG(FATAL) << "Unexpected call to ConstantValue: " << *this;
+  return 0;
+}
+
+int32_t RegType::ConstantValueLo() const {
+  ScopedObjectAccess soa(Thread::Current());
+  LOG(FATAL) << "Unexpected call to ConstantValueLo: " << *this;
+  return 0;
+}
+
+int32_t RegType::ConstantValueHi() const {
+  ScopedObjectAccess soa(Thread::Current());
+  LOG(FATAL) << "Unexpected call to ConstantValueHi: " << *this;
+  return 0;
+}
+
+PrimitiveType::PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : RegType(klass, descriptor, cache_id) {
+  CHECK(klass != NULL);
+  CHECK(!descriptor.empty());
+}
+
+Cat1Type::Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : PrimitiveType(klass, descriptor, cache_id) {
+}
+
+Cat2Type::Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    : PrimitiveType(klass, descriptor, cache_id) {
+}
+
 std::string PreciseConstType::Dump() const {
   std::stringstream result;
   uint32_t val = ConstantValue();
@@ -70,36 +105,44 @@
 std::string ConflictType::Dump() const {
     return "Conflict";
 }
+
 std::string ByteType::Dump() const {
   return "Byte";
 }
+
 std::string ShortType::Dump() const {
   return "short";
 }
+
 std::string CharType::Dump() const {
   return "Char";
 }
+
 std::string FloatType::Dump() const {
   return "float";
 }
+
 std::string LongLoType::Dump() const {
   return "long (Low Half)";
 }
+
 std::string LongHiType::Dump() const {
   return "long (High Half)";
 }
+
 std::string DoubleLoType::Dump() const {
   return "Double (Low Half)";
 }
+
 std::string DoubleHiType::Dump() const {
   return "Double (High Half)";
 }
+
 std::string IntegerType::Dump() const {
     return "Integer";
 }
 
-
-DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                            uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new DoubleHiType(klass, descriptor, cache_id);
@@ -119,7 +162,7 @@
   }
 }
 
-DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                            uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new DoubleLoType(klass, descriptor, cache_id);
@@ -139,7 +182,7 @@
   }
 }
 
-LongLoType* LongLoType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                        uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new LongLoType(klass, descriptor, cache_id);
@@ -147,7 +190,7 @@
   return instance_;
 }
 
-LongHiType* LongHiType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                        uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new LongHiType(klass, descriptor, cache_id);
@@ -179,9 +222,8 @@
   }
 }
 
-FloatType* FloatType::CreateInstance(mirror::Class* klass, std::string& descriptor,
-                                     uint16_t cache_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+FloatType* FloatType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+                                     uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new FloatType(klass, descriptor, cache_id);
   }
@@ -199,17 +241,19 @@
   }
 }
 
-CharType* CharType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+CharType* CharType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                    uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new CharType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 CharType* CharType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void CharType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
@@ -217,81 +261,94 @@
   }
 }
 
-ShortType* ShortType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+ShortType* ShortType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                      uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new ShortType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 ShortType* ShortType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void ShortType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-ByteType* ByteType::CreateInstance(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+ByteType* ByteType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
+                                   uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new ByteType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 ByteType* ByteType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void ByteType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-IntegerType* IntegerType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                          uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new IntegerType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 IntegerType* IntegerType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void IntegerType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-ConflictType* ConflictType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+ConflictType* ConflictType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                            uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new ConflictType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 ConflictType* ConflictType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void ConflictType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
-BooleanType* BooleanType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                          uint16_t cache_id) {
   if (BooleanType::instance == NULL) {
     instance = new BooleanType(klass, descriptor, cache_id);
   }
   return BooleanType::instance;
 }
+
 BooleanType* BooleanType::GetInstance() {
   CHECK(BooleanType::instance != NULL);
   return BooleanType::instance;
@@ -307,23 +364,33 @@
 std::string UndefinedType::Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return "Undefined";
 }
-UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                              uint16_t cache_id) {
   if (instance_ == NULL) {
     instance_ = new UndefinedType(klass, descriptor, cache_id);
   }
   return instance_;
 }
+
 UndefinedType* UndefinedType::GetInstance() {
   CHECK(instance_ != NULL);
   return instance_;
 }
+
 void UndefinedType::Destroy() {
   if (instance_ != NULL) {
     delete instance_;
     instance_ = NULL;
   }
 }
+
+PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, const std::string& descriptor,
+                                           uint16_t cache_id)
+    : RegType(klass, descriptor, cache_id) {
+  DCHECK(klass->IsInstantiable());
+}
+
 std::string UnresolvedMergedType::Dump() const {
   std::stringstream result;
   std::set<uint16_t> types = GetMergedTypes();
@@ -338,6 +405,7 @@
   result << ")";
   return result.str();
 }
+
 std::string UnresolvedSuperClass::Dump() const {
   std::stringstream result;
   uint16_t super_type_id = GetUnresolvedSuperClassChildId();
@@ -358,7 +426,7 @@
   return result.str();
 }
 
-std::string UnresolvedUninitialisedThisRefType::Dump() const {
+std::string UnresolvedUninitializedThisRefType::Dump() const {
   std::stringstream result;
   result << "Unresolved And Uninitialized This Reference" << PrettyDescriptor(GetDescriptor());
   return result.str();
@@ -376,13 +444,14 @@
   return result.str();
 }
 
-std::string UninitialisedReferenceType::Dump() const {
+std::string UninitializedReferenceType::Dump() const {
   std::stringstream result;
   result << "Uninitialized Reference" << ": " << PrettyDescriptor(GetClass());
   result << " Allocation PC: " << GetAllocationPc();
   return result.str();
 }
-std::string UninitialisedThisReferenceType::Dump() const {
+
+std::string UninitializedThisReferenceType::Dump() const {
   std::stringstream result;
   result << "Uninitialized This Reference" << ": " << PrettyDescriptor(GetClass());
   result << "Allocation PC: " << GetAllocationPc();
@@ -459,77 +528,8 @@
   return result.str();
 }
 
-BooleanType::BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      : RegType(klass, descriptor, cache_id) {
-}
-
-ConflictType::ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-ByteType::ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-ShortType::ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-CharType::CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-IntegerType::IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-ConstantType::ConstantType(uint32_t constat, uint16_t cache_id)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_): RegType(NULL, "", cache_id), constant_(constat) {
-}
-
-ReferenceType::ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, std::string& descriptor,
-                                           uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-  DCHECK(klass->IsInstantiable());
-}
-
-UnresolvedUninitialisedThisRefType::UnresolvedUninitialisedThisRefType(std::string& descriptor,
-                                                                       uint16_t cache_id)
-    : UninitializedType(NULL, descriptor, 0, cache_id) {
-}
-
-UnresolvedUninitializedRefType::UnresolvedUninitializedRefType( std::string& descriptor,
-                                                         uint32_t allocation_pc, uint16_t cache_id)
-    : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
-}
-
-UninitialisedReferenceType::UninitialisedReferenceType(mirror::Class* klass,
-                                std::string& descriptor, uint32_t allocation_pc, uint16_t cache_id)
-    : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
-}
-
-LongHiType::LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-FloatType::FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-DoubleLoType::DoubleLoType(mirror::Class* klass,  std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-DoubleHiType::DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
-}
-
-LongLoType::LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id) {
+ConstantType::ConstantType(uint32_t constant, uint16_t cache_id)
+    : RegType(NULL, "", cache_id), constant_(constant) {
 }
 
 const RegType& UndefinedType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
@@ -575,6 +575,17 @@
   }
 }
 
+bool UninitializedType::IsUninitializedTypes() const {
+  return true;
+}
+
+bool UninitializedType::IsNonZeroReferenceTypes() const {
+  return true;
+}
+
+bool UnresolvedType::IsNonZeroReferenceTypes() const {
+  return true;
+}
 std::set<uint16_t> UnresolvedMergedType::GetMergedTypes() const {
   std::pair<uint16_t, uint16_t> refs = GetTopMergedTypes();
   const RegType& _left(reg_type_cache_->GetFromId(refs.first));
@@ -612,7 +623,7 @@
     if (super_klass != NULL) {
       // A super class of a precise type isn't precise as a precise type indicates the register
       // holds exactly that type.
-      return cache->FromClass(super_klass, false);
+      return cache->FromClass(ClassHelper(super_klass).GetDescriptor(), super_klass, false);
     } else {
       return cache->Zero();
     }
@@ -697,62 +708,72 @@
   : ConstantType(constat, cache_id) {
 }
 
-bool RegType::IsAssignableFrom(const RegType& src) const {
-  if (Equals(src)) {
+static bool AssignableFrom(const RegType& lhs, const RegType& rhs, bool strict)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (lhs.Equals(rhs)) {
     return true;
   } else {
-    if (IsBoolean()) {
-      return src.IsBooleanTypes();
-    } else if (IsByte()) {
-      return src.IsByteTypes();
-    } else if (IsShort()) {
-      return src.IsShortTypes();
-    } else if (IsChar()) {
-      return src.IsCharTypes();
-    } else if (IsInteger()) {
-      return src.IsIntegralTypes();
-    } else if (IsFloat()) {
-      return src.IsFloatTypes();
-    } else if (IsLongLo()) {
-      return src.IsLongTypes();
-    } else if (IsDoubleLo()) {
-      return src.IsDoubleTypes();
+    if (lhs.IsBoolean()) {
+      return rhs.IsBooleanTypes();
+    } else if (lhs.IsByte()) {
+      return rhs.IsByteTypes();
+    } else if (lhs.IsShort()) {
+      return rhs.IsShortTypes();
+    } else if (lhs.IsChar()) {
+      return rhs.IsCharTypes();
+    } else if (lhs.IsInteger()) {
+      return rhs.IsIntegralTypes();
+    } else if (lhs.IsFloat()) {
+      return rhs.IsFloatTypes();
+    } else if (lhs.IsLongLo()) {
+      return rhs.IsLongTypes();
+    } else if (lhs.IsDoubleLo()) {
+      return rhs.IsDoubleTypes();
     } else {
-      if (!IsReferenceTypes()) {
-        LOG(FATAL) << "Unexpected register type in 4bleFrom: '" << src << "'";
+      CHECK(lhs.IsReferenceTypes())
+          << "Unexpected register type in IsAssignableFrom: '"
+          << lhs << "' := '" << rhs << "'";
+      if (rhs.IsZero()) {
+        return true;  // All reference types can be assigned null.
+      } else if (!rhs.IsReferenceTypes()) {
+        return false;  // Expect rhs to be a reference type.
+      } else if (lhs.IsJavaLangObject()) {
+        return true;  // All reference types can be assigned to Object.
+      } else if (!strict && !lhs.IsUnresolvedTypes() && lhs.GetClass()->IsInterface()) {
+        // If we're not strict allow assignment to any interface, see comment in ClassJoin.
+        return true;
+      } else if (lhs.IsJavaLangObjectArray()) {
+        return rhs.IsObjectArrayTypes();  // All reference arrays may be assigned to Object[]
+      } else if (lhs.HasClass() && rhs.HasClass() &&
+                 lhs.GetClass()->IsAssignableFrom(rhs.GetClass())) {
+        // We're assignable from the Class point-of-view.
+        return true;
+      } else {
+        // Unresolved types are only assignable for null and equality.
+        return false;
       }
-      if (src.IsZero()) {
-        return true;  // all reference types can be assigned null
-      } else if (!src.IsReferenceTypes()) {
-        return false;  // expect src to be a reference type
-      } else if (IsJavaLangObject()) {
-        return true;  // all reference types can be assigned to Object
-      } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
-          return true;  // We allow assignment to any interface, see comment in ClassJoin
-        } else if (IsJavaLangObjectArray()) {
-          return src.IsObjectArrayTypes();  // All reference arrays may be assigned to Object[]
-        } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
-                   GetClass()->IsAssignableFrom(src.GetClass())) {
-          // We're assignable from the Class point-of-view
-          return true;
-        } else if (IsUnresolvedTypes()) {
-          // Unresolved types are only assignable for null, Object and equality.
-          return (src.IsZero() || src.IsJavaLangObject());
-        } else {
-          return false;
-        }
     }
   }
 }
 
+bool RegType::IsAssignableFrom(const RegType& src) const {
+  return AssignableFrom(*this, src, false);
+}
+
+bool RegType::IsStrictlyAssignableFrom(const RegType& src) const {
+  return AssignableFrom(*this, src, true);
+}
+
 int32_t ConstantType::ConstantValue() const {
   DCHECK(IsConstantTypes());
   return constant_;
 }
+
 int32_t ConstantType::ConstantValueLo() const {
   DCHECK(IsConstantLo());
   return constant_;
 }
+
 int32_t ConstantType::ConstantValueHi() const {
   if (IsConstantHi() || IsPreciseConstantHi() || IsImpreciseConstantHi()) {
     return constant_;
@@ -761,6 +782,7 @@
     return 0;
   }
 }
+
 static const RegType& SelectNonConstant(const RegType& a, const RegType& b) {
   return a.IsConstant() ? b : a;
 }
@@ -884,7 +906,7 @@
       } else if (c2 == join_class && !incoming_type.IsPreciseReference()) {
         return incoming_type;
       } else {
-        return reg_types->FromClass(join_class, false);
+        return reg_types->FromClass(ClassHelper(join_class).GetDescriptor(), join_class, false);
       }
     }
   } else {
@@ -949,33 +971,22 @@
     CHECK(descriptor_.empty()) << *this;
     CHECK(klass_ == NULL) << *this;
   }
+  if (klass_ != NULL) {
+    CHECK(!descriptor_.empty()) << *this;
+  }
 }
 
-UninitializedType::UninitializedType(mirror::Class* klass, std::string& descriptor,
-                                     uint32_t allocation_pc, uint16_t cache_id)
-    : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
+void UninitializedThisReferenceType::CheckInvariants() const {
+  CHECK_EQ(GetAllocationPc(), 0U) << *this;
 }
 
-void UninitializedType::CheckInvariants() const {
-  CHECK_EQ(allocation_pc_, 0U) << *this;
-}
-
-void UninitialisedThisReferenceType::CheckInvariants() const {
-  UninitializedType::CheckInvariants();
-}
-
-UninitialisedThisReferenceType::UninitialisedThisReferenceType(mirror::Class* klass,
-  std::string& descriptor, uint16_t cache_id) : UninitializedType(klass, descriptor, 0, cache_id) {
-}
-
-void UnresolvedUninitialisedThisRefType::CheckInvariants() const {
-  UninitializedType::CheckInvariants();
+void UnresolvedUninitializedThisRefType::CheckInvariants() const {
+  CHECK_EQ(GetAllocationPc(), 0U) << *this;
   CHECK(!descriptor_.empty()) << *this;
   CHECK(klass_ == NULL) << *this;
 }
 
 void UnresolvedUninitializedRefType::CheckInvariants() const {
-  UninitializedType::CheckInvariants();
   CHECK(!descriptor_.empty()) << *this;
   CHECK(klass_ == NULL) << *this;
 }
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 7c42536..9ac0eca 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -18,6 +18,7 @@
 #define ART_SRC_VERIFIER_REG_TYPE_H_
 
 #include "base/macros.h"
+#include "globals.h"
 #include "primitive.h"
 
 #include "jni.h"
@@ -39,105 +40,43 @@
  */
 class RegType {
  public:
-  // The high half that corresponds to this low half
-  const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  inline virtual bool IsUndefined() const {
-    return false;
-  }
-  inline virtual bool IsConflict() const {
-    return false;
-  }
-  inline virtual bool IsBoolean() const {
-    return false;
-  }
-  inline virtual bool IsByte() const {
-    return false;
-  }
-  inline virtual bool IsChar() const {
-    return false;
-  }
-  inline virtual bool IsShort() const {
-    return false;
-  }
-  inline virtual bool IsInteger() const {
-    return false;
-  }
-  inline virtual bool IsLongLo() const {
-    return false;
-  }
-  inline virtual bool IsLongHi() const {
-    return false;
-  }
-  inline virtual bool IsFloat() const {
-    return false;
-  }
-  inline virtual bool IsDouble() const {
-    return false;
-  }
-  inline virtual bool IsDoubleLo() const {
-    return false;
-  }
-  inline virtual bool IsDoubleHi() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedReference() const {
-    return false;
-  }
-  inline virtual bool IsUninitializedReference() const {
-    return false;
-  }
-  inline virtual bool IsUninitializedThisReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedAndUninitializedReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedAndUninitializedThisReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedMergedReference() const {
-    return false;
-  }
-  inline virtual bool IsUnresolvedSuperClass() const {
-    return false;
-  }
-  inline virtual bool IsReference() const {
-    return false;
-  }
-  inline virtual bool IsPreciseReference() const {
-    return false;
-  }
-  inline virtual bool IsPreciseConstant() const {
-    return false;
-  }
-  inline virtual bool IsPreciseConstantLo() const {
-    return false;
-  }
-  inline virtual bool IsPreciseConstantHi() const {
-    return false;
-  }
-  inline virtual bool IsImpreciseConstantLo() const {
-    return false;
-  }
-  inline virtual bool IsImpreciseConstantHi() const {
-    return false;
-  }
-  virtual bool IsImpreciseConstant() const {
-    return false;
-  }
-
-  inline virtual bool IsConstantTypes() const {
-    return false;
-  }
+  virtual bool IsUndefined() const { return false; }
+  virtual bool IsConflict() const { return false; }
+  virtual bool IsBoolean() const { return false; }
+  virtual bool IsByte() const { return false; }
+  virtual bool IsChar() const { return false; }
+  virtual bool IsShort() const { return false; }
+  virtual bool IsInteger() const { return false; }
+  virtual bool IsLongLo() const { return false; }
+  virtual bool IsLongHi() const { return false; }
+  virtual bool IsFloat() const { return false; }
+  virtual bool IsDouble() const { return false; }
+  virtual bool IsDoubleLo() const { return false; }
+  virtual bool IsDoubleHi() const { return false; }
+  virtual bool IsUnresolvedReference() const { return false; }
+  virtual bool IsUninitializedReference() const { return false; }
+  virtual bool IsUninitializedThisReference() const { return false; }
+  virtual bool IsUnresolvedAndUninitializedReference() const { return false; }
+  virtual bool IsUnresolvedAndUninitializedThisReference() const { return false; }
+  virtual bool IsUnresolvedMergedReference() const { return false; }
+  virtual bool IsUnresolvedSuperClass() const { return false; }
+  virtual bool IsReference() const { return false; }
+  virtual bool IsPreciseReference() const { return false; }
+  virtual bool IsPreciseConstant() const { return false; }
+  virtual bool IsPreciseConstantLo() const { return false; }
+  virtual bool IsPreciseConstantHi() const { return false; }
+  virtual bool IsImpreciseConstantLo() const { return false; }
+  virtual bool IsImpreciseConstantHi() const { return false; }
+  virtual bool IsImpreciseConstant() const { return false; }
+  virtual bool IsConstantTypes() const { return false; }
   bool IsConstant() const {
-    return (IsPreciseConstant() || IsImpreciseConstant());
+    return IsPreciseConstant() || IsImpreciseConstant();
   }
   bool IsConstantLo() const {
-    return (IsPreciseConstantLo() || IsImpreciseConstantLo());
+    return IsPreciseConstantLo() || IsImpreciseConstantLo();
   }
   bool IsPrecise() const {
-    return (IsPreciseConstantLo() || IsPreciseConstant() ||
-            IsPreciseConstantHi());
+    return IsPreciseConstantLo() || IsPreciseConstant() || IsPreciseConstantHi();
   }
   bool IsLongConstant() const {
     return IsConstantLo();
@@ -148,11 +87,7 @@
   bool IsLongConstantHigh() const {
     return IsConstantHi();
   }
-  bool IsUninitializedTypes() const {
-    return IsUninitializedReference() || IsUninitializedThisReference() ||
-           IsUnresolvedAndUninitializedReference() ||
-           IsUnresolvedAndUninitializedThisReference();
-  }
+  virtual bool IsUninitializedTypes() const { return false; }
   bool IsUnresolvedTypes() const {
     return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
            IsUnresolvedAndUninitializedThisReference() ||
@@ -170,7 +105,7 @@
   bool IsLongOrDoubleTypes() const {
     return IsLowHalf();
   }
-  // Check this is the low half, and that type_h is its matching high-half
+  // Check this is the low half, and that type_h is its matching high-half.
   inline bool CheckWidePair(const RegType& type_h) const {
     if (IsLowHalf()) {
       return ((IsPreciseConstantLo() && type_h.IsPreciseConstantHi()) ||
@@ -182,37 +117,36 @@
     }
     return false;
   }
+  // The high half that corresponds to this low half
+  const RegType& HighHalf(RegTypeCache* cache) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsConstantBoolean() const {
     return IsConstant() && (ConstantValue() >= 0) && (ConstantValue() <= 1);
   }
-  inline virtual bool IsConstantChar() const {
+  virtual bool IsConstantChar() const {
     return false;
   }
-  inline virtual bool IsConstantByte() const {
+  virtual bool IsConstantByte() const {
     return false;
   }
-  inline virtual bool IsConstantShort() const {
+  virtual bool IsConstantShort() const {
     return false;
   }
-  inline virtual bool IsOne() const {
+  virtual bool IsOne() const {
     return false;
   }
-  inline virtual bool IsZero() const {
+  virtual bool IsZero() const {
     return false;
   }
   bool IsReferenceTypes() const {
     return IsNonZeroReferenceTypes() || IsZero();
   }
-  bool IsNonZeroReferenceTypes() const {
-    return IsReference() || IsPreciseReference() ||
-           IsUninitializedReference() || IsUninitializedThisReference() ||
-           IsUnresolvedReference() || IsUnresolvedAndUninitializedReference() ||
-           IsUnresolvedAndUninitializedThisReference() ||
-           IsUnresolvedMergedReference() || IsUnresolvedSuperClass();
+  virtual bool IsNonZeroReferenceTypes() const {
+    return false;
   }
   bool IsCategory1Types() const {
-    return (IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() ||
-        IsShort() || IsBoolean()  );
+    return IsChar() || IsInteger() || IsFloat() || IsConstant() || IsByte() || IsShort() ||
+        IsBoolean();
   }
   bool IsCategory2Types() const {
     return IsLowHalf();  // Don't expect explicit testing of high halves
@@ -230,20 +164,12 @@
     return IsChar() || IsBooleanTypes() || IsConstantChar();
   }
   bool IsIntegralTypes() const {
-    return (IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean() );
+    return IsInteger() || IsConstant() || IsByte() || IsShort() || IsChar() || IsBoolean();
   }
-  inline virtual int32_t ConstantValue() const {
-    DCHECK(IsConstant());
-    return -1;
-  }
-  inline virtual int32_t ConstantValueLo() const {
-    DCHECK(IsConstantLo());
-    return -1;
-  }
-  inline virtual int32_t ConstantValueHi() const {
-    DCHECK(IsConstantHi());
-    return -1;
-  }
+  // Give the constant value encoded, but this shouldn't be called in the general case.
+  virtual int32_t ConstantValue() const;
+  virtual int32_t ConstantValueLo() const;
+  virtual int32_t ConstantValueHi() const;
   bool IsArrayIndexTypes() const {
     return IsIntegralTypes();
   }
@@ -265,12 +191,11 @@
   bool IsDoubleHighTypes() const {
     return (IsDoubleHi() || IsPreciseConstantHi() || IsImpreciseConstantHi());
   }
-  inline virtual bool IsLong() const {
+  virtual bool IsLong() const {
     return false;
   }
-  bool HasClass() const {
-    return IsReference() || IsPreciseReference() || IsUninitializedReference() ||
-           IsUninitializedThisReference();
+  virtual bool HasClass() const {
+    return false;
   }
   bool IsJavaLangObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsArrayTypes() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -279,210 +204,286 @@
   bool IsJavaLangObjectArray() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsInstantiableTypes() const;
   const std::string& GetDescriptor() const {
-    DCHECK(IsUnresolvedTypes() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass());
+    DCHECK(HasClass() || (IsUnresolvedTypes() && !IsUnresolvedMergedReference() &&
+                          !IsUnresolvedSuperClass()));
     return descriptor_;
   }
-  uint16_t GetId() const {
-    return cache_id_;
-  }
-  const RegType& GetSuperClass(RegTypeCache* cache) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
-  // Can this type access other?
-  bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // Can this type access a member with the given properties?
-  bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // Can this type be assigned by src?
-  bool IsAssignableFrom(const RegType& src) const  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool Equals(const RegType& other) const {
-    return GetId() == other.GetId();
-  }
-  // Compute the merge of this register from one edge (path) with incoming_type from another.
-  virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* GetClass() const {
     DCHECK(!IsUnresolvedReference());
     DCHECK(klass_ != NULL);
     DCHECK(HasClass());
     return klass_;
   }
-    /*
-     * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
-     * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
-     * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
-     * is the deepest (lowest upper bound) parent of S and T).
-     *
-     * This operation applies for regular classes and arrays, however, for interface types there needn't
-     * be a partial ordering on the types. We could solve the problem of a lack of a partial order by
-     * introducing sets of types, however, the only operation permissible on an interface is
-     * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
-     * types until an invoke-interface call on the interface typed reference at runtime and allow
-     * the perversion of Object being assignable to an interface type (note, however, that we don't
-     * allow assignment of Object or Interface to any concrete class and are therefore type safe).
-     *
-     * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
-     */
+  uint16_t GetId() const {
+    return cache_id_;
+  }
+  const RegType& GetSuperClass(RegTypeCache* cache) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  virtual std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
+  // Can this type access other?
+  bool CanAccess(const RegType& other) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type access a member with the given properties?
+  bool CanAccessMember(mirror::Class* klass, uint32_t access_flags) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type be assigned by src?
+  // Note: Object and interface types may always be assigned to one another, see comment on
+  // ClassJoin.
+  bool IsAssignableFrom(const RegType& src) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Can this type be assigned by src? Variant of IsAssignableFrom that doesn't allow assignment to
+  // an interface from an Object.
+  bool IsStrictlyAssignableFrom(const RegType& src) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Are these RegTypes the same?
+  bool Equals(const RegType& other) const {
+    return GetId() == other.GetId();
+  }
+
+  // Compute the merge of this register from one edge (path) with incoming_type from another.
+  virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  /*
+   * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+   * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+   * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
+   * is the deepest (lowest upper bound) parent of S and T).
+   *
+   * This operation applies for regular classes and arrays, however, for interface types there
+   * needn't be a partial ordering on the types. We could solve the problem of a lack of a partial
+   * order by introducing sets of types, however, the only operation permissible on an interface is
+   * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
+   * types until an invoke-interface call on the interface typed reference at runtime and allow
+   * the perversion of Object being assignable to an interface type (note, however, that we don't
+   * allow assignment of Object or Interface to any concrete class and are therefore type safe).
+   *
+   * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
+   */
   static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  RegType(mirror::Class* klass, std::string descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
-  }
-  inline virtual ~RegType() {
-  }
-  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  friend class RegTypeCache;
+
+  virtual ~RegType() {}
 
  protected:
+  RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : descriptor_(descriptor), klass_(klass), cache_id_(cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+
   const std::string descriptor_;
-  mirror::Class* klass_;
+  mirror::Class* const klass_;
   const uint16_t cache_id_;
 
+  friend class RegTypeCache;
+
   DISALLOW_COPY_AND_ASSIGN(RegType);
 };
 
+// Bottom type.
 class ConflictType : public RegType {
  public:
   bool IsConflict() const {
     return true;
   }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static ConflictType* CreateInstance(mirror::Class* klass, std::string& descriptor,
-                                      uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Get the singleton Conflict instance.
   static ConflictType* GetInstance();
+
+  // Create the singleton instance.
+  static ConflictType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
+                                      uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Destroy the singleton instance.
   static void Destroy();
  private:
-  ConflictType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ConflictType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : RegType(klass, descriptor, cache_id) {
+  }
+
   static ConflictType* instance_;
 };
 
+// A variant of the bottom type used to specify an undefined value in the incoming registers.
+// Merging with UndefinedType yields ConflictType which is the true bottom.
 class UndefinedType : public RegType {
  public:
   bool IsUndefined() const {
     return true;
   }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static UndefinedType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+
+  // Get the singleton Undefined instance.
+  static UndefinedType* GetInstance();
+
+  // Create the singleton instance.
+  static UndefinedType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                        uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static UndefinedType* GetInstance();
+
+  // Destroy the singleton instance.
   static void Destroy();
  private:
-  UndefinedType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+  UndefinedType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : RegType(klass, descriptor, cache_id) {
   }
+
   virtual const RegType& Merge(const RegType& incoming_type, RegTypeCache* reg_types) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static UndefinedType* instance_;
 };
 
-class IntegerType : public RegType {
+class PrimitiveType : public RegType {
+ public:
+  PrimitiveType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class Cat1Type : public PrimitiveType {
+ public:
+  Cat1Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class IntegerType : public Cat1Type {
  public:
   bool IsInteger() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static IntegerType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static IntegerType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                      uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static IntegerType* GetInstance();
   static void Destroy();
  private:
-  IntegerType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  IntegerType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static IntegerType* instance_;
 };
 
-class BooleanType : public RegType {
+class BooleanType : public Cat1Type {
  public:
   bool IsBoolean() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static BooleanType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static BooleanType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                      uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static BooleanType* GetInstance();
   static void Destroy();
  private:
-  BooleanType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  BooleanType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
+
   static BooleanType* instance;
 };
 
-class ByteType : public RegType {
+class ByteType : public Cat1Type {
  public:
   bool IsByte() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static ByteType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static ByteType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                   uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static ByteType* GetInstance();
   static void Destroy();
  private:
-  ByteType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ByteType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static ByteType* instance_;
 };
 
-class ShortType : public RegType {
+class ShortType : public Cat1Type {
  public:
   bool IsShort() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static ShortType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static ShortType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                    uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static ShortType* GetInstance();
   static void Destroy();
  private:
-  ShortType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ShortType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static ShortType* instance_;
 };
 
-class CharType : public RegType {
+class CharType : public Cat1Type {
  public:
   bool IsChar() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static CharType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static CharType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                   uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static CharType* GetInstance();
   static void Destroy();
  private:
-  CharType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  CharType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static CharType* instance_;
 };
 
-class FloatType : public RegType {
+class FloatType : public Cat1Type {
  public:
   bool IsFloat() const {
     return true;
   }
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static FloatType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static FloatType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                    uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static FloatType* GetInstance();
   static void Destroy();
  private:
-  FloatType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  FloatType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat1Type(klass, descriptor, cache_id) {
+  }
   static FloatType* instance_;
 };
 
-class LongLoType : public RegType {
+class Cat2Type : public PrimitiveType {
+ public:
+  Cat2Type(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+};
+
+class LongLoType : public Cat2Type {
  public:
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsLongLo() const {
@@ -491,35 +492,39 @@
   bool IsLong() const {
     return true;
   }
-  static LongLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static LongLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                     uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
    static LongLoType* GetInstance();
   static void Destroy();
  private:
-  LongLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  LongLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static LongLoType* instance_;
 };
 
-class LongHiType : public RegType {
+class LongHiType : public Cat2Type {
  public:
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsLongHi() const {
     return true;
   }
-  static LongHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static LongHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                     uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static LongHiType* GetInstance();
   static void Destroy();
  private:
-  LongHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  LongHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static LongHiType* instance_;
 };
 
-class DoubleLoType : public RegType {
+class DoubleLoType : public Cat2Type {
  public:
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsDoubleLo() const {
@@ -528,31 +533,35 @@
   bool IsDouble() const {
     return true;
   }
-  static DoubleLoType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static DoubleLoType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                       uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static DoubleLoType* GetInstance();
   static void Destroy();
  private:
-  DoubleLoType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  DoubleLoType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static DoubleLoType* instance_;
 };
 
-class DoubleHiType : public RegType {
+class DoubleHiType : public Cat2Type {
  public:
   std::string Dump() const;
   virtual bool IsDoubleHi() const {
     return true;
   }
-  static DoubleHiType* CreateInstance(mirror::Class* klass, std::string& descriptor,
+  static DoubleHiType* CreateInstance(mirror::Class* klass, const std::string& descriptor,
                                       uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static DoubleHiType* GetInstance();
   static void Destroy();
  private:
-  DoubleHiType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  DoubleHiType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Cat2Type(klass, descriptor, cache_id) {
+  }
   static DoubleHiType* instance_;
 };
 
@@ -560,9 +569,6 @@
  public:
   ConstantType(uint32_t constat, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  inline virtual ~ConstantType() {
-  }
-  const uint32_t constant_;
   // If this is a 32-bit constant, what is the value? This value may be imprecise in which case
   // the value represents part of the integer range of values that may be held in the register.
   virtual int32_t ConstantValue() const;
@@ -590,7 +596,10 @@
            ConstantValue() >= std::numeric_limits<jshort>::min() &&
            ConstantValue() <= std::numeric_limits<jshort>::max();
   }
-  inline virtual bool IsConstantTypes() const { return true; }
+  virtual bool IsConstantTypes() const { return true; }
+
+ private:
+  const uint32_t constant_;
 };
 
 class PreciseConstType : public ConstantType {
@@ -662,147 +671,254 @@
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// Common parent of all uninitialized types. Uninitialized types are created by "new" dex
+// instructions and must be passed to a constructor.
 class UninitializedType : public RegType {
  public:
-  UninitializedType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
-                    uint16_t cache_id);
-  inline virtual ~UninitializedType() {
+  UninitializedType(mirror::Class* klass, const std::string& descriptor, uint32_t allocation_pc,
+                    uint16_t cache_id)
+      : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {
   }
 
+  bool IsUninitializedTypes() const;
+  bool IsNonZeroReferenceTypes() const;
+
   uint32_t GetAllocationPc() const {
     DCHECK(IsUninitializedTypes());
     return allocation_pc_;
   }
-  virtual void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   const uint32_t allocation_pc_;
 };
 
-class UninitialisedReferenceType : public UninitializedType {
+// Similar to ReferenceType but not yet having been passed to a constructor.
+class UninitializedReferenceType : public UninitializedType {
  public:
-  UninitialisedReferenceType(mirror::Class* klass, std::string& descriptor, uint32_t allocation_pc,
-                             uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  UninitializedReferenceType(mirror::Class* klass, const std::string& descriptor,
+                             uint32_t allocation_pc, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
+  }
 
   bool IsUninitializedReference() const {
     return true;
   }
+
+  bool HasClass() const {
+    return true;
+  }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// Similar to UnresolvedReferenceType but not yet having been passed to a constructor.
 class UnresolvedUninitializedRefType : public UninitializedType {
  public:
-  UnresolvedUninitializedRefType(std::string& descriptor, uint32_t allocation_pc,
-                                 uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  UnresolvedUninitializedRefType(const std::string& descriptor, uint32_t allocation_pc,
+                                 uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(NULL, descriptor, allocation_pc, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
   bool IsUnresolvedAndUninitializedReference() const {
     return true;
   }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UninitialisedThisReferenceType : public UninitializedType {
+// Similar to UninitializedReferenceType but special case for the this argument of a constructor.
+class UninitializedThisReferenceType : public UninitializedType {
  public:
-  UninitialisedThisReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  inline virtual bool IsUninitializedThisReference() const {
+  UninitializedThisReferenceType(mirror::Class* klass, const std::string& descriptor,
+                                 uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(klass, descriptor, 0, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
+  virtual bool IsUninitializedThisReference() const {
     return true;
   }
+
+  bool HasClass() const {
+    return true;
+  }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UnresolvedUninitialisedThisRefType : public UninitializedType {
+class UnresolvedUninitializedThisRefType : public UninitializedType {
  public:
-  UnresolvedUninitialisedThisRefType(std::string& descriptor, uint16_t cache_id)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  UnresolvedUninitializedThisRefType(const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : UninitializedType(NULL, descriptor, 0, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
   bool IsUnresolvedAndUninitializedThisReference() const {
     return true;
   }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// A type of register holding a reference to an Object of type GetClass or a sub-class.
 class ReferenceType : public RegType {
  public:
-  ReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
-     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+     : RegType(klass, descriptor, cache_id) {
+  }
+
   bool IsReference() const {
     return true;
   }
+
+  bool IsNonZeroReferenceTypes() const {
+    return true;
+  }
+
+  bool HasClass() const {
+    return true;
+  }
+
   std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
+// A type of register holding a reference to an Object of type GetClass and only an object of that
+// type.
 class PreciseReferenceType : public RegType {
  public:
-  PreciseReferenceType(mirror::Class* klass, std::string& descriptor, uint16_t cache_id)
+  PreciseReferenceType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   bool IsPreciseReference() const {
     return true;
   }
+
+  bool IsNonZeroReferenceTypes() const {
+    return true;
+  }
+
+  bool HasClass() const {
+    return true;
+  }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UnresolvedReferenceType : public RegType {
+// Common parent of unresolved types.
+class UnresolvedType : public RegType {
  public:
-  UnresolvedReferenceType(std::string& descriptor, uint16_t cache_id)
-     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
+  UnresolvedType(const std::string& descriptor, uint16_t cache_id)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : RegType(NULL, descriptor, cache_id) {
   }
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  bool IsNonZeroReferenceTypes() const;
+};
+
+// Similar to ReferenceType except the Class couldn't be loaded. Assignability and other tests made
+// of this type must be conservative.
+class UnresolvedReferenceType : public UnresolvedType {
+ public:
+  UnresolvedReferenceType(const std::string& descriptor, uint16_t cache_id)
+     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : UnresolvedType(descriptor, cache_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
+  }
+
   bool IsUnresolvedReference() const {
     return true;
   }
+
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
-class UnresolvedSuperClass : public RegType {
+// Type representing the super-class of an unresolved type.
+class UnresolvedSuperClass : public UnresolvedType {
  public:
   UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache, uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : RegType(NULL, "", cache_id), unresolved_child_id_(child_id),
+      : UnresolvedType("", cache_id), unresolved_child_id_(child_id),
         reg_type_cache_(reg_type_cache) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
   }
+
   bool IsUnresolvedSuperClass() const {
     return true;
   }
+
   uint16_t GetUnresolvedSuperClassChildId() const {
     DCHECK(IsUnresolvedSuperClass());
     return static_cast<uint16_t>(unresolved_child_id_ & 0xFFFF);
   }
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
  private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const uint16_t unresolved_child_id_;
   const RegTypeCache* const reg_type_cache_;
 };
 
-class UnresolvedMergedType : public RegType {
+// A merge of two unresolved types. If the types were resolved this may be Conflict or another
+// known ReferenceType.
+class UnresolvedMergedType : public UnresolvedType {
  public:
-  UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache, uint16_t cache_id)
+  UnresolvedMergedType(uint16_t left_id, uint16_t right_id, const RegTypeCache* reg_type_cache,
+                       uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : RegType(NULL, "", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+      : UnresolvedType("", cache_id), reg_type_cache_(reg_type_cache) ,merged_types_(left_id, right_id) {
+    if (kIsDebugBuild) {
+      CheckInvariants();
+    }
   }
+
   // The top of a tree of merged types.
   std::pair<uint16_t, uint16_t> GetTopMergedTypes() const {
     DCHECK(IsUnresolvedMergedReference());
     return merged_types_;
   }
+
   // The complete set of merged types.
   std::set<uint16_t> GetMergedTypes() const;
+
   bool IsUnresolvedMergedReference() const {
     return true;
   }
-  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  std::string Dump() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
  private:
+  void CheckInvariants() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const RegTypeCache* const reg_type_cache_;
   const std::pair<uint16_t, uint16_t> merged_types_;
 };
 
 std::ostream& operator<<(std::ostream& os, const RegType& rhs)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 }  // namespace verifier
 }  // namespace art
 
diff --git a/src/verifier/reg_type_cache-inl.h b/src/verifier/reg_type_cache-inl.h
index f6b0056..42474d1 100644
--- a/src/verifier/reg_type_cache-inl.h
+++ b/src/verifier/reg_type_cache-inl.h
@@ -24,7 +24,7 @@
 namespace art {
 namespace verifier {
 template <class Type>
-Type* RegTypeCache::CreatePrimitiveTypeInstance(std::string descriptor) {
+Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) {
   mirror::Class* klass = NULL;
   // Try loading the class from linker.
   if (!descriptor.empty()) {
@@ -35,6 +35,12 @@
   return entry;
 }
 
+inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
+  DCHECK_LT(id, entries_.size());
+  RegType* result = entries_[id];
+  DCHECK(result != NULL);
+  return *result;
+}
 }  // namespace verifier
 }  // namespace art
 #endif  // ART_SRC_VERIFIER_REG_TYPE_CACHE_INL_H_
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index e914d1e..6013250 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -24,13 +24,24 @@
 
 namespace art {
 namespace verifier {
+
 bool RegTypeCache::primitive_initialized_ = false;
 uint16_t RegTypeCache::primitive_start_ = 0;
 uint16_t RegTypeCache::primitive_count_ = 0;
 
 static bool MatchingPrecisionForClass(RegType* entry, bool precise)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return (entry->IsPreciseReference() == precise) || (entry->GetClass()->IsFinal() && !precise);
+  if (entry->IsPreciseReference() == precise) {
+    // We were or weren't looking for a precise reference and we found what we need.
+    return true;
+  } else {
+    if (!precise && entry->GetClass()->CannotBeAssignedFromOtherTypes()) {
+      // We weren't looking for a precise reference, as we're looking up based on a descriptor, but
+      // we found a matching entry based on the descriptor. Return the precise entry in that case.
+      return true;
+    }
+    return false;
+  }
 }
 
 void RegTypeCache::FillPrimitiveTypes() {
@@ -49,9 +60,10 @@
   DCHECK_EQ(entries_.size(), primitive_count_);
 }
 
-const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) {
-  CHECK(RegTypeCache::primitive_initialized_);
-  if (std::string(descriptor).length() == 1) {
+const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, const char* descriptor,
+                                            bool precise) {
+  DCHECK(RegTypeCache::primitive_initialized_);
+  if (descriptor[1] == '\0') {
     switch (descriptor[0]) {
       case 'Z':
         return Boolean();
@@ -80,15 +92,7 @@
   }
 };
 
-const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const {
-  DCHECK_LT(id, entries_.size());
-  RegType* result = entries_[id];
-  DCHECK(result != NULL);
-  return *result;
-}
-
-const RegType& RegTypeCache::RegTypeFromPrimitiveType(
-    Primitive::Type prim_type) const {
+const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
   CHECK(RegTypeCache::primitive_initialized_);
   switch (prim_type) {
     case Primitive::kPrimBoolean:
@@ -113,41 +117,29 @@
   }
 }
 
-bool RegTypeCache::MatchDescriptor(size_t idx, std::string& descriptor, bool precise) {
-  RegType* cur_entry = entries_[idx];
-  if (cur_entry->HasClass()) {
-    // Check the descriptor in the reg_type if available.
-    if(!cur_entry->descriptor_.empty()) {
-      if (descriptor == cur_entry->descriptor_ && MatchingPrecisionForClass(cur_entry, precise)) {
-        return true;
-      }
-    } else {
-      // Descriptor not found in reg_type , maybe available in Class object.
-      // So we might have cases where we have the class but not the descriptor
-      // for that class we need the class helper to get the descriptor
-      // and match it with the one we are given.
-      ClassHelper kh(cur_entry->GetClass());
-      if ((strcmp(descriptor.c_str(), kh.GetDescriptor()) == 0) &&
-          MatchingPrecisionForClass(cur_entry, precise)) {
-        return true;
-      }
-    }
-  } else if (cur_entry->IsUnresolvedReference() && cur_entry->GetDescriptor() == descriptor) {
-    return true;
+bool RegTypeCache::MatchDescriptor(size_t idx, const char* descriptor, bool precise) {
+  RegType* entry = entries_[idx];
+  if (entry->descriptor_ != descriptor) {
+    return false;
   }
-  return false;
+  if (entry->HasClass()) {
+    return MatchingPrecisionForClass(entry, precise);
+  }
+  // There is no notion of precise unresolved references, the precise information is just dropped
+  // on the floor.
+  DCHECK(entry->IsUnresolvedReference());
+  return true;
 }
 
-
-mirror::Class* RegTypeCache::ResolveClass(std::string descriptor, mirror::ClassLoader* loader) {
+mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) {
   // Class was not found, must create new type.
   // Try resolving class
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* klass = NULL;
   if (can_load_classes_) {
-    klass = class_linker->FindClass(descriptor.c_str(), loader);
+    klass = class_linker->FindClass(descriptor, loader);
   } else {
-    klass = class_linker->LookupClass(descriptor.c_str(), loader);
+    klass = class_linker->LookupClass(descriptor, loader);
     if (klass != NULL && !klass->IsLoaded()) {
       // We found the class but without it being loaded its not safe for use.
       klass = NULL;
@@ -155,6 +147,7 @@
   }
   return klass;
 }
+
 void RegTypeCache::ClearException() {
   if (can_load_classes_) {
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -163,8 +156,9 @@
     DCHECK(!Thread::Current()->IsExceptionPending());
   }
 }
-const RegType& RegTypeCache::From(mirror::ClassLoader* loader, std::string descriptor, bool precise) {
 
+const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descriptor,
+                                  bool precise) {
   // Try looking up the class in the cache first.
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
     if (MatchDescriptor(i, descriptor, precise)) {
@@ -185,7 +179,7 @@
     // 2- Precise Flag passed as true.
     RegType* entry;
     // Create an imprecise type if we can't tell for a fact that it is precise.
-    if ((klass->IsFinal()) || precise) {
+    if (klass->CannotBeAssignedFromOtherTypes() || precise) {
       DCHECK(!(klass->IsAbstract()) || klass->IsArrayClass());
       DCHECK(!klass->IsInterface());
       entry = new PreciseReferenceType(klass, descriptor, entries_.size());
@@ -198,7 +192,7 @@
     // We tried loading the class and failed, this might get an exception raised
     // so we want to clear it before we go on.
     ClearException();
-    if (IsValidDescriptor(descriptor.c_str())) {
+    if (IsValidDescriptor(descriptor)) {
       RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
       entries_.push_back(entry);
       return *entry;
@@ -209,25 +203,26 @@
     }
   }
 }
-const RegType& RegTypeCache::FromClass(mirror::Class* klass, bool precise) {
+
+const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
   if (klass->IsPrimitive()) {
+    // Note: precise isn't used for primitive classes. A char is assignable to an int. All
+    // primitive classes are final.
     return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
   } else {
     // Look for the reference in the list of entries to have.
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if ((cur_entry->HasClass()) && cur_entry->GetClass() == klass &&
-          MatchingPrecisionForClass(cur_entry, precise)) {
+      if (cur_entry->klass_ == klass && MatchingPrecisionForClass(cur_entry, precise)) {
         return *cur_entry;
       }
     }
     // No reference to the class was found, create new reference.
     RegType* entry;
-    std::string empty = "";
     if (precise) {
-      entry = new PreciseReferenceType(klass, empty, entries_.size());
+      entry = new PreciseReferenceType(klass, descriptor, entries_.size());
     } else {
-      entry = new ReferenceType(klass, empty, entries_.size());
+      entry = new ReferenceType(klass, descriptor, entries_.size());
     }
     entries_.push_back(entry);
     return *entry;
@@ -309,13 +304,14 @@
   // Create entry.
   RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size());
   entries_.push_back(entry);
-#ifndef NDEBUG
-  UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
-  std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
-  CHECK(check_types == types);
-#endif
+  if (kIsDebugBuild) {
+    UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
+    std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
+    CHECK(check_types == types);
+  }
   return *entry;
 }
+
 const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
   // Check if entry already exists.
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
@@ -334,11 +330,12 @@
   entries_.push_back(entry);
   return *entry;
 }
+
 const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
   RegType* entry = NULL;
   RegType* cur_entry = NULL;
+  const std::string& descriptor(type.GetDescriptor());
   if (type.IsUnresolvedTypes()) {
-    std::string descriptor(type.GetDescriptor());
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedReference() &&
@@ -353,23 +350,23 @@
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       cur_entry = entries_[i];
       if (cur_entry->IsUninitializedReference() &&
-          down_cast<UninitialisedReferenceType*>(cur_entry)
+          down_cast<UninitializedReferenceType*>(cur_entry)
               ->GetAllocationPc() == allocation_pc &&
           cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    std::string descriptor("");
-    entry = new UninitialisedReferenceType(klass, descriptor, allocation_pc, entries_.size());
+    entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
+
 const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
   RegType* entry;
 
   if (uninit_type.IsUnresolvedTypes()) {
-    std::string descriptor(uninit_type.GetDescriptor());
+    const std::string& descriptor(uninit_type.GetDescriptor());
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedReference() &&
@@ -377,63 +374,52 @@
         return *cur_entry;
       }
     }
-    entry = new UnresolvedReferenceType(descriptor, entries_.size());
+    entry = new UnresolvedReferenceType(descriptor.c_str(), entries_.size());
   } else {
     mirror::Class* klass = uninit_type.GetClass();
     if(uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
-      // For uninitialized this reference look for reference types that are not precise.
+      // For uninitialized "this reference" look for reference types that are not precise.
       for (size_t i = primitive_count_; i < entries_.size(); i++) {
         RegType* cur_entry = entries_[i];
         if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
           return *cur_entry;
         }
       }
-      std::string descriptor("");
-      entry = new ReferenceType(klass, descriptor, entries_.size());
-    } else {
-        std::string descriptor;
-        if (klass->IsFinal()) {
-          if (klass->IsInstantiable()) {
-            for (size_t i = primitive_count_; i < entries_.size(); i++) {
-              RegType* cur_entry = entries_[i];
-              if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
-                return *cur_entry;
-              }
-            }
-            // Precise type was not found , create one !
-            entry = new PreciseReferenceType(klass, descriptor, entries_.size());
-          } else {
-            return Conflict();
-          }
-      } else {
-        // Not a final class, create an imprecise reference. Look up if we have it in the cache first.
-        for (size_t i = primitive_count_; i < entries_.size(); i++) {
-          RegType* cur_entry = entries_[i];
-          if (cur_entry->IsReference() && !(cur_entry->IsPrecise()) &&
-              cur_entry->GetClass() == klass) {
-            return *cur_entry;
-          }
+      entry = new ReferenceType(klass, "", entries_.size());
+    } else if (klass->IsInstantiable()) {
+      // We're uninitialized because of allocation, look or create a precise type as allocations
+      // may only create objects of that type.
+      for (size_t i = primitive_count_; i < entries_.size(); i++) {
+        RegType* cur_entry = entries_[i];
+        if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
+          return *cur_entry;
         }
-        entry = new ReferenceType(klass, descriptor, entries_.size());
       }
+      entry = new PreciseReferenceType(klass, uninit_type.GetDescriptor(), entries_.size());
+    } else {
+      return Conflict();
     }
  }
   entries_.push_back(entry);
   return *entry;
 }
-const RegType& RegTypeCache::ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::ByteConstant() {
   return FromCat1Const(std::numeric_limits<jbyte>::min(), false);
 }
-const RegType& RegTypeCache::ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::ShortConstant() {
   return FromCat1Const(std::numeric_limits<jshort>::min(), false);
 }
-const RegType& RegTypeCache::IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+const RegType& RegTypeCache::IntConstant() {
   return FromCat1Const(std::numeric_limits<jint>::max(), false);
 }
+
 const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
   RegType* entry;
+  const std::string& descriptor(type.GetDescriptor());
   if (type.IsUnresolvedTypes()) {
-    std::string descriptor(type.GetDescriptor());
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
@@ -441,26 +427,26 @@
         return *cur_entry;
       }
     }
-    entry = new UnresolvedUninitialisedThisRefType(descriptor, entries_.size());
+    entry = new UnresolvedUninitializedThisRefType(descriptor, entries_.size());
   } else {
     mirror::Class* klass = type.GetClass();
     for (size_t i = primitive_count_; i < entries_.size(); i++) {
       RegType* cur_entry = entries_[i];
-      if (cur_entry->IsUninitializedThisReference() &&
-          cur_entry->GetClass() == klass) {
+      if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
         return *cur_entry;
       }
     }
-    std::string descriptor("");
-    entry = new UninitialisedThisReferenceType(klass, descriptor, entries_.size());
+    entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size());
   }
   entries_.push_back(entry);
   return *entry;
 }
+
 const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) {
   for (size_t i = primitive_count_; i < entries_.size(); i++) {
     RegType* cur_entry = entries_[i];
-    if (cur_entry->IsConstant() && cur_entry->IsPreciseConstant() == precise &&
+    if (cur_entry->klass_ == NULL && cur_entry->IsConstant() &&
+        cur_entry->IsPreciseConstant() == precise &&
         (down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) {
       return *cur_entry;
     }
@@ -514,12 +500,13 @@
 const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::ClassLoader* loader) {
   CHECK(array.IsArrayTypes());
   if (array.IsUnresolvedTypes()) {
-    std::string descriptor(array.GetDescriptor());
-    std::string component(descriptor.substr(1, descriptor.size() - 1));
+    const std::string& descriptor(array.GetDescriptor());
+    const std::string component(descriptor.substr(1, descriptor.size() - 1));
     return FromDescriptor(loader, component.c_str(), false);
   } else {
     mirror::Class* klass = array.GetClass()->GetComponentType();
-    return FromClass(klass, klass->IsFinal());
+    return FromClass(ClassHelper(klass).GetDescriptor(), klass,
+                     klass->CannotBeAssignedFromOtherTypes());
   }
 }
 
diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h
index 602c950..d70123c 100644
--- a/src/verifier/reg_type_cache.h
+++ b/src/verifier/reg_type_cache.h
@@ -39,6 +39,7 @@
 class RegTypeCache {
  public:
   explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) {
+    entries_.reserve(64);
     FillPrimitiveTypes();
   }
   ~RegTypeCache();
@@ -52,13 +53,13 @@
   }
   static void ShutDown();
   const art::verifier::RegType& GetFromId(uint16_t id) const;
-  const RegType& From(mirror::ClassLoader* loader, std::string descriptor, bool precise)
+  const RegType& From(mirror::ClassLoader* loader, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template <class Type>
-  static Type* CreatePrimitiveTypeInstance(std::string descriptor)
+  static Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void FillPrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const RegType& FromClass(mirror::Class* klass, bool precise)
+  const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& FromCat1Const(int32_t value, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -152,10 +153,10 @@
   // Whether or not we're allowed to load classes.
   const bool can_load_classes_;
   DISALLOW_COPY_AND_ASSIGN(RegTypeCache);
-  mirror::Class* ResolveClass(std::string descriptor, mirror::ClassLoader* loader)
+  mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ClearException();
-  bool MatchDescriptor(size_t idx, std::string& descriptor, bool precise)
+  bool MatchDescriptor(size_t idx, const char* descriptor, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 };
 
diff --git a/src/verifier/reg_type_test.cc b/src/verifier/reg_type_test.cc
index 9b46a7f..f37edff 100644
--- a/src/verifier/reg_type_test.cc
+++ b/src/verifier/reg_type_test.cc
@@ -74,7 +74,6 @@
 }
 
 TEST_F(RegTypeTest, Primitives) {
-
   ScopedObjectAccess soa(Thread::Current());
   RegTypeCache cache(true);
 
@@ -108,6 +107,7 @@
   EXPECT_FALSE(bool_reg_type.IsLongTypes());
   EXPECT_FALSE(bool_reg_type.IsDoubleTypes());
   EXPECT_TRUE(bool_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(bool_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& byte_reg_type = cache.Byte();
   EXPECT_FALSE(byte_reg_type.IsUndefined());
@@ -139,6 +139,7 @@
   EXPECT_FALSE(byte_reg_type.IsLongTypes());
   EXPECT_FALSE(byte_reg_type.IsDoubleTypes());
   EXPECT_TRUE(byte_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(byte_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& char_reg_type = cache.Char();
   EXPECT_FALSE(char_reg_type.IsUndefined());
@@ -170,6 +171,7 @@
   EXPECT_FALSE(char_reg_type.IsLongTypes());
   EXPECT_FALSE(char_reg_type.IsDoubleTypes());
   EXPECT_TRUE(char_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(char_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& short_reg_type = cache.Short();
   EXPECT_FALSE(short_reg_type.IsUndefined());
@@ -201,6 +203,7 @@
   EXPECT_FALSE(short_reg_type.IsLongTypes());
   EXPECT_FALSE(short_reg_type.IsDoubleTypes());
   EXPECT_TRUE(short_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(short_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& int_reg_type = cache.Integer();
   EXPECT_FALSE(int_reg_type.IsUndefined());
@@ -232,6 +235,7 @@
   EXPECT_FALSE(int_reg_type.IsLongTypes());
   EXPECT_FALSE(int_reg_type.IsDoubleTypes());
   EXPECT_TRUE(int_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(int_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& long_reg_type = cache.LongLo();
   EXPECT_FALSE(long_reg_type.IsUndefined());
@@ -263,6 +267,7 @@
   EXPECT_TRUE(long_reg_type.IsLongTypes());
   EXPECT_FALSE(long_reg_type.IsDoubleTypes());
   EXPECT_FALSE(long_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(long_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& float_reg_type = cache.Float();
   EXPECT_FALSE(float_reg_type.IsUndefined());
@@ -294,6 +299,7 @@
   EXPECT_FALSE(float_reg_type.IsLongTypes());
   EXPECT_FALSE(float_reg_type.IsDoubleTypes());
   EXPECT_FALSE(float_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(float_reg_type.IsNonZeroReferenceTypes());
 
   const RegType& double_reg_type = cache.DoubleLo();
   EXPECT_FALSE(double_reg_type.IsUndefined());
@@ -325,6 +331,7 @@
   EXPECT_FALSE(double_reg_type.IsLongTypes());
   EXPECT_TRUE(double_reg_type.IsDoubleTypes());
   EXPECT_FALSE(double_reg_type.IsArrayIndexTypes());
+  EXPECT_FALSE(double_reg_type.IsNonZeroReferenceTypes());
 }
 
 
@@ -352,12 +359,14 @@
   RegTypeCache cache(true);
   const RegType& ref_type_0 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
   EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
+  EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes());
 
   const RegType& ref_type_1 = cache.FromDescriptor(NULL, "Ljava/lang/DoesNotExist;", true);
   EXPECT_TRUE(ref_type_0.Equals(ref_type_1));
 
   const RegType& unresolved_super_class =  cache.FromUnresolvedSuperClass(ref_type_0);
   EXPECT_TRUE(unresolved_super_class.IsUnresolvedSuperClass());
+  EXPECT_TRUE(unresolved_super_class.IsNonZeroReferenceTypes());
 }
 
 TEST_F(RegTypeReferenceTest, UnresolvedUnintializedType) {
@@ -372,6 +381,7 @@
   const RegType& unresolved_unintialised = cache.Uninitialized(ref_type, 1101ull);
   EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
   EXPECT_TRUE(unresolved_unintialised.IsUninitializedTypes());
+  EXPECT_TRUE(unresolved_unintialised.IsNonZeroReferenceTypes());
   // Create an uninitialized type of this unresolved type with different  PC
   const RegType& ref_type_unresolved_unintialised_1 =  cache.Uninitialized(ref_type, 1102ull);
   EXPECT_TRUE(unresolved_unintialised.IsUnresolvedAndUninitializedReference());
diff --git a/src/verifier/register_line-inl.h b/src/verifier/register_line-inl.h
new file mode 100644
index 0000000..157e136
--- /dev/null
+++ b/src/verifier/register_line-inl.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
+#define ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
+
+#include "register_line.h"
+#include "method_verifier.h"
+
+namespace art {
+namespace verifier {
+
+inline const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
+  // The register index was validated during the static pass, so we don't need to check it here.
+  DCHECK_LT(vsrc, num_regs_);
+  return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
+}
+
+}  // namespace verifier
+}  // namespace art
+
+#endif  // ART_SRC_VERIFIER_REGISTER_LINE_INL_H_
diff --git a/src/verifier/register_line.cc b/src/verifier/register_line.cc
index 544a9ee..3a2145b9 100644
--- a/src/verifier/register_line.cc
+++ b/src/verifier/register_line.cc
@@ -16,7 +16,9 @@
 
 #include "register_line.h"
 
+#include "dex_instruction-inl.h"
 #include "method_verifier.h"
+#include "register_line-inl.h"
 
 namespace art {
 namespace verifier {
@@ -92,22 +94,18 @@
   result_[1] = new_type2.GetId();
 }
 
-const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
-  // The register index was validated during the static pass, so we don't need to check it here.
-  DCHECK_LT(vsrc, num_regs_);
-  return verifier_->GetRegTypeCache()->GetFromId(line_[vsrc]);
-}
-
-const RegType& RegisterLine::GetInvocationThis(const DecodedInstruction& dec_insn) {
-  if (dec_insn.vA < 1) {
+const RegType& RegisterLine::GetInvocationThis(const Instruction* inst, bool is_range) {
+  const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
+  if (args_count < 1) {
     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
     return verifier_->GetRegTypeCache()->Conflict();
   }
   /* get the element type of the array held in vsrc */
-  const RegType& this_type = GetRegisterType(dec_insn.vC);
+  const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+  const RegType& this_type = GetRegisterType(this_reg);
   if (!this_type.IsReferenceTypes()) {
     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "tried to get class from non-reference register v"
-                                                 << dec_insn.vC << " (type=" << this_type << ")";
+                                                 << this_reg << " (type=" << this_type << ")";
     return verifier_->GetRegTypeCache()->Conflict();
   }
   return this_type;
@@ -260,125 +258,135 @@
   }
 }
 
-void RegisterLine::CheckUnaryOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOp(const Instruction* inst,
                                 const RegType& dst_type,
                                 const RegType& src_type) {
-  if (VerifyRegisterType(dec_insn.vB, src_type)) {
-    SetRegisterType(dec_insn.vA, dst_type);
+  if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
+    SetRegisterType(inst->VRegA_12x(), dst_type);
   }
 }
 
-void RegisterLine::CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpWide(const Instruction* inst,
                                     const RegType& dst_type1, const RegType& dst_type2,
                                     const RegType& src_type1, const RegType& src_type2) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
+    SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpToWide(const Instruction* inst,
                                       const RegType& dst_type1, const RegType& dst_type2,
                                       const RegType& src_type) {
-  if (VerifyRegisterType(dec_insn.vB, src_type)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  if (VerifyRegisterType(inst->VRegB_12x(), src_type)) {
+    SetRegisterTypeWide(inst->VRegA_12x(), dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckUnaryOpFromWide(const Instruction* inst,
                                         const RegType& dst_type,
                                         const RegType& src_type1, const RegType& src_type2) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
-    SetRegisterType(dec_insn.vA, dst_type);
+  if (VerifyRegisterTypeWide(inst->VRegB_12x(), src_type1, src_type2)) {
+    SetRegisterType(inst->VRegA_12x(), dst_type);
   }
 }
 
-void RegisterLine::CheckBinaryOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp(const Instruction* inst,
                                  const RegType& dst_type,
                                  const RegType& src_type1, const RegType& src_type2,
                                  bool check_boolean_op) {
-  if (VerifyRegisterType(dec_insn.vB, src_type1) &&
-      VerifyRegisterType(dec_insn.vC, src_type2)) {
+  const uint32_t vregB = inst->VRegB_23x();
+  const uint32_t vregC = inst->VRegC_23x();
+  if (VerifyRegisterType(vregB, src_type1) &&
+      VerifyRegisterType(vregC, src_type2)) {
     if (check_boolean_op) {
       DCHECK(dst_type.IsInteger());
-      if (GetRegisterType(dec_insn.vB).IsBooleanTypes() &&
-          GetRegisterType(dec_insn.vC).IsBooleanTypes()) {
-        SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+      if (GetRegisterType(vregB).IsBooleanTypes() &&
+          GetRegisterType(vregC).IsBooleanTypes()) {
+        SetRegisterType(inst->VRegA_23x(), verifier_->GetRegTypeCache()->Boolean());
         return;
       }
     }
-    SetRegisterType(dec_insn.vA, dst_type);
+    SetRegisterType(inst->VRegA_23x(), dst_type);
   }
 }
 
-void RegisterLine::CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOpWide(const Instruction* inst,
                                      const RegType& dst_type1, const RegType& dst_type2,
                                      const RegType& src_type1_1, const RegType& src_type1_2,
                                      const RegType& src_type2_1, const RegType& src_type2_2) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, src_type1_1, src_type1_2) &&
-      VerifyRegisterTypeWide(dec_insn.vC, src_type2_1, src_type2_2)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  if (VerifyRegisterTypeWide(inst->VRegB_23x(), src_type1_1, src_type1_2) &&
+      VerifyRegisterTypeWide(inst->VRegC_23x(), src_type2_1, src_type2_2)) {
+    SetRegisterTypeWide(inst->VRegA_23x(), dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOpWideShift(const Instruction* inst,
                                           const RegType& long_lo_type, const RegType& long_hi_type,
                                           const RegType& int_type) {
-  if (VerifyRegisterTypeWide(dec_insn.vB, long_lo_type, long_hi_type) &&
-      VerifyRegisterType(dec_insn.vC, int_type)) {
-    SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+  if (VerifyRegisterTypeWide(inst->VRegB_23x(), long_lo_type, long_hi_type) &&
+      VerifyRegisterType(inst->VRegC_23x(), int_type)) {
+    SetRegisterTypeWide(inst->VRegA_23x(), long_lo_type, long_hi_type);
   }
 }
 
-void RegisterLine::CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addr(const Instruction* inst,
                                       const RegType& dst_type, const RegType& src_type1,
                                       const RegType& src_type2, bool check_boolean_op) {
-  if (VerifyRegisterType(dec_insn.vA, src_type1) &&
-      VerifyRegisterType(dec_insn.vB, src_type2)) {
+  const uint32_t vregA = inst->VRegA_12x();
+  const uint32_t vregB = inst->VRegB_12x();
+  if (VerifyRegisterType(vregA, src_type1) &&
+      VerifyRegisterType(vregB, src_type2)) {
     if (check_boolean_op) {
       DCHECK(dst_type.IsInteger());
-      if (GetRegisterType(dec_insn.vA).IsBooleanTypes() &&
-          GetRegisterType(dec_insn.vB).IsBooleanTypes()) {
-        SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+      if (GetRegisterType(vregA).IsBooleanTypes() &&
+          GetRegisterType(vregB).IsBooleanTypes()) {
+        SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
         return;
       }
     }
-    SetRegisterType(dec_insn.vA, dst_type);
+    SetRegisterType(vregA, dst_type);
   }
 }
 
-void RegisterLine::CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addrWide(const Instruction* inst,
                                           const RegType& dst_type1, const RegType& dst_type2,
                                           const RegType& src_type1_1, const RegType& src_type1_2,
                                           const RegType& src_type2_1, const RegType& src_type2_2) {
-  if (VerifyRegisterTypeWide(dec_insn.vA, src_type1_1, src_type1_2) &&
-      VerifyRegisterTypeWide(dec_insn.vB, src_type2_1, src_type2_2)) {
-    SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+  const uint32_t vregA = inst->VRegA_12x();
+  const uint32_t vregB = inst->VRegB_12x();
+  if (VerifyRegisterTypeWide(vregA, src_type1_1, src_type1_2) &&
+      VerifyRegisterTypeWide(vregB, src_type2_1, src_type2_2)) {
+    SetRegisterTypeWide(vregA, dst_type1, dst_type2);
   }
 }
 
-void RegisterLine::CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckBinaryOp2addrWideShift(const Instruction* inst,
                                                const RegType& long_lo_type, const RegType& long_hi_type,
                                                const RegType& int_type) {
-  if (VerifyRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type) &&
-      VerifyRegisterType(dec_insn.vB, int_type)) {
-    SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+  const uint32_t vregA = inst->VRegA_12x();
+  const uint32_t vregB = inst->VRegB_12x();
+  if (VerifyRegisterTypeWide(vregA, long_lo_type, long_hi_type) &&
+      VerifyRegisterType(vregB, int_type)) {
+    SetRegisterTypeWide(vregA, long_lo_type, long_hi_type);
   }
 }
 
-void RegisterLine::CheckLiteralOp(const DecodedInstruction& dec_insn,
+void RegisterLine::CheckLiteralOp(const Instruction* inst,
                                   const RegType& dst_type, const RegType& src_type,
-                                  bool check_boolean_op) {
-  if (VerifyRegisterType(dec_insn.vB, src_type)) {
+                                  bool check_boolean_op, bool is_lit16) {
+  const uint32_t vregA = is_lit16 ? inst->VRegA_22s() : inst->VRegA_22b();
+  const uint32_t vregB = is_lit16 ? inst->VRegB_22s() : inst->VRegB_22b();
+  if (VerifyRegisterType(vregB, src_type)) {
     if (check_boolean_op) {
       DCHECK(dst_type.IsInteger());
       /* check vB with the call, then check the constant manually */
-      if (GetRegisterType(dec_insn.vB).IsBooleanTypes() &&
-          (dec_insn.vC == 0 || dec_insn.vC == 1)) {
-        SetRegisterType(dec_insn.vA, verifier_->GetRegTypeCache()->Boolean());
+      const uint32_t val = is_lit16 ? inst->VRegC_22s() : inst->VRegC_22b();
+      if (GetRegisterType(vregB).IsBooleanTypes() && (val == 0 || val == 1)) {
+        SetRegisterType(vregA, verifier_->GetRegTypeCache()->Boolean());
         return;
       }
     }
-    SetRegisterType(dec_insn.vA, dst_type);
+    SetRegisterType(vregA, dst_type);
   }
 }
 
@@ -427,6 +435,8 @@
 
 bool RegisterLine::MergeRegisters(const RegisterLine* incoming_line) {
   bool changed = false;
+  CHECK(NULL != incoming_line);
+  CHECK(NULL != line_.get());
   for (size_t idx = 0; idx < num_regs_; idx++) {
     if (line_[idx] != incoming_line->line_[idx]) {
       const RegType& incoming_reg_type = incoming_line->GetRegisterType(idx);
diff --git a/src/verifier/register_line.h b/src/verifier/register_line.h
index 5719082..5f17049 100644
--- a/src/verifier/register_line.h
+++ b/src/verifier/register_line.h
@@ -169,28 +169,28 @@
    * The argument count is in vA, and the first argument is in vC, for both "simple" and "range"
    * versions. We just need to make sure vA is >= 1 and then return vC.
    */
-  const RegType& GetInvocationThis(const DecodedInstruction& dec_insn)
+  const RegType& GetInvocationThis(const Instruction* inst, bool is_range)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
    * Verify types for a simple two-register instruction (e.g. "neg-int").
    * "dst_type" is stored into vA, and "src_type" is verified against vB.
    */
-  void CheckUnaryOp(const DecodedInstruction& dec_insn,
-                    const RegType& dst_type, const RegType& src_type)
+  void CheckUnaryOp(const Instruction* inst, const RegType& dst_type,
+                    const RegType& src_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+  void CheckUnaryOpWide(const Instruction* inst,
                         const RegType& dst_type1, const RegType& dst_type2,
                         const RegType& src_type1, const RegType& src_type2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+  void CheckUnaryOpToWide(const Instruction* inst,
                           const RegType& dst_type1, const RegType& dst_type2,
                           const RegType& src_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+  void CheckUnaryOpFromWide(const Instruction* inst,
                             const RegType& dst_type,
                             const RegType& src_type1, const RegType& src_type2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -200,18 +200,18 @@
    * "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
    * against vB/vC.
    */
-  void CheckBinaryOp(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp(const Instruction* inst,
                      const RegType& dst_type, const RegType& src_type1, const RegType& src_type2,
                      bool check_boolean_op)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+  void CheckBinaryOpWide(const Instruction* inst,
                          const RegType& dst_type1, const RegType& dst_type2,
                          const RegType& src_type1_1, const RegType& src_type1_2,
                          const RegType& src_type2_1, const RegType& src_type2_2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+  void CheckBinaryOpWideShift(const Instruction* inst,
                               const RegType& long_lo_type, const RegType& long_hi_type,
                               const RegType& int_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -220,19 +220,19 @@
    * Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
    * are verified against vA/vB, then "dst_type" is stored into vA.
    */
-  void CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp2addr(const Instruction* inst,
                           const RegType& dst_type,
                           const RegType& src_type1, const RegType& src_type2,
                           bool check_boolean_op)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp2addrWide(const Instruction* inst,
                               const RegType& dst_type1, const RegType& dst_type2,
                               const RegType& src_type1_1, const RegType& src_type1_2,
                               const RegType& src_type2_1, const RegType& src_type2_2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+  void CheckBinaryOp2addrWideShift(const Instruction* inst,
                                    const RegType& long_lo_type, const RegType& long_hi_type,
                                    const RegType& int_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -243,8 +243,9 @@
    *
    * If "check_boolean_op" is set, we use the constant value in vC.
    */
-  void CheckLiteralOp(const DecodedInstruction& dec_insn,
-                      const RegType& dst_type, const RegType& src_type, bool check_boolean_op)
+  void CheckLiteralOp(const Instruction* inst,
+                      const RegType& dst_type, const RegType& src_type,
+                      bool check_boolean_op, bool is_lit16)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Verify/push monitor onto the monitor stack, locking the value in reg_idx at location insn_idx.
diff --git a/src/well_known_classes.cc b/src/well_known_classes.cc
index f836f4f..4d34c73 100644
--- a/src/well_known_classes.cc
+++ b/src/well_known_classes.cc
@@ -77,7 +77,7 @@
 jfieldID WellKnownClasses::java_lang_Thread_name;
 jfieldID WellKnownClasses::java_lang_Thread_priority;
 jfieldID WellKnownClasses::java_lang_Thread_uncaughtHandler;
-jfieldID WellKnownClasses::java_lang_Thread_vmData;
+jfieldID WellKnownClasses::java_lang_Thread_nativePeer;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_name;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup;
@@ -172,7 +172,7 @@
   java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;");
   java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I");
   java_lang_Thread_uncaughtHandler = CacheField(env, java_lang_Thread, false, "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;");
-  java_lang_Thread_vmData = CacheField(env, java_lang_Thread, false, "vmData", "I");
+  java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "I");
   java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
   java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;");
   java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;");
diff --git a/src/well_known_classes.h b/src/well_known_classes.h
index d9acf2d..8170520 100644
--- a/src/well_known_classes.h
+++ b/src/well_known_classes.h
@@ -90,7 +90,7 @@
   static jfieldID java_lang_Thread_name;
   static jfieldID java_lang_Thread_priority;
   static jfieldID java_lang_Thread_uncaughtHandler;
-  static jfieldID java_lang_Thread_vmData;
+  static jfieldID java_lang_Thread_nativePeer;
   static jfieldID java_lang_ThreadGroup_mainThreadGroup;
   static jfieldID java_lang_ThreadGroup_name;
   static jfieldID java_lang_ThreadGroup_systemThreadGroup;
diff --git a/test/031-class-attributes/expected.txt b/test/031-class-attributes/expected.txt
index afa3416..4ae1eed 100644
--- a/test/031-class-attributes/expected.txt
+++ b/test/031-class-attributes/expected.txt
@@ -1,3 +1,25 @@
+public abstract final int
+public abstract final [I
+public java.lang.Object
+public abstract final [Ljava.lang.Object;
+public ClassAttrs$PublicInnerClass
+public abstract final [LClassAttrs$PublicInnerClass;
+protected ClassAttrs$ProtectedInnerClass
+protected abstract final [LClassAttrs$ProtectedInnerClass;
+private ClassAttrs$PrivateInnerClass
+private abstract final [LClassAttrs$PrivateInnerClass;
+ ClassAttrs$PackagePrivateInnerClass
+abstract final [LClassAttrs$PackagePrivateInnerClass;
+public abstract interface java.io.Serializable
+public abstract final [Ljava.io.Serializable;
+public abstract static interface ClassAttrs$PublicInnerInterface
+public abstract final [LClassAttrs$PublicInnerInterface;
+protected abstract static interface ClassAttrs$ProtectedInnerInterface
+protected abstract final [LClassAttrs$ProtectedInnerInterface;
+private abstract static interface ClassAttrs$PrivateInnerInterface
+private abstract final [LClassAttrs$PrivateInnerInterface;
+abstract static interface ClassAttrs$PackagePrivateInnerInterface
+abstract final [LClassAttrs$PackagePrivateInnerInterface;
 ***** class ClassAttrs:
   name: ClassAttrs
   canonical: ClassAttrs
@@ -11,8 +33,8 @@
   enclosingMeth: null
   modifiers: 1
   package: null
-  declaredClasses: [2] class ClassAttrs$PublicMemberClass, class ClassAttrs$MemberClass
-  member classes: [1] class ClassAttrs$PublicMemberClass
+  declaredClasses: [10] class ClassAttrs$PublicMemberClass, class ClassAttrs$MemberClass, interface ClassAttrs$PackagePrivateInnerInterface, interface ClassAttrs$PrivateInnerInterface, interface ClassAttrs$ProtectedInnerInterface, interface ClassAttrs$PublicInnerInterface, class ClassAttrs$PackagePrivateInnerClass, class ClassAttrs$PrivateInnerClass, class ClassAttrs$ProtectedInnerClass, class ClassAttrs$PublicInnerClass
+  member classes: [3] class ClassAttrs$PublicMemberClass, interface ClassAttrs$PublicInnerInterface, class ClassAttrs$PublicInnerClass
   isAnnotation: false
   isAnonymous: false
   isArray: false
diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java
index 8719e3b..ae8b2f5 100644
--- a/test/031-class-attributes/src/ClassAttrs.java
+++ b/test/031-class-attributes/src/ClassAttrs.java
@@ -1,10 +1,12 @@
 import otherpackage.OtherPackageClass;
 
+import java.io.Serializable;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 
@@ -21,7 +23,72 @@
         cinner.showMe();
     }
 
+    public class PublicInnerClass {
+    }
+
+    protected class ProtectedInnerClass {
+    }
+
+    private class PrivateInnerClass {
+    }
+
+    class PackagePrivateInnerClass {
+    }
+
+    public interface PublicInnerInterface {
+    }
+
+    protected interface ProtectedInnerInterface {
+    }
+
+    private interface PrivateInnerInterface {
+    }
+
+    interface PackagePrivateInnerInterface {
+    }
+
+    private static void showModifiers(Class<?> c) {
+        System.out.println(Modifier.toString(c.getModifiers()) + " " + c.getName());
+    }
+
+    // https://code.google.com/p/android/issues/detail?id=56267
+    private static void test56267() {
+        // Primitive classes.
+        showModifiers(int.class);
+        showModifiers(int[].class);
+
+        // Regular classes.
+        showModifiers(Object.class);
+        showModifiers(Object[].class);
+
+        // Inner classes.
+        showModifiers(PublicInnerClass.class);
+        showModifiers(PublicInnerClass[].class);
+        showModifiers(ProtectedInnerClass.class);
+        showModifiers(ProtectedInnerClass[].class);
+        showModifiers(PrivateInnerClass.class);
+        showModifiers(PrivateInnerClass[].class);
+        showModifiers(PackagePrivateInnerClass.class);
+        showModifiers(PackagePrivateInnerClass[].class);
+
+        // Regular interfaces.
+        showModifiers(Serializable.class);
+        showModifiers(Serializable[].class);
+
+        // Inner interfaces.
+        showModifiers(PublicInnerInterface.class);
+        showModifiers(PublicInnerInterface[].class);
+        showModifiers(ProtectedInnerInterface.class);
+        showModifiers(ProtectedInnerInterface[].class);
+        showModifiers(PrivateInnerInterface.class);
+        showModifiers(PrivateInnerInterface[].class);
+        showModifiers(PackagePrivateInnerInterface.class);
+        showModifiers(PackagePrivateInnerInterface[].class);
+    }
+
     public static void main() {
+        test56267();
+
         printClassAttrs(ClassAttrs.class);
         printClassAttrs(OtherClass.class);
         printClassAttrs(OtherPackageClass.class);
diff --git a/test/045-reflect-array/expected.txt b/test/045-reflect-array/expected.txt
index 5990b34..b9a98c9 100644
--- a/test/045-reflect-array/expected.txt
+++ b/test/045-reflect-array/expected.txt
@@ -6,4 +6,7 @@
 ReflectArrayTest.testMultiInt passed
 zero one two ++
 ReflectArrayTest.testMulti passed
+class [Ljava.lang.Number; modifiers: 1041
+class [Ljava.lang.Cloneable; modifiers: 1041
+ReflectArrayTest.testAbstract passed
 ReflectArrayTest passed
diff --git a/test/045-reflect-array/src/Main.java b/test/045-reflect-array/src/Main.java
index 05cf843..7418eed8 100644
--- a/test/045-reflect-array/src/Main.java
+++ b/test/045-reflect-array/src/Main.java
@@ -16,6 +16,7 @@
         testSingle();
         testMultiInt();
         testMulti();
+        testAbstract();
 
         System.out.println("ReflectArrayTest passed");
     }
@@ -255,4 +256,14 @@
         }
         System.out.println("ReflectArrayTest.testMulti passed");
     }
+
+    static void testAbstract() {
+        Object arrayOfAbstractClasses = Array.newInstance(Number.class, 1);
+        System.out.println(arrayOfAbstractClasses.getClass().toString() + " modifiers: " +
+                           arrayOfAbstractClasses.getClass().getModifiers());
+        arrayOfAbstractClasses = Array.newInstance(Cloneable.class, 1);
+        System.out.println(arrayOfAbstractClasses.getClass().toString() + " modifiers: " +
+                           arrayOfAbstractClasses.getClass().getModifiers());
+        System.out.println("ReflectArrayTest.testAbstract passed");
+    }
 }
diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt
index 0c567d4..f56fd98 100644
--- a/test/100-reflect2/expected.txt
+++ b/test/100-reflect2/expected.txt
@@ -34,7 +34,7 @@
 30 (class java.lang.Integer)
 62 (class java.lang.Long)
 14 (class java.lang.Short)
-[public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), private java.lang.String(java.lang.String,char), private java.lang.String(java.lang.String,int), private java.lang.String(java.lang.String,java.lang.String), private java.lang.String(java.lang.String,java.lang.String,java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)]
+[public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)]
 [private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID]
 [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), static void java.lang.String.<clinit>(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)]
 []
diff --git a/test/108-check-cast/expected.txt b/test/108-check-cast/expected.txt
new file mode 100644
index 0000000..d86bac9
--- /dev/null
+++ b/test/108-check-cast/expected.txt
@@ -0,0 +1 @@
+OK
diff --git a/test/108-check-cast/info.txt b/test/108-check-cast/info.txt
new file mode 100644
index 0000000..e7ffa4f
--- /dev/null
+++ b/test/108-check-cast/info.txt
@@ -0,0 +1,10 @@
+This test relies on the correct behavior of instance-of to test check-cast behavior,
+as shown below:
+
+
+CCE throw| InstanceOf | Correct?
+---------+------------+----------
+      1  |     0      |    OK
+      1  |     1      |    BAD
+      0  |     0      |    BAD
+      0  |     1      |    OK
\ No newline at end of file
diff --git a/test/108-check-cast/src/Main.java b/test/108-check-cast/src/Main.java
new file mode 100644
index 0000000..7ef13fd
--- /dev/null
+++ b/test/108-check-cast/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Testing check-cast, see comment in info.txt
+ */
+
+class B {}
+class D extends B {}
+
+public class Main {
+    public static void main(String args[]) {
+        B b = null;
+        try {
+            if (1 == args.length) {
+                b = new B();
+            } else {
+                b = new D();
+            }
+            D d = (D) b;
+            if (!(b instanceof D)) {
+                System.out.println("Error: No ClassCastException throuwn when it should have been.");
+            } else {
+                System.out.println("OK");
+            }
+        }
+        catch (ClassCastException cce) {
+            if (b instanceof D) {
+                System.out.println("Error: ClassCastException thrown when it shouldn't have been.");
+            } else {
+                System.out.println("OK");
+            }
+        }
+    }
+}