Merge "Reduce space filter threshold to 128."
diff --git a/Android.mk b/Android.mk
index 54a33b2..49b61bb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,6 +78,8 @@
 
 include $(art_path)/runtime/Android.mk
 include $(art_path)/compiler/Android.mk
+include $(art_path)/dexdump/Android.mk
+include $(art_path)/dexlist/Android.mk
 include $(art_path)/dex2oat/Android.mk
 include $(art_path)/disassembler/Android.mk
 include $(art_path)/oatdump/Android.mk
@@ -166,7 +168,8 @@
 
 # "mm test-art-host" to build and run all host tests.
 .PHONY: test-art-host
-test-art-host: test-art-host-gtest test-art-host-run-test test-art-host-vixl
+test-art-host: test-art-host-gtest test-art-host-run-test \
+               test-art-host-vixl test-art-host-dexdump
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All host tests that run solely with the default compiler.
@@ -235,6 +238,11 @@
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 endif
 
+# Dexdump/list regression test.
+.PHONY: test-art-host-dexdump
+test-art-host-dexdump: $(addprefix $(HOST_OUT_EXECUTABLES)/, dexdump2 dexlist2)
+	ANDROID_HOST_OUT=$(realpath $(HOST_OUT)) art/test/dexdump/run-all-tests
+
 # Valgrind. Currently only 32b gtests.
 .PHONY: valgrind-test-art-host
 valgrind-test-art-host: valgrind-test-art-host-gtest32
@@ -419,6 +427,7 @@
 	adb shell setprop dalvik.vm.dex2oat-filter \"\"
 	adb shell setprop dalvik.vm.image-dex2oat-filter \"\"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
+	adb shell setprop dalvik.vm.usejit false
 	adb shell start
 
 .PHONY: use-artd-full
@@ -429,16 +438,18 @@
 	adb shell setprop dalvik.vm.dex2oat-filter \"\"
 	adb shell setprop dalvik.vm.image-dex2oat-filter \"\"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
+	adb shell setprop dalvik.vm.usejit false
 	adb shell start
 
-.PHONY: use-art-verify-at-runtime
-use-art-verify-at-runtime:
+.PHONY: use-art-jit
+use-art-jit:
 	adb root
 	adb wait-for-device shell stop
 	adb shell rm -rf $(ART_TARGET_DALVIK_CACHE_DIR)/*
 	adb shell setprop dalvik.vm.dex2oat-filter "verify-at-runtime"
 	adb shell setprop dalvik.vm.image-dex2oat-filter "verify-at-runtime"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
+	adb shell setprop dalvik.vm.usejit true
 	adb shell start
 
 .PHONY: use-art-interpret-only
@@ -449,6 +460,7 @@
 	adb shell setprop dalvik.vm.dex2oat-filter "interpret-only"
 	adb shell setprop dalvik.vm.image-dex2oat-filter "interpret-only"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
+	adb shell setprop dalvik.vm.usejit false
 	adb shell start
 
 .PHONY: use-artd-interpret-only
@@ -459,6 +471,7 @@
 	adb shell setprop dalvik.vm.dex2oat-filter "interpret-only"
 	adb shell setprop dalvik.vm.image-dex2oat-filter "interpret-only"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libartd.so
+	adb shell setprop dalvik.vm.usejit false
 	adb shell start
 
 .PHONY: use-art-verify-none
@@ -469,6 +482,7 @@
 	adb shell setprop dalvik.vm.dex2oat-filter "verify-none"
 	adb shell setprop dalvik.vm.image-dex2oat-filter "verify-none"
 	adb shell setprop persist.sys.dalvik.vm.lib.2 libart.so
+	adb shell setprop dalvik.vm.usejit false
 	adb shell start
 
 ########################################################################
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 29b3573..5d4feb8 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -33,6 +33,16 @@
 ART_BUILD_TARGET_DEBUG ?= true
 ART_BUILD_HOST_NDEBUG ?= true
 ART_BUILD_HOST_DEBUG ?= true
+ART_BUILD_HOST_STATIC ?= true
+
+# Asan does not support static linkage
+ifdef SANITIZE_HOST
+  ART_BUILD_HOST_STATIC := false
+endif
+
+ifneq ($(HOST_OS),linux)
+  ART_BUILD_HOST_STATIC := false
+endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),false)
 $(info Disabling ART_BUILD_TARGET_NDEBUG)
@@ -46,6 +56,14 @@
 ifeq ($(ART_BUILD_HOST_DEBUG),false)
 $(info Disabling ART_BUILD_HOST_DEBUG)
 endif
+ifeq ($(ART_BUILD_HOST_STATIC),true)
+$(info Enabling ART_BUILD_HOST_STATIC)
+endif
+
+ifeq ($(ART_TEST_DEBUG_GC),true)
+  ART_DEFAULT_GC_TYPE := SS
+  ART_USE_TLAB := true
+endif
 
 #
 # Used to enable JIT
@@ -253,10 +271,10 @@
   # Larger frame-size for host clang builds today
   ifneq ($(ART_COVERAGE),true)
     ifneq ($(NATIVE_COVERAGE),true)
-      ifndef SANITIZE_HOST
-        art_host_non_debug_cflags += -Wframe-larger-than=2700
-      endif
-      ifndef SANITIZE_TARGET
+      art_host_non_debug_cflags += -Wframe-larger-than=2700
+      ifdef SANITIZE_TARGET
+        art_target_non_debug_cflags += -Wframe-larger-than=5450
+      else
         art_target_non_debug_cflags += -Wframe-larger-than=1728
       endif
     endif
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 183f4e3..a561c5f 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -88,4 +88,8 @@
 
 HOST_CORE_DEX_FILES   := $(foreach jar,$(HOST_CORE_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
 TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
+
+# Classpath for Jack compilation: we only need core-libart.
+HOST_JACK_CLASSPATH   := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack)
+TARGET_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack)
 endif # ART_ANDROID_COMMON_PATH_MK
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 7b03682..a251c92 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -28,6 +28,7 @@
 # $(5): target or host
 # $(6): ndebug or debug
 # $(7): value for LOCAL_MULTILIB (empty means default)
+# $(8): static or shared (empty means shared, applies only for host)
 define build-art-executable
   ifneq ($(5),target)
     ifneq ($(5),host)
@@ -42,11 +43,12 @@
 
   art_executable := $(1)
   art_source := $(2)
-  art_shared_libraries := $(3)
+  art_libraries := $(3)
   art_c_includes := $(4)
   art_target_or_host := $(5)
   art_ndebug_or_debug := $(6)
   art_multilib := $(7)
+  art_static_or_shared := $(8)
   art_out_binary_name :=
 
   include $(CLEAR_VARS)
@@ -54,8 +56,12 @@
   LOCAL_MODULE_TAGS := optional
   LOCAL_SRC_FILES := $$(art_source)
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime art/cmdline $$(art_c_includes)
-  LOCAL_SHARED_LIBRARIES += $$(art_shared_libraries)
-  LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
+
+  ifeq ($$(art_static_or_shared),static)
+    LOCAL_STATIC_LIBRARIES += $$(art_libraries)
+  else
+    LOCAL_SHARED_LIBRARIES += $$(art_libraries)
+  endif
 
   ifeq ($$(art_ndebug_or_debug),ndebug)
     LOCAL_MODULE := $$(art_executable)
@@ -63,6 +69,10 @@
     LOCAL_MODULE := $$(art_executable)d
   endif
 
+  ifeq ($$(art_static_or_shared),static)
+    LOCAL_MODULE := $(LOCAL_MODULE)s
+  endif
+
   LOCAL_CFLAGS := $(ART_EXECUTABLES_CFLAGS)
   # Mac OS linker doesn't understand --export-dynamic.
   ifneq ($$(HOST_OS)-$$(art_target_or_host),darwin-host)
@@ -84,12 +94,29 @@
       LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
     endif
     LOCAL_LDLIBS += -lpthread -ldl
+    ifeq ($$(art_static_or_shared),static)
+      LOCAL_LDFLAGS += -static
+      # We need this because GC stress mode makes use of _Unwind_GetIP and _Unwind_Backtrace and
+      # the symbols are also defined in libgcc_eh.a(unwind-dw2.o)
+      # TODO: Having this is not ideal as it might obscure errors. Try to get rid of it.
+      LOCAL_LDFLAGS += -z muldefs
+      ifeq ($$(HOST_OS),linux)
+        LOCAL_LDLIBS += -lrt
+      endif
+    endif
+
   endif
 
+  # If dynamically linked add libart by default. Statically linked executables
+  # needs to specify it in art_libraries to ensure proper ordering.
   ifeq ($$(art_ndebug_or_debug),ndebug)
-    LOCAL_SHARED_LIBRARIES += libart
+    ifneq ($$(art_static_or_shared),static)
+      LOCAL_SHARED_LIBRARIES += libart
+    endif
   else # debug
-    LOCAL_SHARED_LIBRARIES += libartd
+    ifneq ($$(art_static_or_shared),static)
+      LOCAL_SHARED_LIBRARIES += libartd
+    endif
   endif
 
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
@@ -144,11 +171,12 @@
   # Clear out local variables now that we're done with them.
   art_executable :=
   art_source :=
-  art_shared_libraries :=
+  art_libraries :=
   art_c_includes :=
   art_target_or_host :=
   art_ndebug_or_debug :=
   art_multilib :=
+  art_static_or_shared :=
   art_out_binary_name :=
 
 endef
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 9f6dc9a..0958c64 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -93,6 +93,28 @@
 # TODO: document why this is needed.
 ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
 
+# The dexdump test requires an image and the dexdump utility.
+# TODO: rename into dexdump when migration completes
+ART_GTEST_dexdump_test_HOST_DEPS := \
+  $(HOST_CORE_IMAGE_default_no-pic_64) \
+  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_OUT_EXECUTABLES)/dexdump2
+ART_GTEST_dexdump_test_TARGET_DEPS := \
+  $(TARGET_CORE_IMAGE_default_no-pic_64) \
+  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  dexdump2
+
+# The dexlist test requires an image and the dexlist utility.
+# TODO: rename into dexlist when migration completes
+ART_GTEST_dexlist_test_HOST_DEPS := \
+  $(HOST_CORE_IMAGE_default_no-pic_64) \
+  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_OUT_EXECUTABLES)/dexlist2
+ART_GTEST_dexlist_test_TARGET_DEPS := \
+  $(TARGET_CORE_IMAGE_default_no-pic_64) \
+  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  dexlist2
+
 # The imgdiag test has dependencies on core.oat since it needs to load it during the test.
 # For the host, also add the installed tool (in the base size, that should suffice). For the
 # target, just the module is fine, the sync will happen late enough.
@@ -120,6 +142,8 @@
 
 RUNTIME_GTEST_COMMON_SRC_FILES := \
   cmdline/cmdline_parser_test.cc \
+  dexdump/dexdump_test.cc \
+  dexlist/dexlist_test.cc \
   imgdiag/imgdiag_test.cc \
   oatdump/oatdump_test.cc \
   runtime/arch/arch_test.cc \
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 2967e27..2e9f208 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -104,7 +104,9 @@
   options.push_back(
       std::make_pair("imageinstructionset",
                      reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
-
+  // None of the command line tools need sig chain. If this changes we'll need
+  // to upgrade this option to a proper parameter.
+  options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
   if (!Runtime::Create(options, false)) {
     fprintf(stderr, "Failed to create runtime\n");
     return nullptr;
diff --git a/compiler/Android.mk b/compiler/Android.mk
index dd21406..3947078 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -181,6 +181,7 @@
 
 # $(1): target or host
 # $(2): ndebug or debug
+# $(3): static or shared (empty means shared, applies only for host)
 define build-libart-compiler
   ifneq ($(1),target)
     ifneq ($(1),host)
@@ -195,6 +196,7 @@
 
   art_target_or_host := $(1)
   art_ndebug_or_debug := $(2)
+  art_static_or_shared := $(3)
 
   include $(CLEAR_VARS)
   ifeq ($$(art_target_or_host),host)
@@ -203,17 +205,29 @@
   LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
   ifeq ($$(art_ndebug_or_debug),ndebug)
     LOCAL_MODULE := libart-compiler
-    LOCAL_SHARED_LIBRARIES += libart
+    ifeq ($$(art_static_or_shared), static)
+      LOCAL_STATIC_LIBRARIES += libart
+    else
+      LOCAL_SHARED_LIBRARIES += libart
+    endif
     ifeq ($$(art_target_or_host),target)
       LOCAL_FDO_SUPPORT := true
     endif
   else # debug
     LOCAL_MODULE := libartd-compiler
-    LOCAL_SHARED_LIBRARIES += libartd
+    ifeq ($$(art_static_or_shared), static)
+      LOCAL_STATIC_LIBRARIES += libartd
+    else
+      LOCAL_SHARED_LIBRARIES += libartd
+    endif
   endif
 
   LOCAL_MODULE_TAGS := optional
-  LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+  ifeq ($$(art_static_or_shared), static)
+    LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+  else
+    LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+  endif
 
   LOCAL_SRC_FILES := $$(LIBART_COMPILER_SRC_FILES)
 
@@ -237,6 +251,9 @@
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
     LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
+    ifeq ($$(art_static_or_shared),static)
+      LOCAL_LDFLAGS += -static
+    endif
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
     else
@@ -254,9 +271,17 @@
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
   # Vixl assembly support for ARM64 targets.
   ifeq ($$(art_ndebug_or_debug),debug)
-    LOCAL_SHARED_LIBRARIES += libvixld
+    ifeq ($$(art_static_or_shared), static)
+      LOCAL_WHOLESTATIC_LIBRARIES += libvixld
+    else
+      LOCAL_SHARED_LIBRARIES += libvixld
+    endif
   else
-    LOCAL_SHARED_LIBRARIES += libvixl
+    ifeq ($$(art_static_or_shared), static)
+      LOCAL_WHOLE_STATIC_LIBRARIES += libvixl
+    else
+      LOCAL_SHARED_LIBRARIES += libvixl
+    endif
   endif
 
   LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
@@ -267,7 +292,11 @@
     include $(BUILD_SHARED_LIBRARY)
   else # host
     LOCAL_MULTILIB := both
-    include $(BUILD_HOST_SHARED_LIBRARY)
+    ifeq ($$(art_static_or_shared), static)
+      include $(BUILD_HOST_STATIC_LIBRARY)
+    else
+      include $(BUILD_HOST_SHARED_LIBRARY)
+    endif
   endif
 
   ifeq ($$(art_target_or_host),target)
@@ -278,20 +307,38 @@
     endif
   else # host
     ifeq ($$(art_ndebug_or_debug),debug)
-      $(HOST_OUT_EXECUTABLES)/dex2oatd: $$(LOCAL_INSTALLED_MODULE)
+      ifeq ($$(art_static_or_shared),static)
+        $(HOST_OUT_EXECUTABLES)/dex2oatds: $$(LOCAL_INSTALLED_MODULE)
+      else
+        $(HOST_OUT_EXECUTABLES)/dex2oatd: $$(LOCAL_INSTALLED_MODULE)
+      endif
     else
-      $(HOST_OUT_EXECUTABLES)/dex2oat: $$(LOCAL_INSTALLED_MODULE)
+      ifeq ($$(art_static_or_shared),static)
+        $(HOST_OUT_EXECUTABLES)/dex2oats: $$(LOCAL_INSTALLED_MODULE)
+      else
+        $(HOST_OUT_EXECUTABLES)/dex2oat: $$(LOCAL_INSTALLED_MODULE)
+      endif
     endif
   endif
 
+  # Clear locally defined variables.
+  art_target_or_host :=
+  art_ndebug_or_debug :=
+  art_static_or_shared :=
 endef
 
 # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
   $(eval $(call build-libart-compiler,host,ndebug))
+  ifeq ($(ART_BUILD_HOST_STATIC),true)
+    $(eval $(call build-libart-compiler,host,ndebug,static))
+  endif
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
   $(eval $(call build-libart-compiler,host,debug))
+  ifeq ($(ART_BUILD_HOST_STATIC),true)
+    $(eval $(call build-libart-compiler,host,debug,static))
+  endif
 endif
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
   $(eval $(call build-libart-compiler,target,ndebug))
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index d1acada..74ef35e 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -23,20 +23,12 @@
                            const ArrayRef<const uint8_t>& quick_code, bool owns_code_array)
     : compiler_driver_(compiler_driver), instruction_set_(instruction_set),
       owns_code_array_(owns_code_array), quick_code_(nullptr) {
-  SetCode(&quick_code);
-}
-
-void CompiledCode::SetCode(const ArrayRef<const uint8_t>* quick_code) {
-  if (quick_code != nullptr) {
-    CHECK(!quick_code->empty());
-    if (owns_code_array_) {
-      // If we are supposed to own the code, don't deduplicate it.
-      CHECK(quick_code_ == nullptr);
-      quick_code_ = new SwapVector<uint8_t>(quick_code->begin(), quick_code->end(),
-                                            compiler_driver_->GetSwapSpaceAllocator());
-    } else {
-      quick_code_ = compiler_driver_->DeduplicateCode(*quick_code);
-    }
+  if (owns_code_array_) {
+    // If we are supposed to own the code, don't deduplicate it.
+    quick_code_ = new SwapVector<uint8_t>(quick_code.begin(), quick_code.end(),
+                                          compiler_driver_->GetSwapSpaceAllocator());
+  } else {
+    quick_code_ = compiler_driver_->DeduplicateCode(quick_code);
   }
 }
 
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 45a62bc..a4d2387 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -47,8 +47,6 @@
     return quick_code_;
   }
 
-  void SetCode(const ArrayRef<const uint8_t>* quick_code);
-
   bool operator==(const CompiledCode& rhs) const;
 
   // To align an offset from a page-aligned value to make it suitable
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index bd59046..4b56b69 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -18,6 +18,7 @@
 #include "art_method-inl.h"
 #include "base/logging.h"
 #include "base/mutex.h"
+#include "compiled_method.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "driver/compiler_driver.h"
@@ -34,6 +35,13 @@
 // Control check-cast elision.
 const bool kEnableCheckCastEllision = true;
 
+struct QuickenedInfo {
+  QuickenedInfo(uint32_t pc, uint16_t index) : dex_pc(pc), dex_member_index(index) {}
+
+  uint32_t dex_pc;
+  uint16_t dex_member_index;
+};
+
 class DexCompiler {
  public:
   DexCompiler(art::CompilerDriver& compiler,
@@ -47,6 +55,10 @@
 
   void Compile();
 
+  const std::vector<QuickenedInfo>& GetQuickenedInfo() const {
+    return quickened_info_;
+  }
+
  private:
   const DexFile& GetDexFile() const {
     return *unit_.GetDexFile();
@@ -87,6 +99,11 @@
   const DexCompilationUnit& unit_;
   const DexToDexCompilationLevel dex_to_dex_compilation_level_;
 
+  // Filled by the compiler when quickening, in order to encode that information
+  // in the .oat file. The runtime will use that information to get to the original
+  // opcodes.
+  std::vector<QuickenedInfo> quickened_info_;
+
   DISALLOW_COPY_AND_ASSIGN(DexCompiler);
 };
 
@@ -248,6 +265,7 @@
     inst->SetOpcode(new_opcode);
     // Replace field index by field offset.
     inst->SetVRegC_22c(static_cast<uint16_t>(field_offset.Int32Value()));
+    quickened_info_.push_back(QuickenedInfo(dex_pc, field_idx));
   }
 }
 
@@ -287,24 +305,60 @@
       } else {
         inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
       }
+      quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
     }
   }
 }
 
-}  // namespace optimizer
-}  // namespace art
-
-extern "C" void ArtCompileDEX(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item,
-                              uint32_t access_flags, art::InvokeType invoke_type,
-                              uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
-                              const art::DexFile& dex_file,
-                              art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
-  UNUSED(invoke_type);
+extern "C" CompiledMethod* ArtCompileDEX(
+    art::CompilerDriver& driver,
+    const art::DexFile::CodeItem* code_item,
+    uint32_t access_flags,
+    art::InvokeType invoke_type ATTRIBUTE_UNUSED,
+    uint16_t class_def_idx,
+    uint32_t method_idx,
+    jobject class_loader,
+    const art::DexFile& dex_file,
+    art::DexToDexCompilationLevel dex_to_dex_compilation_level) {
   if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) {
     art::DexCompilationUnit unit(nullptr, class_loader, art::Runtime::Current()->GetClassLinker(),
                                  dex_file, code_item, class_def_idx, method_idx, access_flags,
                                  driver.GetVerifiedMethod(&dex_file, method_idx));
     art::optimizer::DexCompiler dex_compiler(driver, unit, dex_to_dex_compilation_level);
     dex_compiler.Compile();
+    if (dex_compiler.GetQuickenedInfo().empty()) {
+      // No need to create a CompiledMethod if there are no quickened opcodes.
+      return nullptr;
+    }
+
+    // Create a `CompiledMethod`, with the quickened information in the vmap table.
+    Leb128EncodingVector builder;
+    for (QuickenedInfo info : dex_compiler.GetQuickenedInfo()) {
+      builder.PushBackUnsigned(info.dex_pc);
+      builder.PushBackUnsigned(info.dex_member_index);
+    }
+    InstructionSet instruction_set = driver.GetInstructionSet();
+    if (instruction_set == kThumb2) {
+      // Don't use the thumb2 instruction set to avoid the one off code delta.
+      instruction_set = kArm;
+    }
+    return CompiledMethod::SwapAllocCompiledMethod(
+        &driver,
+        instruction_set,
+        ArrayRef<const uint8_t>(),                   // no code
+        0,
+        0,
+        0,
+        nullptr,                                     // src_mapping_table
+        ArrayRef<const uint8_t>(),                   // mapping_table
+        ArrayRef<const uint8_t>(builder.GetData()),  // vmap_table
+        ArrayRef<const uint8_t>(),                   // gc_map
+        ArrayRef<const uint8_t>(),                   // cfi data
+        ArrayRef<const LinkerPatch>());
   }
+  return nullptr;
 }
+
+}  // namespace optimizer
+
+}  // namespace art
diff --git a/compiler/dex/gvn_dead_code_elimination.cc b/compiler/dex/gvn_dead_code_elimination.cc
index b1f5d87..044989e 100644
--- a/compiler/dex/gvn_dead_code_elimination.cc
+++ b/compiler/dex/gvn_dead_code_elimination.cc
@@ -1192,7 +1192,6 @@
     case Instruction::CONST_WIDE_32:
     case Instruction::CONST_WIDE:
     case Instruction::CONST_WIDE_HIGH16:
-    case Instruction::ARRAY_LENGTH:
     case Instruction::CMPL_FLOAT:
     case Instruction::CMPG_FLOAT:
     case Instruction::CMPL_DOUBLE:
@@ -1316,6 +1315,13 @@
       }
       break;
 
+    case Instruction::ARRAY_LENGTH:
+      if ((mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
+        must_keep = true;
+        uses_all_vregs = true;
+      }
+      break;
+
     case Instruction::AGET_OBJECT:
     case Instruction::AGET:
     case Instruction::AGET_WIDE:
diff --git a/compiler/dex/gvn_dead_code_elimination_test.cc b/compiler/dex/gvn_dead_code_elimination_test.cc
index 461c844..6ba91b6 100644
--- a/compiler/dex/gvn_dead_code_elimination_test.cc
+++ b/compiler/dex/gvn_dead_code_elimination_test.cc
@@ -2066,4 +2066,31 @@
   }
 }
 
+TEST_F(GvnDeadCodeEliminationTestSimple, ArrayLengthThrows) {
+  static const MIRDef mirs[] = {
+      DEF_CONST(3, Instruction::CONST, 0u, 0),              // null
+      DEF_UNOP(3, Instruction::ARRAY_LENGTH, 1u, 0u),       // null.length
+      DEF_CONST(3, Instruction::CONST, 2u, 1000u),          // Overwrite the array-length dest.
+  };
+
+  static const int32_t sreg_to_vreg_map[] = { 0, 1, 1 };
+  PrepareSRegToVRegMap(sreg_to_vreg_map);
+
+  PrepareMIRs(mirs);
+  PerformGVN_DCE();
+
+  ASSERT_EQ(arraysize(mirs), value_names_.size());
+  static const size_t diff_indexes[] = { 0, 1, 2 };
+  ExpectValueNamesNE(diff_indexes);
+
+  static const bool eliminated[] = {
+      false, false, false,
+  };
+  static_assert(arraysize(eliminated) == arraysize(mirs), "array size mismatch");
+  for (size_t i = 0; i != arraysize(eliminated); ++i) {
+    bool actually_eliminated = (static_cast<int>(mirs_[i].dalvikInsn.opcode) == kMirOpNop);
+    EXPECT_EQ(eliminated[i], actually_eliminated) << i;
+  }
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc
index df4a9f2..5f911db 100644
--- a/compiler/dex/quick/arm/assemble_arm.cc
+++ b/compiler/dex/quick/arm/assemble_arm.cc
@@ -1298,7 +1298,7 @@
              */
             delta &= ~0x3;
           }
-          DCHECK_EQ((delta & 0x3), 0);
+          DCHECK_ALIGNED(delta, 4);
           // First, a sanity check for cases we shouldn't see now
           if (kIsDebugBuild && (((lir->opcode == kThumbAddPcRel) && (delta > 1020)) ||
               ((lir->opcode == kThumbLdrPcRel) && (delta > 1020)))) {
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 2ef92f8..062f7af 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -880,7 +880,7 @@
 LIR* ArmMir2Lir::LoadStoreUsingInsnWithOffsetImm8Shl2(ArmOpcode opcode, RegStorage r_base,
                                                       int displacement, RegStorage r_src_dest,
                                                       RegStorage r_work) {
-  DCHECK_EQ(displacement & 3, 0);
+  DCHECK_ALIGNED(displacement, 4);
   constexpr int kOffsetMask = 0xff << 2;
   int encoded_disp = (displacement & kOffsetMask) >> 2;  // Within range of the instruction.
   RegStorage r_ptr = r_base;
@@ -942,7 +942,7 @@
         already_generated = true;
         break;
       }
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       scale = 2;
       if (r_dest.Low8() && (r_base == rs_rARM_PC) && (displacement <= 1020) &&
           (displacement >= 0)) {
@@ -959,14 +959,14 @@
       }
       break;
     case kUnsignedHalf:
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       scale = 1;
       short_form = all_low && (displacement >> (5 + scale)) == 0;
       opcode16 = kThumbLdrhRRI5;
       opcode32 = kThumb2LdrhRRI12;
       break;
     case kSignedHalf:
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       scale = 1;
       DCHECK_EQ(opcode16, kThumbBkpt);  // Not available.
       opcode32 = kThumb2LdrshRRI12;
@@ -1096,7 +1096,7 @@
         already_generated = true;
         break;
       }
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       scale = 2;
       if (r_src.Low8() && (r_base == rs_r13sp) && (displacement <= 1020) && (displacement >= 0)) {
         short_form = true;
@@ -1109,7 +1109,7 @@
       break;
     case kUnsignedHalf:
     case kSignedHalf:
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       scale = 1;
       short_form = all_low && (displacement >> (5 + scale)) == 0;
       opcode16 = kThumbStrhRRI5;
diff --git a/compiler/dex/quick/arm64/assemble_arm64.cc b/compiler/dex/quick/arm64/assemble_arm64.cc
index b78fb80..25c69d1 100644
--- a/compiler/dex/quick/arm64/assemble_arm64.cc
+++ b/compiler/dex/quick/arm64/assemble_arm64.cc
@@ -909,7 +909,7 @@
           CodeOffset target = target_lir->offset +
               ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
           int32_t delta = target - pc;
-          DCHECK_EQ(delta & 0x3, 0);
+          DCHECK_ALIGNED(delta, 4);
           if (!IS_SIGNED_IMM26(delta >> 2)) {
             LOG(FATAL) << "Invalid jump range in kFixupT1Branch";
           }
@@ -933,7 +933,7 @@
           CodeOffset target = target_lir->offset +
             ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
           int32_t delta = target - pc;
-          DCHECK_EQ(delta & 0x3, 0);
+          DCHECK_ALIGNED(delta, 4);
           if (!IS_SIGNED_IMM19(delta >> 2)) {
             LOG(FATAL) << "Invalid jump range in kFixupLoad";
           }
@@ -965,7 +965,7 @@
           CodeOffset target = target_lir->offset +
               ((target_lir->flags.generation == lir->flags.generation) ? 0 : offset_adjustment);
           int32_t delta = target - pc;
-          DCHECK_EQ(delta & 0x3, 0);
+          DCHECK_ALIGNED(delta, 4);
           // Check if branch offset can be encoded in tbz/tbnz.
           if (!IS_SIGNED_IMM14(delta >> 2)) {
             DexOffset dalvik_offset = lir->dalvik_offset;
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index da12d8e..853980d 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -24,6 +24,7 @@
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
 #include "mips_lir.h"
@@ -285,12 +286,25 @@
   RegStorage check_reg = AllocPtrSizeTemp();
   RegStorage new_sp = AllocPtrSizeTemp();
   const RegStorage rs_sp = TargetPtrReg(kSp);
+  const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(target);
+  const bool large_frame = static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes;
+  bool generate_explicit_stack_overflow_check = large_frame ||
+    !cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks();
+
   if (!skip_overflow_check) {
-    // Load stack limit.
-    if (cu_->target64) {
-      LoadWordDisp(TargetPtrReg(kSelf), Thread::StackEndOffset<8>().Int32Value(), check_reg);
+    if (generate_explicit_stack_overflow_check) {
+      // Load stack limit.
+      if (cu_->target64) {
+        LoadWordDisp(TargetPtrReg(kSelf), Thread::StackEndOffset<8>().Int32Value(), check_reg);
+      } else {
+        Load32Disp(TargetPtrReg(kSelf), Thread::StackEndOffset<4>().Int32Value(), check_reg);
+      }
     } else {
-      Load32Disp(TargetPtrReg(kSelf), Thread::StackEndOffset<4>().Int32Value(), check_reg);
+      // Implicit stack overflow check.
+      // Generate a load from [sp, #-overflowsize].  If this is in the stack
+      // redzone we will get a segmentation fault.
+      Load32Disp(rs_sp, -kStackOverflowReservedUsableBytes, rs_rZERO);
+      MarkPossibleStackOverflowException();
     }
   }
   // Spill core callee saves.
@@ -298,7 +312,7 @@
   // NOTE: promotion of FP regs currently unsupported, thus no FP spill.
   DCHECK_EQ(num_fp_spills_, 0);
   const int frame_sub = frame_size_ - spill_count * ptr_size;
-  if (!skip_overflow_check) {
+  if (!skip_overflow_check && generate_explicit_stack_overflow_check) {
     class StackOverflowSlowPath : public LIRSlowPath {
      public:
       StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace)
@@ -329,6 +343,8 @@
     OpRegCopy(rs_sp, new_sp);  // Establish stack.
     cfi_.AdjustCFAOffset(frame_sub);
   } else {
+    // Here if skip_overflow_check or doing implicit stack overflow check.
+    // Just make room on the stack for the frame now.
     OpRegImm(kOpSub, rs_sp, frame_sub);
     cfi_.AdjustCFAOffset(frame_sub);
   }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 713264e..43fbcbd 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -79,6 +79,7 @@
   OVERRIDE;
   LIR* CheckSuspendUsingLoad() OVERRIDE;
   RegStorage LoadHelper(QuickEntrypointEnum trampoline) OVERRIDE;
+  void ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide);
   LIR* LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
                     VolatileKind is_volatile) OVERRIDE;
   LIR* LoadBaseIndexed(RegStorage r_base, RegStorage r_index, RegStorage r_dest, int scale,
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index f5ad7c7..1099303 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -691,6 +691,9 @@
     reg_len = AllocTemp();
     // Get len.
     Load32Disp(rl_array.reg, len_offset, reg_len);
+    MarkPossibleNullPointerException(opt_flags);
+  } else {
+    ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
   }
   // reg_ptr -> array data.
   OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
@@ -781,6 +784,9 @@
     // NOTE: max live temps(4) here.
     // Get len.
     Load32Disp(rl_array.reg, len_offset, reg_len);
+    MarkPossibleNullPointerException(opt_flags);
+  } else {
+    ForceImplicitNullCheck(rl_array.reg, opt_flags, false);
   }
   // reg_ptr -> array data.
   OpRegImm(kOpAdd, reg_ptr, data_offset);
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 4c0bd83..b098bc2 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -791,6 +791,7 @@
   RegStorage reg_ptr = TargetReg(kArg0);
   OpRegRegImm(kOpAdd, reg_ptr, r_base, displacement);
   RegStorage r_tgt = LoadHelper(kQuickA64Load);
+  ForceImplicitNullCheck(reg_ptr, 0, true);  // is_wide = true
   LIR *ret = OpReg(kOpBlx, r_tgt);
   RegStorage reg_ret;
   if (cu_->target64) {
@@ -813,6 +814,7 @@
   LockCallTemps();  // Using fixed registers.
   RegStorage temp_ptr = AllocTemp();
   OpRegRegImm(kOpAdd, temp_ptr, r_base, displacement);
+  ForceImplicitNullCheck(temp_ptr, 0, true);  // is_wide = true
   RegStorage temp_value = AllocTempWide();
   OpRegCopyWide(temp_value, r_src);
   if (cu_->target64) {
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 95c61cd..ec2475a 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -21,7 +21,9 @@
 #include "base/logging.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "dex/reg_storage_eq.h"
+#include "dex/mir_graph.h"
 #include "driver/compiler_driver.h"
+#include "driver/compiler_options.h"
 #include "mips_lir.h"
 
 namespace art {
@@ -712,7 +714,7 @@
         } else {
           opcode = kMipsFldc1;
         }
-        DCHECK_EQ((displacement & 0x3), 0);
+        DCHECK_ALIGNED(displacement, 4);
         break;
       }
       is64bit = true;
@@ -734,15 +736,15 @@
           DCHECK(r_dest.IsDouble());
         }
       }
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       break;
     case kUnsignedHalf:
       opcode = kMipsLhu;
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       break;
     case kSignedHalf:
       opcode = kMipsLh;
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       break;
     case kUnsignedByte:
       opcode = kMipsLbu;
@@ -830,6 +832,22 @@
   return res;
 }
 
+void MipsMir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags, bool is_wide) {
+  if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
+    if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+      return;
+    }
+    // Force an implicit null check by performing a memory operation (load) from the given
+    // register with offset 0.  This will cause a signal if the register contains 0 (null).
+    LIR* load = Load32Disp(reg, LOWORD_OFFSET, rs_rZERO);
+    MarkSafepointPC(load);
+    if (is_wide) {
+      load = Load32Disp(reg, HIWORD_OFFSET, rs_rZERO);
+      MarkSafepointPC(load);
+    }
+  }
+}
+
 LIR* MipsMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_dest, OpSize size,
                                VolatileKind is_volatile) {
   if (UNLIKELY(is_volatile == kVolatile && (size == k64 || size == kDouble))
@@ -873,7 +891,7 @@
         } else {
           opcode = kMipsFsdc1;
         }
-        DCHECK_EQ((displacement & 0x3), 0);
+        DCHECK_ALIGNED(displacement, 4);
         break;
       }
       is64bit = true;
@@ -895,12 +913,12 @@
           DCHECK(r_src.IsDouble());
         }
       }
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       break;
     case kUnsignedHalf:
     case kSignedHalf:
       opcode = kMipsSh;
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       break;
     case kUnsignedByte:
     case kSignedByte:
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 7ca03cf..c50246d 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -193,7 +193,8 @@
   }
 
   if (!reg_arg.Valid()) {
-    LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, rl_dest.wide ? k64 : k32, kNotVolatile);
+    OpSize op_size = rl_dest.wide ? k64 : (rl_dest.ref ? kReference : k32);
+    LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, op_size, kNotVolatile);
   } else {
     if (rl_dest.wide) {
       OpRegCopyWide(rl_dest.reg, reg_arg);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index d993d93..d1fe167 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1336,9 +1336,24 @@
     }
     OpRegReg(kOpRev, rl_result.reg.GetLow(), rl_i.reg.GetHigh());
     OpRegReg(kOpRev, rl_result.reg.GetHigh(), r_i_low);
+    // Free up at least one input register if it was a temp. Otherwise we may be in the bad
+    // situation of not having a temp available for SwapBits. Make sure it's not overlapping
+    // with the output, though.
     if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
+      // There's definitely a free temp after this.
       FreeTemp(r_i_low);
+    } else {
+      // We opportunistically release both here. That saves duplication of the register state
+      // lookup (to see if it's actually a temp).
+      if (rl_i.reg.GetLowReg() != rl_result.reg.GetHighReg()) {
+        FreeTemp(rl_i.reg.GetLow());
+      }
+      if (rl_i.reg.GetHighReg() != rl_result.reg.GetLowReg() &&
+          rl_i.reg.GetHighReg() != rl_result.reg.GetHighReg()) {
+        FreeTemp(rl_i.reg.GetHigh());
+      }
     }
+
     SwapBits(rl_result.reg.GetLow(), 1, 0x55555555);
     SwapBits(rl_result.reg.GetLow(), 2, 0x33333333);
     SwapBits(rl_result.reg.GetLow(), 4, 0x0f0f0f0f);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 61a1bec..b16ae98 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -659,7 +659,7 @@
         opcode = is_array ? kX86Mov32RA  : kX86Mov32RM;
       }
       // TODO: double store is to unaligned address
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       break;
     case kWord:
       if (cu_->target64) {
@@ -677,15 +677,15 @@
         opcode = is_array ? kX86MovssRA : kX86MovssRM;
         DCHECK(r_dest.IsFloat());
       }
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       break;
     case kUnsignedHalf:
       opcode = is_array ? kX86Movzx16RA : kX86Movzx16RM;
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       break;
     case kSignedHalf:
       opcode = is_array ? kX86Movsx16RA : kX86Movsx16RM;
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       break;
     case kUnsignedByte:
       opcode = is_array ? kX86Movzx8RA : kX86Movzx8RM;
@@ -812,7 +812,7 @@
         opcode = is_array ? kX86Mov32AR  : kX86Mov32MR;
       }
       // TODO: double store is to unaligned address
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       break;
     case kWord:
       if (cu_->target64) {
@@ -831,13 +831,13 @@
         opcode = is_array ? kX86MovssAR : kX86MovssMR;
         DCHECK(r_src.IsSingle());
       }
-      DCHECK_EQ((displacement & 0x3), 0);
+      DCHECK_ALIGNED(displacement, 4);
       consider_non_temporal = true;
       break;
     case kUnsignedHalf:
     case kSignedHalf:
       opcode = is_array ? kX86Mov16AR : kX86Mov16MR;
-      DCHECK_EQ((displacement & 0x1), 0);
+      DCHECK_ALIGNED(displacement, 2);
       break;
     case kUnsignedByte:
     case kSignedByte:
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 7890108..a52bfae 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2291,10 +2291,16 @@
       // TODO: add a command-line option to disable DEX-to-DEX compilation ?
       // Do not optimize if a VerifiedMethod is missing. SafeCast elision, for example, relies on
       // it.
-      (*dex_to_dex_compiler_)(*this, code_item, access_flags,
-                              invoke_type, class_def_idx,
-                              method_idx, class_loader, dex_file,
-                              has_verified_method ? dex_to_dex_compilation_level : kRequired);
+      compiled_method = (*dex_to_dex_compiler_)(
+          *this,
+          code_item,
+          access_flags,
+          invoke_type,
+          class_def_idx,
+          method_idx,
+          class_loader,
+          dex_file,
+          has_verified_method ? dex_to_dex_compilation_level : kRequired);
     }
   }
   if (kTimeCompileMethod) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 2d7ceae..5cf4044 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -675,12 +675,13 @@
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
 
-  typedef void (*DexToDexCompilerFn)(CompilerDriver& driver,
-                                     const DexFile::CodeItem* code_item,
-                                     uint32_t access_flags, InvokeType invoke_type,
-                                     uint32_t class_dex_idx, uint32_t method_idx,
-                                     jobject class_loader, const DexFile& dex_file,
-                                     DexToDexCompilationLevel dex_to_dex_compilation_level);
+  typedef CompiledMethod* (*DexToDexCompilerFn)(
+      CompilerDriver& driver,
+      const DexFile::CodeItem* code_item,
+      uint32_t access_flags, InvokeType invoke_type,
+      uint32_t class_dex_idx, uint32_t method_idx,
+      jobject class_loader, const DexFile& dex_file,
+      DexToDexCompilationLevel dex_to_dex_compilation_level);
   DexToDexCompilerFn dex_to_dex_compiler_;
 
   void* compiler_context_;
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index c68bbc0..c10ffeb 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -249,16 +249,16 @@
   // Find all addresses (low_pc) which contain deduped methods.
   // The first instance of method is not marked deduped_, but the rest is.
   std::unordered_set<uint32_t> deduped_addresses;
-  for (auto it = method_infos.begin(); it != method_infos.end(); ++it) {
-    if (it->deduped_) {
-      deduped_addresses.insert(it->low_pc_);
+  for (const OatWriter::DebugInfo& mi : method_infos) {
+    if (mi.deduped_) {
+      deduped_addresses.insert(mi.low_pc_);
     }
   }
 
   // Group the methods into compilation units based on source file.
   std::vector<std::vector<const OatWriter::DebugInfo*>> compilation_units;
   const char* last_source_file = nullptr;
-  for (const auto& mi : method_infos) {
+  for (const OatWriter::DebugInfo& mi : method_infos) {
     // Attribute given instruction range only to single method.
     // Otherwise the debugger might get really confused.
     if (!mi.deduped_) {
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 73e121f..fdfeb48 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -989,6 +989,8 @@
   CHECK_EQ(image_objects_offset_begin_ + bin_slot_previous_sizes_[kBinArtMethodClean],
            methods_section->Offset());
   cur_pos = methods_section->End();
+  // Round up to the alignment the string table expects. See HashSet::WriteToMemory.
+  cur_pos = RoundUp(cur_pos, sizeof(uint64_t));
   // Calculate the size of the interned strings.
   auto* interned_strings_section = &sections[ImageHeader::kSectionInternedStrings];
   *interned_strings_section = ImageSection(cur_pos, intern_table_bytes_);
@@ -1417,9 +1419,6 @@
     if (UNLIKELY(orig->IsAbstract())) {
       copy->SetEntryPointFromQuickCompiledCodePtrSize(
           GetOatAddress(quick_to_interpreter_bridge_offset_), target_ptr_size_);
-      copy->SetEntryPointFromInterpreterPtrSize(
-          reinterpret_cast<EntryPointFromInterpreter*>(const_cast<uint8_t*>(
-                  GetOatAddress(interpreter_to_interpreter_bridge_offset_))), target_ptr_size_);
     } else {
       bool quick_is_interpreted;
       const uint8_t* quick_code = GetQuickCode(orig, &quick_is_interpreted);
@@ -1432,16 +1431,6 @@
         copy->SetEntryPointFromJniPtrSize(
             GetOatAddress(jni_dlsym_lookup_offset_), target_ptr_size_);
       }
-
-      // Interpreter entrypoint:
-      // Set the interpreter entrypoint depending on whether there is compiled code or not.
-      uint32_t interpreter_code = (quick_is_interpreted)
-          ? interpreter_to_interpreter_bridge_offset_
-          : interpreter_to_compiled_code_bridge_offset_;
-      EntryPointFromInterpreter* interpreter_entrypoint =
-          reinterpret_cast<EntryPointFromInterpreter*>(
-              const_cast<uint8_t*>(GetOatAddress(interpreter_code)));
-      copy->SetEntryPointFromInterpreterPtrSize(interpreter_entrypoint, target_ptr_size_);
     }
   }
 }
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 9d45ce2..1523383 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -18,7 +18,7 @@
 #define ART_COMPILER_IMAGE_WRITER_H_
 
 #include <stdint.h>
-#include <valgrind.h>
+#include "base/memory_tool.h"
 
 #include <cstddef>
 #include <memory>
@@ -199,7 +199,7 @@
   const uint8_t* GetOatAddress(uint32_t offset) const {
     // With Quick, code is within the OatFile, as there are all in one
     // .o ELF object.
-    DCHECK_LT(offset, oat_file_->Size());
+    DCHECK_LE(offset, oat_file_->Size());
     DCHECK(oat_data_begin_ != nullptr);
     return offset == 0u ? nullptr : oat_data_begin_ + offset;
   }
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index a1d8226..a122ceb 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -71,18 +71,18 @@
       CompilerOptions::kDefaultSmallMethodThreshold,
       CompilerOptions::kDefaultTinyMethodThreshold,
       CompilerOptions::kDefaultNumDexMethodsThreshold,
-      false,
+      /* include_patch_information */ false,
       CompilerOptions::kDefaultTopKProfileThreshold,
-      false,  // TODO: Think about debuggability of JIT-compiled code.
+      Runtime::Current()->IsDebuggable(),
       CompilerOptions::kDefaultGenerateDebugInfo,
-      false,
-      false,
-      false,
-      false,  // pic
-      nullptr,
+      /* implicit_null_checks */ true,
+      /* implicit_so_checks */ true,
+      /* implicit_suspend_checks */ false,
+      /* pic */ true,  // TODO: Support non-PIC in optimizing.
+      /* verbose_methods */ nullptr,
       pass_manager_options,
-      nullptr,
-      false));
+      /* init_failure_output */ nullptr,
+      /* abort_on_hard_verifier_failure */ false));
   const InstructionSet instruction_set = kRuntimeISA;
   instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
   cumulative_logger_.reset(new CumulativeLogger("jit times"));
@@ -92,10 +92,23 @@
                                               method_inliner_map_.get(),
                                               CompilerCallbacks::CallbackMode::kCompileApp));
   compiler_driver_.reset(new CompilerDriver(
-      compiler_options_.get(), verification_results_.get(), method_inliner_map_.get(),
-      Compiler::kQuick, instruction_set, instruction_set_features_.get(), false,
-      nullptr, nullptr, nullptr, 1, false, true,
-      std::string(), cumulative_logger_.get(), -1, std::string()));
+      compiler_options_.get(),
+      verification_results_.get(),
+      method_inliner_map_.get(),
+      Compiler::kOptimizing,
+      instruction_set,
+      instruction_set_features_.get(),
+      /* image */ false,
+      /* image_classes */ nullptr,
+      /* compiled_classes */ nullptr,
+      /* compiled_methods */ nullptr,
+      /* thread_count */ 1,
+      /* dump_stats */ false,
+      /* dump_passes */ false,
+      /* dump_cfg_file_name */ "",
+      cumulative_logger_.get(),
+      /* swap_fd */ -1,
+      /* profile_file */ ""));
   // Disable dedupe so we can remove compiled methods.
   compiler_driver_->SetDedupeEnabled(false);
   compiler_driver_->SetSupportBootImageFixup(false);
@@ -195,9 +208,14 @@
   std::copy(quick_code->data(), quick_code->data() + code_size, code_ptr);
   // After we are done writing we need to update the method header.
   // Write out the method header last.
-  method_header = new(method_header)OatQuickMethodHeader(
-      code_ptr - mapping_table, code_ptr - vmap_table, code_ptr - gc_map, frame_size_in_bytes,
-      core_spill_mask, fp_spill_mask, code_size);
+  method_header = new(method_header) OatQuickMethodHeader(
+      (mapping_table == nullptr) ? 0 : code_ptr - mapping_table,
+      (vmap_table == nullptr) ? 0 : code_ptr - vmap_table,
+      (gc_map == nullptr) ? 0 : code_ptr - gc_map,
+      frame_size_in_bytes,
+      core_spill_mask,
+      fp_spill_mask,
+      code_size);
   // Return the code ptr.
   return code_ptr;
 }
@@ -216,23 +234,35 @@
   auto* const mapping_table = compiled_method->GetMappingTable();
   auto* const vmap_table = compiled_method->GetVmapTable();
   auto* const gc_map = compiled_method->GetGcMap();
-  CHECK(gc_map != nullptr) << PrettyMethod(method);
-  // Write out pre-header stuff.
-  uint8_t* const mapping_table_ptr = code_cache->AddDataArray(
-      self, mapping_table->data(), mapping_table->data() + mapping_table->size());
-  if (mapping_table_ptr == nullptr) {
-    return false;  // Out of data cache.
+  uint8_t* mapping_table_ptr = nullptr;
+  uint8_t* vmap_table_ptr = nullptr;
+  uint8_t* gc_map_ptr = nullptr;
+
+  if (mapping_table != nullptr) {
+    // Write out pre-header stuff.
+    mapping_table_ptr = code_cache->AddDataArray(
+        self, mapping_table->data(), mapping_table->data() + mapping_table->size());
+    if (mapping_table_ptr == nullptr) {
+      return false;  // Out of data cache.
+    }
   }
-  uint8_t* const vmap_table_ptr = code_cache->AddDataArray(
-      self, vmap_table->data(), vmap_table->data() + vmap_table->size());
-  if (vmap_table_ptr == nullptr) {
-    return false;  // Out of data cache.
+
+  if (vmap_table != nullptr) {
+    vmap_table_ptr = code_cache->AddDataArray(
+        self, vmap_table->data(), vmap_table->data() + vmap_table->size());
+    if (vmap_table_ptr == nullptr) {
+      return false;  // Out of data cache.
+    }
   }
-  uint8_t* const gc_map_ptr = code_cache->AddDataArray(
-      self, gc_map->data(), gc_map->data() + gc_map->size());
-  if (gc_map_ptr == nullptr) {
-    return false;  // Out of data cache.
+
+  if (gc_map != nullptr) {
+    gc_map_ptr = code_cache->AddDataArray(
+        self, gc_map->data(), gc_map->data() + gc_map->size());
+    if (gc_map_ptr == nullptr) {
+      return false;  // Out of data cache.
+    }
   }
+
   // Don't touch this until you protect / unprotect the code.
   const size_t reserve_size = sizeof(OatQuickMethodHeader) + quick_code->size() + 32;
   uint8_t* const code_reserve = code_cache->ReserveCode(self, reserve_size);
diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc
index a057a4c..13f67e6 100644
--- a/compiler/linker/arm/relative_patcher_thumb2_test.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc
@@ -50,7 +50,7 @@
 
     // We want to put the method3 at a very precise offset.
     const uint32_t method3_offset = method1_offset + distance_without_thunks;
-    CHECK(IsAligned<kArmAlignment>(method3_offset - sizeof(OatQuickMethodHeader)));
+    CHECK_ALIGNED(method3_offset - sizeof(OatQuickMethodHeader), kArmAlignment);
 
     // Calculate size of method2 so that we put method3 at the correct place.
     const uint32_t method2_offset =
@@ -242,8 +242,10 @@
   };
 
   constexpr uint32_t max_positive_disp = 16 * MB - 2u + 4u /* PC adjustment */;
-  bool thunk_in_gap = Create2MethodsWithGap(method1_code, method1_patches,
-                                            kNopCode, ArrayRef<const LinkerPatch>(),
+  bool thunk_in_gap = Create2MethodsWithGap(method1_code,
+                                            ArrayRef<const LinkerPatch>(method1_patches),
+                                            kNopCode,
+                                            ArrayRef<const LinkerPatch>(),
                                             bl_offset_in_method1 + max_positive_disp);
   ASSERT_FALSE(thunk_in_gap);  // There should be no thunk.
 
@@ -262,8 +264,10 @@
   };
 
   constexpr uint32_t just_over_max_negative_disp = 16 * MB - 4u /* PC adjustment */;
-  bool thunk_in_gap = Create2MethodsWithGap(kNopCode, ArrayRef<const LinkerPatch>(),
-                                            method3_code, method3_patches,
+  bool thunk_in_gap = Create2MethodsWithGap(kNopCode,
+                                            ArrayRef<const LinkerPatch>(),
+                                            method3_code,
+                                            ArrayRef<const LinkerPatch>(method3_patches),
                                             just_over_max_negative_disp - bl_offset_in_method3);
   ASSERT_FALSE(thunk_in_gap);  // There should be no thunk.
 
@@ -282,8 +286,10 @@
   };
 
   constexpr uint32_t just_over_max_positive_disp = 16 * MB + 4u /* PC adjustment */;
-  bool thunk_in_gap = Create2MethodsWithGap(method1_code, method1_patches,
-                                            kNopCode, ArrayRef<const LinkerPatch>(),
+  bool thunk_in_gap = Create2MethodsWithGap(method1_code,
+                                            ArrayRef<const LinkerPatch>(method1_patches),
+                                            kNopCode,
+                                            ArrayRef<const LinkerPatch>(),
                                             bl_offset_in_method1 + just_over_max_positive_disp);
   ASSERT_TRUE(thunk_in_gap);
 
@@ -311,8 +317,10 @@
   };
 
   constexpr uint32_t just_over_max_negative_disp = 16 * MB + 2 - 4u /* PC adjustment */;
-  bool thunk_in_gap = Create2MethodsWithGap(kNopCode, ArrayRef<const LinkerPatch>(),
-                                            method3_code, method3_patches,
+  bool thunk_in_gap = Create2MethodsWithGap(kNopCode,
+                                            ArrayRef<const LinkerPatch>(),
+                                            method3_code,
+                                            ArrayRef<const LinkerPatch>(method3_patches),
                                             just_over_max_negative_disp - bl_offset_in_method3);
   ASSERT_FALSE(thunk_in_gap);  // There should be a thunk but it should be after the method2.
 
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index 29355d6..6b9c530 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -108,7 +108,7 @@
     if (!current_method_thunks_.empty()) {
       uint32_t aligned_offset = CompiledMethod::AlignCode(offset, kArm64);
       if (kIsDebugBuild) {
-        CHECK(IsAligned<kAdrpThunkSize>(current_method_thunks_.size()));
+        CHECK_ALIGNED(current_method_thunks_.size(), kAdrpThunkSize);
         size_t num_thunks = current_method_thunks_.size() / kAdrpThunkSize;
         CHECK_LE(num_thunks, processed_adrp_thunks_);
         for (size_t i = 0u; i != num_thunks; ++i) {
@@ -203,7 +203,7 @@
       if ((adrp & 0x9f000000u) != 0x90000000u) {
         CHECK(fix_cortex_a53_843419_);
         CHECK_EQ(adrp & 0xfc000000u, 0x14000000u);  // B <thunk>
-        CHECK(IsAligned<kAdrpThunkSize>(current_method_thunks_.size()));
+        CHECK_ALIGNED(current_method_thunks_.size(), kAdrpThunkSize);
         size_t num_thunks = current_method_thunks_.size() / kAdrpThunkSize;
         CHECK_LE(num_thunks, processed_adrp_thunks_);
         uint32_t b_offset = patch_offset - literal_offset + pc_insn_offset;
diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc
index 21f9367..b3af4c6 100644
--- a/compiler/linker/arm64/relative_patcher_arm64_test.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc
@@ -66,7 +66,7 @@
     // We want to put the method3 at a very precise offset.
     const uint32_t last_method_offset = method1_offset + distance_without_thunks;
     const uint32_t gap_end = last_method_offset - sizeof(OatQuickMethodHeader);
-    CHECK(IsAligned<kArm64Alignment>(gap_end));
+    CHECK_ALIGNED(gap_end, kArm64Alignment);
 
     // Fill the gap with intermediate methods in chunks of 2MiB and the last in [2MiB, 4MiB).
     // (This allows deduplicating the small chunks to avoid using 256MiB of memory for +-128MiB
@@ -396,8 +396,10 @@
   };
 
   constexpr uint32_t max_positive_disp = 128 * MB - 4u;
-  uint32_t last_method_idx = Create2MethodsWithGap(method1_code, method1_patches,
-                                                   kNopCode, ArrayRef<const LinkerPatch>(),
+  uint32_t last_method_idx = Create2MethodsWithGap(method1_code,
+                                                   ArrayRef<const LinkerPatch>(method1_patches),
+                                                   kNopCode,
+                                                   ArrayRef<const LinkerPatch>(),
                                                    bl_offset_in_method1 + max_positive_disp);
   ASSERT_EQ(expected_last_method_idx, last_method_idx);
 
@@ -420,8 +422,10 @@
   };
 
   constexpr uint32_t max_negative_disp = 128 * MB;
-  uint32_t last_method_idx = Create2MethodsWithGap(kNopCode, ArrayRef<const LinkerPatch>(),
-                                                   last_method_code, last_method_patches,
+  uint32_t last_method_idx = Create2MethodsWithGap(kNopCode,
+                                                   ArrayRef<const LinkerPatch>(),
+                                                   last_method_code,
+                                                   ArrayRef<const LinkerPatch>(last_method_patches),
                                                    max_negative_disp - bl_offset_in_last_method);
   uint32_t method1_offset = GetMethodOffset(1u);
   uint32_t last_method_offset = GetMethodOffset(last_method_idx);
@@ -445,7 +449,10 @@
 
   constexpr uint32_t just_over_max_positive_disp = 128 * MB;
   uint32_t last_method_idx = Create2MethodsWithGap(
-      method1_code, method1_patches, kNopCode, ArrayRef<const LinkerPatch>(),
+      method1_code,
+      ArrayRef<const LinkerPatch>(method1_patches),
+      kNopCode,
+      ArrayRef<const LinkerPatch>(),
       bl_offset_in_method1 + just_over_max_positive_disp);
   ASSERT_EQ(expected_last_method_idx, last_method_idx);
 
@@ -474,7 +481,8 @@
 
   constexpr uint32_t just_over_max_negative_disp = 128 * MB + 4;
   uint32_t last_method_idx = Create2MethodsWithGap(
-      kNopCode, ArrayRef<const LinkerPatch>(), last_method_code, last_method_patches,
+      kNopCode, ArrayRef<const LinkerPatch>(), last_method_code,
+      ArrayRef<const LinkerPatch>(last_method_patches),
       just_over_max_negative_disp - bl_offset_in_last_method);
   uint32_t method1_offset = GetMethodOffset(1u);
   uint32_t last_method_offset = GetMethodOffset(last_method_idx);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index a98a304..4318ea5 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -374,9 +374,7 @@
       uint32_t quick_code_offset = 0;
 
       const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-      CHECK(quick_code != nullptr);
       uint32_t code_size = quick_code->size() * sizeof(uint8_t);
-      CHECK_NE(code_size, 0U);
       uint32_t thumb_offset = compiled_method->CodeDelta();
 
       // Deduplicate code arrays if we are not producing debuggable code.
@@ -394,16 +392,18 @@
         }
       }
 
-      MethodReference method_ref(dex_file_, it.GetMemberIndex());
-      auto method_lb = writer_->method_offset_map_.map.lower_bound(method_ref);
-      if (method_lb != writer_->method_offset_map_.map.end() &&
-          !writer_->method_offset_map_.map.key_comp()(method_ref, method_lb->first)) {
-        // TODO: Should this be a hard failure?
-        LOG(WARNING) << "Multiple definitions of "
-            << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file)
-            << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : "");
-      } else {
-        writer_->method_offset_map_.map.PutBefore(method_lb, method_ref, quick_code_offset);
+      if (code_size != 0) {
+        MethodReference method_ref(dex_file_, it.GetMemberIndex());
+        auto method_lb = writer_->method_offset_map_.map.lower_bound(method_ref);
+        if (method_lb != writer_->method_offset_map_.map.end() &&
+            !writer_->method_offset_map_.map.key_comp()(method_ref, method_lb->first)) {
+          // TODO: Should this be a hard failure?
+          LOG(WARNING) << "Multiple definitions of "
+              << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file)
+              << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : "");
+        } else {
+          writer_->method_offset_map_.map.PutBefore(method_lb, method_ref, quick_code_offset);
+        }
       }
 
       // Update quick method header.
@@ -411,21 +411,24 @@
       OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
       uint32_t mapping_table_offset = method_header->mapping_table_offset_;
       uint32_t vmap_table_offset = method_header->vmap_table_offset_;
+      // If we don't have quick code, then we must have a vmap, as that is how the dex2dex
+      // compiler records its transformations.
+      DCHECK(quick_code != nullptr || vmap_table_offset != 0);
       uint32_t gc_map_offset = method_header->gc_map_offset_;
       // The code offset was 0 when the mapping/vmap table offset was set, so it's set
       // to 0-offset and we need to adjust it by code_offset.
       uint32_t code_offset = quick_code_offset - thumb_offset;
-      if (mapping_table_offset != 0u) {
+      if (mapping_table_offset != 0u && code_offset != 0u) {
         mapping_table_offset += code_offset;
-        DCHECK_LT(mapping_table_offset, code_offset);
+        DCHECK_LT(mapping_table_offset, code_offset) << "Overflow in oat offsets";
       }
-      if (vmap_table_offset != 0u) {
+      if (vmap_table_offset != 0u && code_offset != 0u) {
         vmap_table_offset += code_offset;
-        DCHECK_LT(vmap_table_offset, code_offset);
+        DCHECK_LT(vmap_table_offset, code_offset) << "Overflow in oat offsets";
       }
-      if (gc_map_offset != 0u) {
+      if (gc_map_offset != 0u && code_offset != 0u) {
         gc_map_offset += code_offset;
-        DCHECK_LT(gc_map_offset, code_offset);
+        DCHECK_LT(gc_map_offset, code_offset) << "Overflow in oat offsets";
       }
       uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
       uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
@@ -534,7 +537,7 @@
                               const ClassDataItemIterator& it,
                               uint32_t thumb_offset) {
     offset_ = writer_->relative_patcher_->ReserveSpace(
-              offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
+        offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
     offset_ = compiled_method->AlignCode(offset_);
     DCHECK_ALIGNED_PARAM(offset_,
                          GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
@@ -619,15 +622,19 @@
         *dex_file_, it.GetMemberIndex(), dex_cache, NullHandle<mirror::ClassLoader>(), nullptr,
         invoke_type);
     if (method == nullptr) {
-      LOG(ERROR) << "Unexpected failure to resolve a method: "
-                 << PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
+      LOG(INTERNAL_FATAL) << "Unexpected failure to resolve a method: "
+                          << PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
       soa.Self()->AssertPendingException();
       mirror::Throwable* exc = soa.Self()->GetException();
       std::string dump = exc->Dump();
       LOG(FATAL) << dump;
+      UNREACHABLE();
     }
-    method->SetEntryPointFromQuickCompiledCodePtrSize(reinterpret_cast<void*>(offsets.code_offset_),
-                                                      pointer_size_);
+
+    if (compiled_method != nullptr && compiled_method->GetQuickCode()->size() != 0) {
+      method->SetEntryPointFromQuickCompiledCodePtrSize(
+          reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
+    }
 
     return true;
   }
@@ -689,85 +696,82 @@
       OutputStream* out = out_;
 
       const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
-      if (quick_code != nullptr) {
-        // Need a wrapper if we create a copy for patching.
-        ArrayRef<const uint8_t> wrapped(*quick_code);
-        uint32_t code_size = quick_code->size() * sizeof(uint8_t);
-        CHECK_NE(code_size, 0U);
+      // Need a wrapper if we create a copy for patching.
+      ArrayRef<const uint8_t> wrapped(*quick_code);
+      uint32_t code_size = quick_code->size() * sizeof(uint8_t);
 
-        // Deduplicate code arrays.
-        const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
-        if (method_offsets.code_offset_ >= offset_) {
-          offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
-          if (offset_ == 0u) {
-            ReportWriteFailure("relative call thunk", it);
-            return false;
-          }
-          uint32_t aligned_offset = compiled_method->AlignCode(offset_);
-          uint32_t aligned_code_delta = aligned_offset - offset_;
-          if (aligned_code_delta != 0) {
-            if (!writer_->WriteCodeAlignment(out, aligned_code_delta)) {
-              ReportWriteFailure("code alignment padding", it);
-              return false;
-            }
-            offset_ += aligned_code_delta;
-            DCHECK_OFFSET_();
-          }
-          DCHECK_ALIGNED_PARAM(offset_,
-                               GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
-          DCHECK_EQ(method_offsets.code_offset_,
-                    offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
-              << PrettyMethod(it.GetMemberIndex(), *dex_file_);
-          const OatQuickMethodHeader& method_header =
-              oat_class->method_headers_[method_offsets_index_];
-          writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header));
-          if (!out->WriteFully(&method_header, sizeof(method_header))) {
-            ReportWriteFailure("method header", it);
-            return false;
-          }
-          writer_->size_method_header_ += sizeof(method_header);
-          offset_ += sizeof(method_header);
-          DCHECK_OFFSET_();
-
-          if (!compiled_method->GetPatches().empty()) {
-            patched_code_.assign(quick_code->begin(), quick_code->end());
-            wrapped = ArrayRef<const uint8_t>(patched_code_);
-            for (const LinkerPatch& patch : compiled_method->GetPatches()) {
-              if (patch.Type() == kLinkerPatchCallRelative) {
-                // NOTE: Relative calls across oat files are not supported.
-                uint32_t target_offset = GetTargetOffset(patch);
-                uint32_t literal_offset = patch.LiteralOffset();
-                writer_->relative_patcher_->PatchCall(&patched_code_, literal_offset,
-                                                       offset_ + literal_offset, target_offset);
-              } else if (patch.Type() == kLinkerPatchDexCacheArray) {
-                uint32_t target_offset = GetDexCacheOffset(patch);
-                uint32_t literal_offset = patch.LiteralOffset();
-                writer_->relative_patcher_->PatchDexCacheReference(&patched_code_, patch,
-                                                                   offset_ + literal_offset,
-                                                                   target_offset);
-              } else if (patch.Type() == kLinkerPatchCall) {
-                uint32_t target_offset = GetTargetOffset(patch);
-                PatchCodeAddress(&patched_code_, patch.LiteralOffset(), target_offset);
-              } else if (patch.Type() == kLinkerPatchMethod) {
-                ArtMethod* method = GetTargetMethod(patch);
-                PatchMethodAddress(&patched_code_, patch.LiteralOffset(), method);
-              } else if (patch.Type() == kLinkerPatchType) {
-                mirror::Class* type = GetTargetType(patch);
-                PatchObjectAddress(&patched_code_, patch.LiteralOffset(), type);
-              }
-            }
-          }
-
-          writer_->oat_header_->UpdateChecksum(wrapped.data(), code_size);
-          if (!out->WriteFully(wrapped.data(), code_size)) {
-            ReportWriteFailure("method code", it);
-            return false;
-          }
-          writer_->size_code_ += code_size;
-          offset_ += code_size;
+      // Deduplicate code arrays.
+      const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
+      if (method_offsets.code_offset_ > offset_) {
+        offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
+        if (offset_ == 0u) {
+          ReportWriteFailure("relative call thunk", it);
+          return false;
         }
+        uint32_t aligned_offset = compiled_method->AlignCode(offset_);
+        uint32_t aligned_code_delta = aligned_offset - offset_;
+        if (aligned_code_delta != 0) {
+          if (!writer_->WriteCodeAlignment(out, aligned_code_delta)) {
+            ReportWriteFailure("code alignment padding", it);
+            return false;
+          }
+          offset_ += aligned_code_delta;
+          DCHECK_OFFSET_();
+        }
+        DCHECK_ALIGNED_PARAM(offset_,
+                             GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
+        DCHECK_EQ(method_offsets.code_offset_,
+                  offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
+            << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+        const OatQuickMethodHeader& method_header =
+            oat_class->method_headers_[method_offsets_index_];
+        writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header));
+        if (!out->WriteFully(&method_header, sizeof(method_header))) {
+          ReportWriteFailure("method header", it);
+          return false;
+        }
+        writer_->size_method_header_ += sizeof(method_header);
+        offset_ += sizeof(method_header);
         DCHECK_OFFSET_();
+
+        if (!compiled_method->GetPatches().empty()) {
+          patched_code_.assign(quick_code->begin(), quick_code->end());
+          wrapped = ArrayRef<const uint8_t>(patched_code_);
+          for (const LinkerPatch& patch : compiled_method->GetPatches()) {
+            if (patch.Type() == kLinkerPatchCallRelative) {
+              // NOTE: Relative calls across oat files are not supported.
+              uint32_t target_offset = GetTargetOffset(patch);
+              uint32_t literal_offset = patch.LiteralOffset();
+              writer_->relative_patcher_->PatchCall(&patched_code_, literal_offset,
+                                                     offset_ + literal_offset, target_offset);
+            } else if (patch.Type() == kLinkerPatchDexCacheArray) {
+              uint32_t target_offset = GetDexCacheOffset(patch);
+              uint32_t literal_offset = patch.LiteralOffset();
+              writer_->relative_patcher_->PatchDexCacheReference(&patched_code_, patch,
+                                                                 offset_ + literal_offset,
+                                                                 target_offset);
+            } else if (patch.Type() == kLinkerPatchCall) {
+              uint32_t target_offset = GetTargetOffset(patch);
+              PatchCodeAddress(&patched_code_, patch.LiteralOffset(), target_offset);
+            } else if (patch.Type() == kLinkerPatchMethod) {
+              ArtMethod* method = GetTargetMethod(patch);
+              PatchMethodAddress(&patched_code_, patch.LiteralOffset(), method);
+            } else if (patch.Type() == kLinkerPatchType) {
+              mirror::Class* type = GetTargetType(patch);
+              PatchObjectAddress(&patched_code_, patch.LiteralOffset(), type);
+            }
+          }
+        }
+
+        writer_->oat_header_->UpdateChecksum(wrapped.data(), code_size);
+        if (!out->WriteFully(wrapped.data(), code_size)) {
+          ReportWriteFailure("method code", it);
+          return false;
+        }
+        writer_->size_code_ += code_size;
+        offset_ += code_size;
       }
+      DCHECK_OFFSET_();
       ++method_offsets_index_;
     }
 
diff --git a/compiler/optimizing/boolean_simplifier.cc b/compiler/optimizing/boolean_simplifier.cc
index daf7d67..84201c3 100644
--- a/compiler/optimizing/boolean_simplifier.cc
+++ b/compiler/optimizing/boolean_simplifier.cc
@@ -119,6 +119,14 @@
   // Check if the selection negates/preserves the value of the condition and
   // if so, generate a suitable replacement instruction.
   HInstruction* if_condition = if_instruction->InputAt(0);
+
+  // Don't change FP compares.  The definition of compares involving NaNs forces
+  // the compares to be done as written by the user.
+  if (if_condition->IsCondition() &&
+      Primitive::IsFloatingPointType(if_condition->InputAt(0)->GetType())) {
+    return;
+  }
+
   HInstruction* replacement;
   if (NegatesCondition(true_value, false_value)) {
     replacement = GetOppositeCondition(if_condition);
@@ -146,11 +154,6 @@
   // entry block. Any following blocks would have had the join block
   // as a dominator, and `MergeWith` handles changing that to the
   // entry block.
-
-  // Remove the original condition if it is now unused.
-  if (!if_condition->HasUses()) {
-    if_condition->GetBlock()->RemoveInstructionOrPhi(if_condition);
-  }
 }
 
 void HBooleanSimplifier::Run() {
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 54155db..1319f2c 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -259,14 +259,20 @@
   return false;
 }
 
-bool HGraphBuilder::IsBlockInPcRange(HBasicBlock* block,
-                                     uint32_t dex_pc_start,
-                                     uint32_t dex_pc_end) {
-  uint32_t dex_pc = block->GetDexPc();
-  return block != entry_block_
-      && block != exit_block_
-      && dex_pc >= dex_pc_start
-      && dex_pc < dex_pc_end;
+static const DexFile::TryItem* GetTryItem(HBasicBlock* block,
+                                          const DexFile::CodeItem& code_item,
+                                          const ArenaBitVector& can_block_throw) {
+  DCHECK(!block->IsSingleTryBoundary());
+
+  // Block does not contain throwing instructions. Even if it is covered by
+  // a TryItem, we will consider it not in a try block.
+  if (!can_block_throw.IsBitSet(block->GetBlockId())) {
+    return nullptr;
+  }
+
+  // Instructions in the block may throw. Find a TryItem covering this block.
+  int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc());
+  return (try_item_idx == -1) ? nullptr : DexFile::GetTryItems(code_item, try_item_idx);
 }
 
 void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item) {
@@ -327,108 +333,129 @@
     return;
   }
 
-  for (size_t idx = 0; idx < code_item.tries_size_; ++idx) {
-    const DexFile::TryItem* try_item = DexFile::GetTryItems(code_item, idx);
-    uint32_t try_start = try_item->start_addr_;
-    uint32_t try_end = try_start + try_item->insn_count_;
+  // Bit vector stores information on which blocks contain throwing instructions.
+  // Must be expandable because catch blocks may be split into two.
+  ArenaBitVector can_block_throw(arena_, graph_->GetBlocks().Size(), /* expandable */ true);
 
-    // Iterate over all blocks in the dex pc range of the TryItem and:
-    //   (a) split edges which enter/exit the try range,
-    //   (b) create TryBoundary instructions in the new blocks,
-    //   (c) link the new blocks to corresponding exception handlers.
-    for (uint32_t inner_pc = try_start; inner_pc < try_end; ++inner_pc) {
-      HBasicBlock* try_block = FindBlockStartingAt(inner_pc);
-      if (try_block == nullptr) {
-        continue;
+  // Scan blocks and mark those which contain throwing instructions.
+  for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) {
+    HBasicBlock* block = graph_->GetBlocks().Get(block_id);
+    bool can_throw = false;
+    for (HInstructionIterator insn(block->GetInstructions()); !insn.Done(); insn.Advance()) {
+      if (insn.Current()->CanThrow()) {
+        can_throw = true;
+        break;
       }
+    }
 
-      if (try_block->IsCatchBlock()) {
+    if (can_throw) {
+      if (block->IsCatchBlock()) {
         // Catch blocks are always considered an entry point into the TryItem in
-        // order to avoid splitting exceptional edges (they might not have been
-        // created yet). We separate the move-exception (if present) from the
-        // rest of the block and insert a TryBoundary after it, creating a
-        // landing pad for the exceptional edges.
-        HInstruction* first_insn = try_block->GetFirstInstruction();
-        HInstruction* split_position = nullptr;
+        // order to avoid splitting exceptional edges. We split the block after
+        // the move-exception (if present) and mark the first part non-throwing.
+        // Later on, a TryBoundary will be inserted between the two blocks.
+        HInstruction* first_insn = block->GetFirstInstruction();
         if (first_insn->IsLoadException()) {
           // Catch block starts with a LoadException. Split the block after the
           // StoreLocal that must come after the load.
           DCHECK(first_insn->GetNext()->IsStoreLocal());
-          split_position = first_insn->GetNext()->GetNext();
+          block = block->SplitBefore(first_insn->GetNext()->GetNext());
         } else {
-          // Catch block does not obtain the exception. Split at the beginning
-          // to create an empty catch block.
-          split_position = first_insn;
-        }
-        DCHECK(split_position != nullptr);
-        HBasicBlock* catch_block = try_block;
-        try_block = catch_block->SplitBefore(split_position);
-        SplitTryBoundaryEdge(catch_block, try_block, HTryBoundary::kEntry, code_item, *try_item);
-      } else {
-        // For non-catch blocks, find predecessors which are not covered by the
-        // same TryItem range. Such edges enter the try block and will have
-        // a TryBoundary inserted.
-        for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
-          HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
-          if (predecessor->IsSingleTryBoundary()) {
-            // The edge was already split because of an exit from a neighbouring
-            // TryItem. We split it again and insert an entry point.
-            if (kIsDebugBuild) {
-              HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary();
-              DCHECK(!last_insn->IsEntry());
-              DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block);
-              DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i));
-              DCHECK(!IsBlockInPcRange(predecessor->GetSinglePredecessor(), try_start, try_end));
-            }
-          } else if (!IsBlockInPcRange(predecessor, try_start, try_end)) {
-            // This is an entry point into the TryItem and the edge has not been
-            // split yet. That means that `predecessor` is not in a TryItem, or
-            // it is in a different TryItem and we happened to iterate over this
-            // block first. We split the edge and insert an entry point.
-          } else {
-            // Not an edge on the boundary of the try block.
-            continue;
-          }
-          SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item);
+          // Catch block does not load the exception. Split at the beginning to
+          // create an empty catch block.
+          block = block->SplitBefore(first_insn);
         }
       }
+      can_block_throw.SetBit(block->GetBlockId());
+    }
+  }
 
-      // Find successors which are not covered by the same TryItem range. Such
-      // edges exit the try block and will have a TryBoundary inserted.
-      for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) {
-        HBasicBlock* successor = try_block->GetSuccessors().Get(i);
-        if (successor->IsCatchBlock()) {
-          // A catch block is always considered an entry point into its TryItem.
-          // We therefore assume this is an exit point, regardless of whether
-          // the catch block is in a different TryItem or not.
-        } else if (successor->IsSingleTryBoundary()) {
-          // The edge was already split because of an entry into a neighbouring
-          // TryItem. We split it again and insert an exit.
-          if (kIsDebugBuild) {
-            HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary();
-            DCHECK_EQ(try_block, successor->GetSinglePredecessor());
-            DCHECK(last_insn->IsEntry());
-            DCHECK(!IsBlockInPcRange(last_insn->GetNormalFlowSuccessor(), try_start, try_end));
-          }
-        } else if (!IsBlockInPcRange(successor, try_start, try_end)) {
-          // This is an exit out of the TryItem and the edge has not been split
-          // yet. That means that either `successor` is not in a TryItem, or it
-          // is in a different TryItem and we happened to iterate over this
-          // block first. We split the edge and insert an exit.
-          HInstruction* last_instruction = try_block->GetLastInstruction();
-          if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) {
-            DCHECK_EQ(successor, exit_block_);
-            // Control flow exits the try block with a Return(Void). Because
-            // splitting the edge would invalidate the invariant that Return
-            // always jumps to Exit, we move the Return outside the try block.
-            successor = try_block->SplitBefore(last_instruction);
-          }
-        } else {
-          // Not an edge on the boundary of the try block.
-          continue;
+  // Iterate over all blocks, find those covered by some TryItem and:
+  //   (a) split edges which enter/exit the try range,
+  //   (b) create TryBoundary instructions in the new blocks,
+  //   (c) link the new blocks to corresponding exception handlers.
+  // We cannot iterate only over blocks in `branch_targets_` because switch-case
+  // blocks share the same dex_pc.
+  for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) {
+    HBasicBlock* try_block = graph_->GetBlocks().Get(block_id);
+
+    // TryBoundary blocks are added at the end of the list and not iterated over.
+    DCHECK(!try_block->IsSingleTryBoundary());
+
+    // Find the TryItem for this block.
+    const DexFile::TryItem* try_item = GetTryItem(try_block, code_item, can_block_throw);
+    if (try_item == nullptr) {
+      continue;
+    }
+
+    // Catch blocks were split earlier and cannot throw.
+    DCHECK(!try_block->IsCatchBlock());
+
+    // Find predecessors which are not covered by the same TryItem range. Such
+    // edges enter the try block and will have a TryBoundary inserted.
+    for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
+      HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
+      if (predecessor->IsSingleTryBoundary()) {
+        // The edge was already split because of an exit from a neighbouring
+        // TryItem. We split it again and insert an entry point.
+        if (kIsDebugBuild) {
+          HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary();
+          const DexFile::TryItem* predecessor_try_item =
+              GetTryItem(predecessor->GetSinglePredecessor(), code_item, can_block_throw);
+          DCHECK(!last_insn->IsEntry());
+          DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block);
+          DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i));
+          DCHECK_NE(try_item, predecessor_try_item);
         }
-        SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, *try_item);
+      } else if (GetTryItem(predecessor, code_item, can_block_throw) != try_item) {
+        // This is an entry point into the TryItem and the edge has not been
+        // split yet. That means that `predecessor` is not in a TryItem, or
+        // it is in a different TryItem and we happened to iterate over this
+        // block first. We split the edge and insert an entry point.
+      } else {
+        // Not an edge on the boundary of the try block.
+        continue;
       }
+      SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item);
+    }
+
+    // Find successors which are not covered by the same TryItem range. Such
+    // edges exit the try block and will have a TryBoundary inserted.
+    for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) {
+      HBasicBlock* successor = try_block->GetSuccessors().Get(i);
+      if (successor->IsCatchBlock()) {
+        // A catch block is always considered an entry point into its TryItem.
+        // We therefore assume this is an exit point, regardless of whether
+        // the catch block is in a different TryItem or not.
+      } else if (successor->IsSingleTryBoundary()) {
+        // The edge was already split because of an entry into a neighbouring
+        // TryItem. We split it again and insert an exit.
+        if (kIsDebugBuild) {
+          HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary();
+          const DexFile::TryItem* successor_try_item =
+              GetTryItem(last_insn->GetNormalFlowSuccessor(), code_item, can_block_throw);
+          DCHECK_EQ(try_block, successor->GetSinglePredecessor());
+          DCHECK(last_insn->IsEntry());
+          DCHECK_NE(try_item, successor_try_item);
+        }
+      } else if (GetTryItem(successor, code_item, can_block_throw) != try_item) {
+        // This is an exit out of the TryItem and the edge has not been split
+        // yet. That means that either `successor` is not in a TryItem, or it
+        // is in a different TryItem and we happened to iterate over this
+        // block first. We split the edge and insert an exit.
+        HInstruction* last_instruction = try_block->GetLastInstruction();
+        if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) {
+          DCHECK_EQ(successor, exit_block_);
+          // Control flow exits the try block with a Return(Void). Because
+          // splitting the edge would invalidate the invariant that Return
+          // always jumps to Exit, we move the Return outside the try block.
+          successor = try_block->SplitBefore(last_instruction);
+        }
+      } else {
+        // Not an edge on the boundary of the try block.
+        continue;
+      }
+      SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, *try_item);
     }
   }
 }
@@ -487,14 +514,14 @@
   // Add the suspend check to the entry block.
   entry_block_->AddInstruction(new (arena_) HSuspendCheck(0));
   entry_block_->AddInstruction(new (arena_) HGoto());
+  // Add the exit block at the end.
+  graph_->AddBlock(exit_block_);
 
   // Iterate over blocks covered by TryItems and insert TryBoundaries at entry
   // and exit points. This requires all control-flow instructions and
   // non-exceptional edges to have been created.
   InsertTryBoundaryBlocks(code_item);
 
-  // Add the exit block at the end to give it the highest id.
-  graph_->AddBlock(exit_block_);
   return true;
 }
 
@@ -563,11 +590,10 @@
         uint32_t target = dex_pc + table.GetEntryAt(i + offset);
         FindOrCreateBlockStartingAt(target);
 
-        // The next case gets its own block.
-        if (i < num_entries) {
-          block = new (arena_) HBasicBlock(graph_, target);
-          branch_targets_.Put(table.GetDexPcForIndex(i), block);
-        }
+        // Create a block for the switch-case logic. The block gets the dex_pc
+        // of the SWITCH instruction because it is part of its semantics.
+        block = new (arena_) HBasicBlock(graph_, dex_pc);
+        branch_targets_.Put(table.GetDexPcForIndex(i), block);
       }
 
       // Fall-through. Add a block if there is more code afterwards.
@@ -649,7 +675,7 @@
 
 void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction,
                                   Primitive::Type type,
-                                  HCompare::Bias bias,
+                                  ComparisonBias bias,
                                   uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
   HInstruction* second = LoadLocal(instruction.VRegC(), type);
@@ -730,6 +756,35 @@
   current_block_ = nullptr;
 }
 
+void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register,
+                                                  uint32_t dex_pc,
+                                                  HInvoke* actual_string) {
+  if (!graph_->IsDebuggable()) {
+    // Notify that we cannot compile with baseline. The dex registers aliasing
+    // with `original_dex_register` will be handled when we optimize
+    // (see HInstructionSimplifer::VisitFakeString).
+    can_use_baseline_for_string_init_ = false;
+    return;
+  }
+  const VerifiedMethod* verified_method =
+      compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
+  if (verified_method != nullptr) {
+    UpdateLocal(original_dex_register, actual_string);
+    const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
+        verified_method->GetStringInitPcRegMap();
+    auto map_it = string_init_map.find(dex_pc);
+    if (map_it != string_init_map.end()) {
+      std::set<uint32_t> reg_set = map_it->second;
+      for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
+        HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot);
+        UpdateLocal(*set_it, load_local);
+      }
+    }
+  } else {
+    can_use_baseline_for_string_init_ = false;
+  }
+}
+
 bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
                                 uint32_t dex_pc,
                                 uint32_t method_idx,
@@ -971,34 +1026,23 @@
   if (clinit_check_requirement == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit) {
     // Add the class initialization check as last input of `invoke`.
     DCHECK(clinit_check != nullptr);
+    DCHECK(!is_string_init);
     invoke->SetArgumentAt(argument_index, clinit_check);
+    argument_index++;
   }
 
-  current_block_->AddInstruction(invoke);
-  latest_result_ = invoke;
-
   // Add move-result for StringFactory method.
   if (is_string_init) {
     uint32_t orig_this_reg = is_range ? register_index : args[0];
-    UpdateLocal(orig_this_reg, invoke);
-    const VerifiedMethod* verified_method =
-        compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
-    if (verified_method == nullptr) {
-      LOG(WARNING) << "No verified method for method calling String.<init>: "
-                   << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_);
-      return false;
-    }
-    const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
-        verified_method->GetStringInitPcRegMap();
-    auto map_it = string_init_map.find(dex_pc);
-    if (map_it != string_init_map.end()) {
-      std::set<uint32_t> reg_set = map_it->second;
-      for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
-        HInstruction* load_local = LoadLocal(orig_this_reg, Primitive::kPrimNot);
-        UpdateLocal(*set_it, load_local);
-      }
-    }
+    HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+    invoke->SetArgumentAt(argument_index, fake_string);
+    current_block_->AddInstruction(invoke);
+    PotentiallySimplifyFakeString(orig_this_reg, dex_pc, invoke);
+  } else {
+    current_block_->AddInstruction(invoke);
   }
+  latest_result_ = invoke;
+
   return true;
 }
 
@@ -2213,10 +2257,10 @@
     case Instruction::NEW_INSTANCE: {
       uint16_t type_index = instruction.VRegB_21c();
       if (compiler_driver_->IsStringTypeIndex(type_index, dex_file_)) {
-        // Turn new-instance of string into a const 0.
         int32_t register_index = instruction.VRegA();
-        HNullConstant* constant = graph_->GetNullConstant();
-        UpdateLocal(register_index, constant);
+        HFakeString* fake_string = new (arena_) HFakeString();
+        current_block_->AddInstruction(fake_string);
+        UpdateLocal(register_index, fake_string);
       } else {
         QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
             ? kQuickAllocObjectWithAccessCheck
@@ -2303,27 +2347,27 @@
     }
 
     case Instruction::CMP_LONG: {
-      Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimLong, ComparisonBias::kNoBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, ComparisonBias::kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, ComparisonBias::kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, ComparisonBias::kLtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, ComparisonBias::kLtBias, dex_pc);
       break;
     }
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index cae762b..76610f5 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -54,6 +54,7 @@
         return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])),
         code_start_(nullptr),
         latest_result_(nullptr),
+        can_use_baseline_for_string_init_(true),
         compilation_stats_(compiler_stats) {}
 
   // Only for unit testing.
@@ -72,10 +73,15 @@
         return_type_(return_type),
         code_start_(nullptr),
         latest_result_(nullptr),
+        can_use_baseline_for_string_init_(true),
         compilation_stats_(nullptr) {}
 
   bool BuildGraph(const DexFile::CodeItem& code);
 
+  bool CanUseBaselineForStringInit() const {
+    return can_use_baseline_for_string_init_;
+  }
+
   static constexpr const char* kBuilderPassName = "builder";
 
  private:
@@ -98,9 +104,6 @@
   HBasicBlock* FindBlockStartingAt(int32_t dex_pc) const;
   HBasicBlock* FindOrCreateBlockStartingAt(int32_t dex_pc);
 
-  // Returns whether the dex_pc of `block` lies within the given range.
-  bool IsBlockInPcRange(HBasicBlock* block, uint32_t dex_pc_start, uint32_t dex_pc_end);
-
   // Adds new blocks to `branch_targets_` starting at the limits of TryItems and
   // their exception handlers.
   void CreateBlocksForTryCatch(const DexFile::CodeItem& code_item);
@@ -139,7 +142,7 @@
 
   void Binop_23x_cmp(const Instruction& instruction,
                      Primitive::Type type,
-                     HCompare::Bias bias,
+                     ComparisonBias bias,
                      uint32_t dex_pc);
 
   template<typename T>
@@ -254,6 +257,10 @@
   // Returns whether `type_index` points to the outer-most compiling method's class.
   bool IsOutermostCompilingClass(uint16_t type_index) const;
 
+  void PotentiallySimplifyFakeString(uint16_t original_dex_register,
+                                     uint32_t dex_pc,
+                                     HInvoke* invoke);
+
   ArenaAllocator* const arena_;
 
   // A list of the size of the dex code holding block information for
@@ -293,6 +300,11 @@
   // used by move-result instructions.
   HInstruction* latest_result_;
 
+  // We need to know whether we have built a graph that has calls to StringFactory
+  // and hasn't gone through the verifier. If the following flag is `false`, then
+  // we cannot compile with baseline.
+  bool can_use_baseline_for_string_init_;
+
   OptimizingCompilerStats* compilation_stats_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 4cecd61..eb63b49 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -294,6 +294,12 @@
     allocated_registers_.Add(location);
   }
 
+  bool HasAllocatedRegister(bool is_core, int reg) const {
+    return is_core
+        ? allocated_registers_.ContainsCoreRegister(reg)
+        : allocated_registers_.ContainsFloatingPointRegister(reg);
+  }
+
   void AllocateLocations(HInstruction* instruction);
 
   // Tells whether the stack frame of the compiled method is
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index e3683ef..75b8f06 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -334,7 +334,7 @@
 #undef __
 #define __ down_cast<ArmAssembler*>(GetAssembler())->
 
-inline Condition ARMCondition(IfCondition cond) {
+inline Condition ARMSignedOrFPCondition(IfCondition cond) {
   switch (cond) {
     case kCondEQ: return EQ;
     case kCondNE: return NE;
@@ -342,24 +342,22 @@
     case kCondLE: return LE;
     case kCondGT: return GT;
     case kCondGE: return GE;
-    default:
-      LOG(FATAL) << "Unknown if condition";
   }
-  return EQ;        // Unreachable.
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
-inline Condition ARMOppositeCondition(IfCondition cond) {
+inline Condition ARMUnsignedCondition(IfCondition cond) {
   switch (cond) {
-    case kCondEQ: return NE;
-    case kCondNE: return EQ;
-    case kCondLT: return GE;
-    case kCondLE: return GT;
-    case kCondGT: return LE;
-    case kCondGE: return LT;
-    default:
-      LOG(FATAL) << "Unknown if condition";
+    case kCondEQ: return EQ;
+    case kCondNE: return NE;
+    case kCondLT: return LO;
+    case kCondLE: return LS;
+    case kCondGT: return HI;
+    case kCondGE: return HS;
   }
-  return EQ;        // Unreachable.
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
@@ -1008,6 +1006,142 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorARM::GenerateCompareWithImmediate(Register left, int32_t right) {
+  ShifterOperand operand;
+  if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, right, &operand)) {
+    __ cmp(left, operand);
+  } else {
+    Register temp = IP;
+    __ LoadImmediate(temp, right);
+    __ cmp(left, ShifterOperand(temp));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateFPJumps(HCondition* cond,
+                                                  Label* true_label,
+                                                  Label* false_label) {
+  __ vmstat();  // transfer FP status register to ARM APSR.
+  if (cond->IsFPConditionTrueIfNaN()) {
+    __ b(true_label, VS);  // VS for unordered.
+  } else if (cond->IsFPConditionFalseIfNaN()) {
+    __ b(false_label, VS);  // VS for unordered.
+  }
+  __ b(true_label, ARMSignedOrFPCondition(cond->GetCondition()));
+}
+
+void InstructionCodeGeneratorARM::GenerateLongComparesAndJumps(HCondition* cond,
+                                                               Label* true_label,
+                                                               Label* false_label) {
+  LocationSummary* locations = cond->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+  IfCondition if_cond = cond->GetCondition();
+
+  Register left_high = left.AsRegisterPairHigh<Register>();
+  Register left_low = left.AsRegisterPairLow<Register>();
+  IfCondition true_high_cond = if_cond;
+  IfCondition false_high_cond = cond->GetOppositeCondition();
+  Condition final_condition = ARMUnsignedCondition(if_cond);
+
+  // Set the conditions for the test, remembering that == needs to be
+  // decided using the low words.
+  switch (if_cond) {
+    case kCondEQ:
+    case kCondNE:
+      // Nothing to do.
+      break;
+    case kCondLT:
+      false_high_cond = kCondGT;
+      break;
+    case kCondLE:
+      true_high_cond = kCondLT;
+      break;
+    case kCondGT:
+      false_high_cond = kCondLT;
+      break;
+    case kCondGE:
+      true_high_cond = kCondGT;
+      break;
+  }
+  if (right.IsConstant()) {
+    int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+    int32_t val_low = Low32Bits(value);
+    int32_t val_high = High32Bits(value);
+
+    GenerateCompareWithImmediate(left_high, val_high);
+    if (if_cond == kCondNE) {
+      __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
+    } else if (if_cond == kCondEQ) {
+      __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
+    } else {
+      __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
+      __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
+    }
+    // Must be equal high, so compare the lows.
+    GenerateCompareWithImmediate(left_low, val_low);
+  } else {
+    Register right_high = right.AsRegisterPairHigh<Register>();
+    Register right_low = right.AsRegisterPairLow<Register>();
+
+    __ cmp(left_high, ShifterOperand(right_high));
+    if (if_cond == kCondNE) {
+      __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
+    } else if (if_cond == kCondEQ) {
+      __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
+    } else {
+      __ b(true_label, ARMSignedOrFPCondition(true_high_cond));
+      __ b(false_label, ARMSignedOrFPCondition(false_high_cond));
+    }
+    // Must be equal high, so compare the lows.
+    __ cmp(left_low, ShifterOperand(right_low));
+  }
+  // The last comparison might be unsigned.
+  __ b(true_label, final_condition);
+}
+
+void InstructionCodeGeneratorARM::GenerateCompareTestAndBranch(HIf* if_instr,
+                                                               HCondition* condition,
+                                                               Label* true_target,
+                                                               Label* false_target,
+                                                               Label* always_true_target) {
+  LocationSummary* locations = condition->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  // We don't want true_target as a nullptr.
+  if (true_target == nullptr) {
+    true_target = always_true_target;
+  }
+  bool falls_through = (false_target == nullptr);
+
+  // FP compares don't like null false_targets.
+  if (false_target == nullptr) {
+    false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+  }
+
+  Primitive::Type type = condition->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong:
+      GenerateLongComparesAndJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimFloat:
+      __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimDouble:
+      __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected compare type " << type;
+  }
+
+  if (!falls_through) {
+    __ b(false_target);
+  }
+}
+
 void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction,
                                                         Label* true_target,
                                                         Label* false_target,
@@ -1033,25 +1167,27 @@
     } else {
       // Condition has not been materialized, use its inputs as the
       // comparison and its condition as the branch condition.
+      Primitive::Type type =
+          cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
+      // Is this a long or FP comparison that has been folded into the HCondition?
+      if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+        // Generate the comparison directly.
+        GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
+                                     true_target, false_target, always_true_target);
+        return;
+      }
+
       LocationSummary* locations = cond->GetLocations();
       DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0);
       Register left = locations->InAt(0).AsRegister<Register>();
-      if (locations->InAt(1).IsRegister()) {
-        __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
+      Location right = locations->InAt(1);
+      if (right.IsRegister()) {
+        __ cmp(left, ShifterOperand(right.AsRegister<Register>()));
       } else {
-        DCHECK(locations->InAt(1).IsConstant());
-        HConstant* constant = locations->InAt(1).GetConstant();
-        int32_t value = CodeGenerator::GetInt32ValueOf(constant);
-        ShifterOperand operand;
-        if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
-          __ cmp(left, operand);
-        } else {
-          Register temp = IP;
-          __ LoadImmediate(temp, value);
-          __ cmp(left, ShifterOperand(temp));
-        }
+        DCHECK(right.IsConstant());
+        GenerateCompareWithImmediate(left, CodeGenerator::GetInt32ValueOf(right.GetConstant()));
       }
-      __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition()));
+      __ b(true_target, ARMSignedOrFPCondition(cond->AsCondition()->GetCondition()));
     }
   }
   if (false_target != nullptr) {
@@ -1104,37 +1240,88 @@
 void LocationsBuilderARM::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
-  if (cond->NeedsMaterialization()) {
-    locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+  // Handle the long/FP comparisons made in instruction simplification.
+  switch (cond->InputAt(0)->GetType()) {
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+      }
+      break;
+
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+      }
+      break;
+
+    default:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+      }
   }
 }
 
 void InstructionCodeGeneratorARM::VisitCondition(HCondition* cond) {
-  if (!cond->NeedsMaterialization()) return;
-  LocationSummary* locations = cond->GetLocations();
-  Register left = locations->InAt(0).AsRegister<Register>();
-
-  if (locations->InAt(1).IsRegister()) {
-    __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
-  } else {
-    DCHECK(locations->InAt(1).IsConstant());
-    int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant());
-    ShifterOperand operand;
-    if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
-      __ cmp(left, operand);
-    } else {
-      Register temp = IP;
-      __ LoadImmediate(temp, value);
-      __ cmp(left, ShifterOperand(temp));
-    }
+  if (!cond->NeedsMaterialization()) {
+    return;
   }
-  __ it(ARMCondition(cond->GetCondition()), kItElse);
-  __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
-         ARMCondition(cond->GetCondition()));
-  __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
-         ARMOppositeCondition(cond->GetCondition()));
+
+  LocationSummary* locations = cond->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+  Register out = locations->Out().AsRegister<Register>();
+  Label true_label, false_label;
+
+  switch (cond->InputAt(0)->GetType()) {
+    default: {
+      // Integer case.
+      if (right.IsRegister()) {
+        __ cmp(left.AsRegister<Register>(), ShifterOperand(right.AsRegister<Register>()));
+      } else {
+        DCHECK(right.IsConstant());
+        GenerateCompareWithImmediate(left.AsRegister<Register>(),
+                                     CodeGenerator::GetInt32ValueOf(right.GetConstant()));
+      }
+      __ it(ARMSignedOrFPCondition(cond->GetCondition()), kItElse);
+      __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
+             ARMSignedOrFPCondition(cond->GetCondition()));
+      __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
+             ARMSignedOrFPCondition(cond->GetOppositeCondition()));
+      return;
+    }
+    case Primitive::kPrimLong:
+      GenerateLongComparesAndJumps(cond, &true_label, &false_label);
+      break;
+    case Primitive::kPrimFloat:
+      __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>());
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    case Primitive::kPrimDouble:
+      __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()),
+               FromLowSToD(right.AsFpuRegisterPairLow<SRegister>()));
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+  }
+
+  // Convert the jumps into the result.
+  Label done_label;
+
+  // False case: result = 0.
+  __ Bind(&false_label);
+  __ LoadImmediate(out, 0);
+  __ b(&done_label);
+
+  // True case: result = 1.
+  __ Bind(&true_label);
+  __ LoadImmediate(out, 1);
+  __ Bind(&done_label);
 }
 
 void LocationsBuilderARM::VisitEqual(HEqual* comp) {
@@ -2913,7 +3100,7 @@
              ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
       __ b(&less, LT);
       __ b(&greater, GT);
-      // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags.
+      // Do LoadImmediate before the last `cmp`, as LoadImmediate might affect the status flags.
       __ LoadImmediate(out, 0);
       __ cmp(left.AsRegisterPairLow<Register>(),
              ShifterOperand(right.AsRegisterPairLow<Register>()));  // Unsigned compare.
@@ -2936,7 +3123,7 @@
       LOG(FATAL) << "Unexpected compare type " << type;
   }
   __ b(&done, EQ);
-  __ b(&less, CC);  // CC is for both: unsigned compare for longs and 'less than' for floats.
+  __ b(&less, LO);  // LO is for both: unsigned compare for longs and 'less than' for floats.
 
   __ Bind(&greater);
   __ LoadImmediate(out, 1);
@@ -3710,7 +3897,7 @@
   Register length = locations->InAt(1).AsRegister<Register>();
 
   __ cmp(index, ShifterOperand(length));
-  __ b(slow_path->GetEntryLabel(), CS);
+  __ b(slow_path->GetEntryLabel(), HS);
 }
 
 void CodeGeneratorARM::MarkGCCard(Register temp,
@@ -4365,6 +4552,18 @@
   LOG(FATAL) << "Unreachable";
 }
 
+void LocationsBuilderARM::VisitFakeString(HFakeString* instruction) {
+  DCHECK(codegen_->IsBaseline());
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorARM::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+  DCHECK(codegen_->IsBaseline());
+  // Will be generated at use site.
+}
+
 #undef __
 #undef QUICK_ENTRY_POINT
 
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 1d10293..53bd766 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -207,6 +207,14 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void GenerateCompareWithImmediate(Register left, int32_t right);
+  void GenerateCompareTestAndBranch(HIf* if_instr,
+                                    HCondition* condition,
+                                    Label* true_target,
+                                    Label* false_target,
+                                    Label* always_true_target);
+  void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label);
+  void GenerateLongComparesAndJumps(HCondition* cond, Label* true_label, Label* false_label);
   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a9a95d3..11de4ee 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -77,10 +77,9 @@
     case kCondLE: return le;
     case kCondGT: return gt;
     case kCondGE: return ge;
-    default:
-      LOG(FATAL) << "Unknown if condition";
   }
-  return nv;  // Unreachable.
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 Location ARM64ReturnLocation(Primitive::Type return_type) {
@@ -657,6 +656,13 @@
   Primitive::Type type = instruction->GetType();
   DCHECK_NE(type, Primitive::kPrimVoid);
 
+  if (instruction->IsFakeString()) {
+    // The fake string is an alias for null.
+    DCHECK(IsBaseline());
+    instruction = locations->Out().GetConstant();
+    DCHECK(instruction->IsNullConstant()) << instruction->DebugName();
+  }
+
   if (instruction->IsCurrentMethod()) {
     MoveLocation(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
   } else if (locations != nullptr && locations->Out().Equals(location)) {
@@ -905,7 +911,7 @@
              (source.IsFpuRegister() == Primitive::IsFloatingPointType(type)));
       __ Str(CPURegisterFrom(source, type), StackOperandFrom(destination));
     } else if (source.IsConstant()) {
-      DCHECK(unspecified_type || CoherentConstantAndType(source, type));
+      DCHECK(unspecified_type || CoherentConstantAndType(source, type)) << source << " " << type;
       UseScratchRegisterScope temps(GetVIXLAssembler());
       HConstant* src_cst = source.GetConstant();
       CPURegister temp;
@@ -1477,9 +1483,8 @@
     source = HeapOperand(obj, offset);
   } else {
     Register temp = temps.AcquireSameSizeAs(obj);
-    Register index_reg = RegisterFrom(index, Primitive::kPrimInt);
-    __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type)));
-    source = HeapOperand(temp, offset);
+    __ Add(temp, obj, offset);
+    source = HeapOperand(temp, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
   }
 
   codegen_->Load(type, OutputCPURegister(instruction), source);
@@ -1562,9 +1567,11 @@
         destination = HeapOperand(obj, offset);
       } else {
         Register temp = temps.AcquireSameSizeAs(obj);
-        Register index_reg = InputRegisterAt(instruction, 1);
-        __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type)));
-        destination = HeapOperand(temp, offset);
+        __ Add(temp, obj, offset);
+        destination = HeapOperand(temp,
+                                  XRegisterFrom(index),
+                                  LSL,
+                                  Primitive::ComponentSizeShift(value_type));
       }
 
       codegen_->Store(value_type, source, destination);
@@ -1645,6 +1652,11 @@
   GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0));
 }
 
+static bool IsFloatingPointZeroConstant(HInstruction* instruction) {
+  return (instruction->IsFloatConstant() && (instruction->AsFloatConstant()->GetValue() == 0.0f))
+      || (instruction->IsDoubleConstant() && (instruction->AsDoubleConstant()->GetValue() == 0.0));
+}
+
 void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
@@ -1659,13 +1671,10 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      HInstruction* right = compare->InputAt(1);
-      if ((right->IsFloatConstant() && (right->AsFloatConstant()->GetValue() == 0.0f)) ||
-          (right->IsDoubleConstant() && (right->AsDoubleConstant()->GetValue() == 0.0))) {
-        locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
-      } else {
-        locations->SetInAt(1, Location::RequiresFpuRegister());
-      }
+      locations->SetInAt(1,
+                         IsFloatingPointZeroConstant(compare->InputAt(1))
+                             ? Location::ConstantLocation(compare->InputAt(1)->AsConstant())
+                             : Location::RequiresFpuRegister());
       locations->SetOut(Location::RequiresRegister());
       break;
     }
@@ -1696,12 +1705,8 @@
       Register result = OutputRegister(compare);
       FPRegister left = InputFPRegisterAt(compare, 0);
       if (compare->GetLocations()->InAt(1).IsConstant()) {
-        if (kIsDebugBuild) {
-          HInstruction* right = compare->GetLocations()->InAt(1).GetConstant();
-          DCHECK((right->IsFloatConstant() && (right->AsFloatConstant()->GetValue() == 0.0f)) ||
-                  (right->IsDoubleConstant() && (right->AsDoubleConstant()->GetValue() == 0.0)));
-        }
-        // 0.0 is the only immediate that can be encoded directly in a FCMP instruction.
+        DCHECK(IsFloatingPointZeroConstant(compare->GetLocations()->InAt(1).GetConstant()));
+        // 0.0 is the only immediate that can be encoded directly in an FCMP instruction.
         __ Fcmp(left, 0.0);
       } else {
         __ Fcmp(left, InputFPRegisterAt(compare, 1));
@@ -1721,8 +1726,19 @@
 
 void LocationsBuilderARM64::VisitCondition(HCondition* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
+
+  if (Primitive::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
+    locations->SetInAt(0, Location::RequiresFpuRegister());
+    locations->SetInAt(1,
+                       IsFloatingPointZeroConstant(instruction->InputAt(1))
+                           ? Location::ConstantLocation(instruction->InputAt(1)->AsConstant())
+                           : Location::RequiresFpuRegister());
+  } else {
+    // Integer cases.
+    locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetInAt(1, ARM64EncodableConstantOrRegister(instruction->InputAt(1), instruction));
+  }
+
   if (instruction->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   }
@@ -1734,13 +1750,34 @@
   }
 
   LocationSummary* locations = instruction->GetLocations();
-  Register lhs = InputRegisterAt(instruction, 0);
-  Operand rhs = InputOperandAt(instruction, 1);
   Register res = RegisterFrom(locations->Out(), instruction->GetType());
-  Condition cond = ARM64Condition(instruction->GetCondition());
+  IfCondition if_cond = instruction->GetCondition();
+  Condition arm64_cond = ARM64Condition(if_cond);
 
-  __ Cmp(lhs, rhs);
-  __ Cset(res, cond);
+  if (Primitive::IsFloatingPointType(instruction->InputAt(0)->GetType())) {
+    FPRegister lhs = InputFPRegisterAt(instruction, 0);
+    if (locations->InAt(1).IsConstant()) {
+      DCHECK(IsFloatingPointZeroConstant(locations->InAt(1).GetConstant()));
+      // 0.0 is the only immediate that can be encoded directly in an FCMP instruction.
+      __ Fcmp(lhs, 0.0);
+    } else {
+      __ Fcmp(lhs, InputFPRegisterAt(instruction, 1));
+    }
+    __ Cset(res, arm64_cond);
+    if (instruction->IsFPConditionTrueIfNaN()) {
+      // res = IsUnordered(arm64_cond) ? 1 : res  <=>  res = IsNotUnordered(arm64_cond) ? res : 1
+      __ Csel(res, res, Operand(1), vc);  // VC for "not unordered".
+    } else if (instruction->IsFPConditionFalseIfNaN()) {
+      // res = IsUnordered(arm64_cond) ? 0 : res  <=>  res = IsNotUnordered(arm64_cond) ? res : 0
+      __ Csel(res, res, Operand(0), vc);  // VC for "not unordered".
+    }
+  } else {
+    // Integer cases.
+    Register lhs = InputRegisterAt(instruction, 0);
+    Operand rhs = InputOperandAt(instruction, 1);
+    __ Cmp(lhs, rhs);
+    __ Cset(res, arm64_cond);
+  }
 }
 
 #define FOR_EACH_CONDITION_INSTRUCTION(M)                                                \
@@ -2072,33 +2109,58 @@
   } else {
     // The condition instruction has not been materialized, use its inputs as
     // the comparison and its condition as the branch condition.
-    Register lhs = InputRegisterAt(condition, 0);
-    Operand rhs = InputOperandAt(condition, 1);
-    Condition arm64_cond = ARM64Condition(condition->GetCondition());
-    if ((arm64_cond != gt && arm64_cond != le) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
-      switch (arm64_cond) {
-        case eq:
-          __ Cbz(lhs, true_target);
-          break;
-        case ne:
-          __ Cbnz(lhs, true_target);
-          break;
-        case lt:
-          // Test the sign bit and branch accordingly.
-          __ Tbnz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
-          break;
-        case ge:
-          // Test the sign bit and branch accordingly.
-          __ Tbz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
-          break;
-        default:
-          // Without the `static_cast` the compiler throws an error for
-          // `-Werror=sign-promo`.
-          LOG(FATAL) << "Unexpected condition: " << static_cast<int>(arm64_cond);
+    Primitive::Type type =
+        cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
+
+    if (Primitive::IsFloatingPointType(type)) {
+      // FP compares don't like null false_targets.
+      if (false_target == nullptr) {
+        false_target = codegen_->GetLabelOf(instruction->AsIf()->IfFalseSuccessor());
       }
+      FPRegister lhs = InputFPRegisterAt(condition, 0);
+      if (condition->GetLocations()->InAt(1).IsConstant()) {
+        DCHECK(IsFloatingPointZeroConstant(condition->GetLocations()->InAt(1).GetConstant()));
+        // 0.0 is the only immediate that can be encoded directly in an FCMP instruction.
+        __ Fcmp(lhs, 0.0);
+      } else {
+        __ Fcmp(lhs, InputFPRegisterAt(condition, 1));
+      }
+      if (condition->IsFPConditionTrueIfNaN()) {
+        __ B(vs, true_target);  // VS for unordered.
+      } else if (condition->IsFPConditionFalseIfNaN()) {
+        __ B(vs, false_target);  // VS for unordered.
+      }
+      __ B(ARM64Condition(condition->GetCondition()), true_target);
     } else {
-      __ Cmp(lhs, rhs);
-      __ B(arm64_cond, true_target);
+      // Integer cases.
+      Register lhs = InputRegisterAt(condition, 0);
+      Operand rhs = InputOperandAt(condition, 1);
+      Condition arm64_cond = ARM64Condition(condition->GetCondition());
+      if ((arm64_cond != gt && arm64_cond != le) && rhs.IsImmediate() && (rhs.immediate() == 0)) {
+        switch (arm64_cond) {
+          case eq:
+            __ Cbz(lhs, true_target);
+            break;
+          case ne:
+            __ Cbnz(lhs, true_target);
+            break;
+          case lt:
+            // Test the sign bit and branch accordingly.
+            __ Tbnz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
+            break;
+          case ge:
+            // Test the sign bit and branch accordingly.
+            __ Tbz(lhs, (lhs.IsX() ? kXRegSize : kWRegSize) - 1, true_target);
+            break;
+          default:
+            // Without the `static_cast` the compiler throws an error for
+            // `-Werror=sign-promo`.
+            LOG(FATAL) << "Unexpected condition: " << static_cast<int>(arm64_cond);
+        }
+      } else {
+        __ Cmp(lhs, rhs);
+        __ B(arm64_cond, true_target);
+      }
     }
   }
   if (false_target != nullptr) {
@@ -3038,6 +3100,18 @@
   LOG(FATAL) << "Unreachable";
 }
 
+void LocationsBuilderARM64::VisitFakeString(HFakeString* instruction) {
+  DCHECK(codegen_->IsBaseline());
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorARM64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+  DCHECK(codegen_->IsBaseline());
+  // Will be generated at use site.
+}
+
 #undef __
 #undef QUICK_ENTRY_POINT
 
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index aa4fd26..e7d2ec6 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3292,5 +3292,17 @@
   VisitCondition(comp);
 }
 
+void LocationsBuilderMIPS64::VisitFakeString(HFakeString* instruction) {
+  DCHECK(codegen_->IsBaseline());
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorMIPS64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+  DCHECK(codegen_->IsBaseline());
+  // Will be generated at use site.
+}
+
 }  // namespace mips64
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 262b234..e15eff9 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -344,7 +344,7 @@
 #undef __
 #define __ down_cast<X86Assembler*>(GetAssembler())->
 
-inline Condition X86Condition(IfCondition cond) {
+inline Condition X86SignedCondition(IfCondition cond) {
   switch (cond) {
     case kCondEQ: return kEqual;
     case kCondNE: return kNotEqual;
@@ -352,10 +352,22 @@
     case kCondLE: return kLessEqual;
     case kCondGT: return kGreater;
     case kCondGE: return kGreaterEqual;
-    default:
-      LOG(FATAL) << "Unknown if condition";
   }
-  return kEqual;
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
+}
+
+inline Condition X86UnsignedOrFPCondition(IfCondition cond) {
+  switch (cond) {
+    case kCondEQ: return kEqual;
+    case kCondNE: return kNotEqual;
+    case kCondLT: return kBelow;
+    case kCondLE: return kBelowEqual;
+    case kCondGT: return kAbove;
+    case kCondGE: return kAboveEqual;
+  }
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
@@ -889,6 +901,138 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
+                                                  Label* true_label,
+                                                  Label* false_label) {
+  if (cond->IsFPConditionTrueIfNaN()) {
+    __ j(kUnordered, true_label);
+  } else if (cond->IsFPConditionFalseIfNaN()) {
+    __ j(kUnordered, false_label);
+  }
+  __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
+}
+
+void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
+                                                               Label* true_label,
+                                                               Label* false_label) {
+  LocationSummary* locations = cond->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+  IfCondition if_cond = cond->GetCondition();
+
+  Register left_high = left.AsRegisterPairHigh<Register>();
+  Register left_low = left.AsRegisterPairLow<Register>();
+  IfCondition true_high_cond = if_cond;
+  IfCondition false_high_cond = cond->GetOppositeCondition();
+  Condition final_condition = X86UnsignedOrFPCondition(if_cond);
+
+  // Set the conditions for the test, remembering that == needs to be
+  // decided using the low words.
+  switch (if_cond) {
+    case kCondEQ:
+    case kCondNE:
+      // Nothing to do.
+      break;
+    case kCondLT:
+      false_high_cond = kCondGT;
+      break;
+    case kCondLE:
+      true_high_cond = kCondLT;
+      break;
+    case kCondGT:
+      false_high_cond = kCondLT;
+      break;
+    case kCondGE:
+      true_high_cond = kCondGT;
+      break;
+  }
+
+  if (right.IsConstant()) {
+    int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+    int32_t val_high = High32Bits(value);
+    int32_t val_low = Low32Bits(value);
+
+    if (val_high == 0) {
+      __ testl(left_high, left_high);
+    } else {
+      __ cmpl(left_high, Immediate(val_high));
+    }
+    if (if_cond == kCondNE) {
+      __ j(X86SignedCondition(true_high_cond), true_label);
+    } else if (if_cond == kCondEQ) {
+      __ j(X86SignedCondition(false_high_cond), false_label);
+    } else {
+      __ j(X86SignedCondition(true_high_cond), true_label);
+      __ j(X86SignedCondition(false_high_cond), false_label);
+    }
+    // Must be equal high, so compare the lows.
+    if (val_low == 0) {
+      __ testl(left_low, left_low);
+    } else {
+      __ cmpl(left_low, Immediate(val_low));
+    }
+  } else {
+    Register right_high = right.AsRegisterPairHigh<Register>();
+    Register right_low = right.AsRegisterPairLow<Register>();
+
+    __ cmpl(left_high, right_high);
+    if (if_cond == kCondNE) {
+      __ j(X86SignedCondition(true_high_cond), true_label);
+    } else if (if_cond == kCondEQ) {
+      __ j(X86SignedCondition(false_high_cond), false_label);
+    } else {
+      __ j(X86SignedCondition(true_high_cond), true_label);
+      __ j(X86SignedCondition(false_high_cond), false_label);
+    }
+    // Must be equal high, so compare the lows.
+    __ cmpl(left_low, right_low);
+  }
+  // The last comparison might be unsigned.
+  __ j(final_condition, true_label);
+}
+
+void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
+                                                               HCondition* condition,
+                                                               Label* true_target,
+                                                               Label* false_target,
+                                                               Label* always_true_target) {
+  LocationSummary* locations = condition->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  // We don't want true_target as a nullptr.
+  if (true_target == nullptr) {
+    true_target = always_true_target;
+  }
+  bool falls_through = (false_target == nullptr);
+
+  // FP compares don't like null false_targets.
+  if (false_target == nullptr) {
+    false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+  }
+
+  Primitive::Type type = condition->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong:
+      GenerateLongComparesAndJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimFloat:
+      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimDouble:
+      __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected compare type " << type;
+  }
+
+  if (!falls_through) {
+    __ jmp(false_target);
+  }
+}
+
 void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
                                                         Label* true_target,
                                                         Label* false_target,
@@ -906,14 +1050,17 @@
       DCHECK_EQ(cond_value, 0);
     }
   } else {
-    bool materialized =
+    bool is_materialized =
         !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
     // Moves do not affect the eflags register, so if the condition is
     // evaluated just before the if, we don't need to evaluate it
-    // again.
+    // again.  We can't use the eflags on long/FP conditions if they are
+    // materialized due to the complex branching.
+    Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
     bool eflags_set = cond->IsCondition()
-        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
-    if (materialized) {
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
+        && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type));
+    if (is_materialized) {
       if (!eflags_set) {
         // Materialized condition, compare against 0.
         Location lhs = instruction->GetLocations()->InAt(0);
@@ -924,9 +1071,23 @@
         }
         __ j(kNotEqual, true_target);
       } else {
-        __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
+        __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
       }
     } else {
+      // Condition has not been materialized, use its inputs as the
+      // comparison and its condition as the branch condition.
+
+      // Is this a long or FP comparison that has been folded into the HCondition?
+      if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+        // Generate the comparison directly.
+        GenerateCompareTestAndBranch(instruction->AsIf(),
+                                     cond->AsCondition(),
+                                     true_target,
+                                     false_target,
+                                     always_true_target);
+        return;
+      }
+
       Location lhs = cond->GetLocations()->InAt(0);
       Location rhs = cond->GetLocations()->InAt(1);
       // LHS is guaranteed to be in a register (see
@@ -943,7 +1104,7 @@
       } else {
         __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
       }
-      __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
+      __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
     }
   }
   if (false_target != nullptr) {
@@ -1041,36 +1202,94 @@
 void LocationsBuilderX86::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
-  if (cond->NeedsMaterialization()) {
-    // We need a byte register.
-    locations->SetOut(Location::RegisterLocation(ECX));
+  // Handle the long/FP comparisons made in instruction simplification.
+  switch (cond->InputAt(0)->GetType()) {
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister());
+      }
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister());
+      }
+      break;
+    }
+    default:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      if (cond->NeedsMaterialization()) {
+        // We need a byte register.
+        locations->SetOut(Location::RegisterLocation(ECX));
+      }
+      break;
   }
 }
 
 void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
-  if (cond->NeedsMaterialization()) {
-    LocationSummary* locations = cond->GetLocations();
-    Register reg = locations->Out().AsRegister<Register>();
-    // Clear register: setcc only sets the low byte.
-    __ xorl(reg, reg);
-    Location lhs = locations->InAt(0);
-    Location rhs = locations->InAt(1);
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
-    } else if (rhs.IsConstant()) {
-      int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-      if (constant == 0) {
-        __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
-      } else {
-      __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
-      }
-    } else {
-      __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
-    }
-    __ setb(X86Condition(cond->GetCondition()), reg);
+  if (!cond->NeedsMaterialization()) {
+    return;
   }
+
+  LocationSummary* locations = cond->GetLocations();
+  Location lhs = locations->InAt(0);
+  Location rhs = locations->InAt(1);
+  Register reg = locations->Out().AsRegister<Register>();
+  Label true_label, false_label;
+
+  switch (cond->InputAt(0)->GetType()) {
+    default: {
+      // Integer case.
+
+      // Clear output register: setcc only sets the low byte.
+      __ xorl(reg, reg);
+
+      if (rhs.IsRegister()) {
+        __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
+      } else if (rhs.IsConstant()) {
+        int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
+        if (constant == 0) {
+          __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
+        } else {
+          __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
+        }
+      } else {
+        __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
+      }
+      __ setb(X86SignedCondition(cond->GetCondition()), reg);
+      return;
+    }
+    case Primitive::kPrimLong:
+      GenerateLongComparesAndJumps(cond, &true_label, &false_label);
+      break;
+    case Primitive::kPrimFloat:
+      __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    case Primitive::kPrimDouble:
+      __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+  }
+
+  // Convert the jumps into the result.
+  Label done_label;
+
+  // False case: result = 0.
+  __ Bind(&false_label);
+  __ xorl(reg, reg);
+  __ jmp(&done_label);
+
+  // True case: result = 1.
+  __ Bind(&true_label);
+  __ movl(reg, Immediate(1));
+  __ Bind(&done_label);
 }
 
 void LocationsBuilderX86::VisitEqual(HEqual* comp) {
@@ -4745,6 +4964,18 @@
   LOG(FATAL) << "Unreachable";
 }
 
+void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
+  DCHECK(codegen_->IsBaseline());
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+  DCHECK(codegen_->IsBaseline());
+  // Will be generated at use site.
+}
+
 #undef __
 
 }  // namespace x86
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 623e832..65d6e0a 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -177,7 +177,7 @@
   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
   void DivByPowerOfTwo(HDiv* instruction);
   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
-  void GenerateRemFP(HRem *rem);
+  void GenerateRemFP(HRem* rem);
   void HandleShift(HBinaryOperation* instruction);
   void GenerateShlLong(const Location& loc, Register shifter);
   void GenerateShrLong(const Location& loc, Register shifter);
@@ -201,6 +201,13 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void GenerateCompareTestAndBranch(HIf* if_inst,
+                                    HCondition* condition,
+                                    Label* true_target,
+                                    Label* false_target,
+                                    Label* always_true_target);
+  void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label);
+  void GenerateLongComparesAndJumps(HCondition* cond, Label* true_label, Label* false_label);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   X86Assembler* const assembler_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index c9d19c8..a95ce68 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -363,7 +363,7 @@
 #undef __
 #define __ down_cast<X86_64Assembler*>(GetAssembler())->
 
-inline Condition X86_64Condition(IfCondition cond) {
+inline Condition X86_64IntegerCondition(IfCondition cond) {
   switch (cond) {
     case kCondEQ: return kEqual;
     case kCondNE: return kNotEqual;
@@ -371,10 +371,22 @@
     case kCondLE: return kLessEqual;
     case kCondGT: return kGreater;
     case kCondGE: return kGreaterEqual;
-    default:
-      LOG(FATAL) << "Unknown if condition";
   }
-  return kEqual;
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
+}
+
+inline Condition X86_64FPCondition(IfCondition cond) {
+  switch (cond) {
+    case kCondEQ: return kEqual;
+    case kCondNE: return kNotEqual;
+    case kCondLT: return kBelow;
+    case kCondLE: return kBelowEqual;
+    case kCondGT: return kAbove;
+    case kCondGE: return kAboveEqual;
+  };
+  LOG(FATAL) << "Unreachable";
+  UNREACHABLE();
 }
 
 void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
@@ -833,6 +845,100 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
+                                                     Label* true_label,
+                                                     Label* false_label) {
+  if (cond->IsFPConditionTrueIfNaN()) {
+    __ j(kUnordered, true_label);
+  } else if (cond->IsFPConditionFalseIfNaN()) {
+    __ j(kUnordered, false_label);
+  }
+  __ j(X86_64FPCondition(cond->GetCondition()), true_label);
+}
+
+void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
+                                                                  HCondition* condition,
+                                                                  Label* true_target,
+                                                                  Label* false_target,
+                                                                  Label* always_true_target) {
+  LocationSummary* locations = condition->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  // We don't want true_target as a nullptr.
+  if (true_target == nullptr) {
+    true_target = always_true_target;
+  }
+  bool falls_through = (false_target == nullptr);
+
+  // FP compares don't like null false_targets.
+  if (false_target == nullptr) {
+    false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+  }
+
+  Primitive::Type type = condition->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong: {
+      CpuRegister left_reg = left.AsRegister<CpuRegister>();
+      if (right.IsConstant()) {
+        int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+        if (IsInt<32>(value)) {
+          if (value == 0) {
+            __ testq(left_reg, left_reg);
+          } else {
+            __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
+          }
+        } else {
+          // Value won't fit in a 32-bit integer.
+          __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
+        }
+      } else if (right.IsDoubleStackSlot()) {
+        __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
+      } else {
+        __ cmpq(left_reg, right.AsRegister<CpuRegister>());
+      }
+      __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
+      break;
+    }
+    case Primitive::kPrimFloat: {
+      if (right.IsFpuRegister()) {
+        __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      } else if (right.IsConstant()) {
+        __ ucomiss(left.AsFpuRegister<XmmRegister>(),
+                   codegen_->LiteralFloatAddress(
+                     right.GetConstant()->AsFloatConstant()->GetValue()));
+      } else {
+        DCHECK(right.IsStackSlot());
+        __ ucomiss(left.AsFpuRegister<XmmRegister>(),
+                   Address(CpuRegister(RSP), right.GetStackIndex()));
+      }
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      if (right.IsFpuRegister()) {
+        __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      } else if (right.IsConstant()) {
+        __ ucomisd(left.AsFpuRegister<XmmRegister>(),
+                   codegen_->LiteralDoubleAddress(
+                     right.GetConstant()->AsDoubleConstant()->GetValue()));
+      } else {
+        DCHECK(right.IsDoubleStackSlot());
+        __ ucomisd(left.AsFpuRegister<XmmRegister>(),
+                   Address(CpuRegister(RSP), right.GetStackIndex()));
+      }
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected condition type " << type;
+  }
+
+  if (!falls_through) {
+    __ jmp(false_target);
+  }
+}
+
 void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
                                                            Label* true_target,
                                                            Label* false_target,
@@ -850,14 +956,18 @@
       DCHECK_EQ(cond_value, 0);
     }
   } else {
-    bool materialized =
+    bool is_materialized =
         !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
     // Moves do not affect the eflags register, so if the condition is
     // evaluated just before the if, we don't need to evaluate it
-    // again.
+    // again.  We can't use the eflags on FP conditions if they are
+    // materialized due to the complex branching.
+    Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
     bool eflags_set = cond->IsCondition()
-        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
-    if (materialized) {
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
+        && !Primitive::IsFloatingPointType(type);
+
+    if (is_materialized) {
       if (!eflags_set) {
         // Materialized condition, compare against 0.
         Location lhs = instruction->GetLocations()->InAt(0);
@@ -869,9 +979,20 @@
         }
         __ j(kNotEqual, true_target);
       } else {
-        __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
+        __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
       }
     } else {
+      // Condition has not been materialized, use its inputs as the
+      // comparison and its condition as the branch condition.
+
+      // Is this a long or FP comparison that has been folded into the HCondition?
+      if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+        // Generate the comparison directly.
+        GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
+                                     true_target, false_target, always_true_target);
+        return;
+      }
+
       Location lhs = cond->GetLocations()->InAt(0);
       Location rhs = cond->GetLocations()->InAt(1);
       if (rhs.IsRegister()) {
@@ -887,7 +1008,7 @@
         __ cmpl(lhs.AsRegister<CpuRegister>(),
                 Address(CpuRegister(RSP), rhs.GetStackIndex()));
       }
-      __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
+      __ j(X86_64IntegerCondition(cond->AsCondition()->GetCondition()), true_target);
     }
   }
   if (false_target != nullptr) {
@@ -985,35 +1106,122 @@
 void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
+  // Handle the long/FP comparisons made in instruction simplification.
+  switch (cond->InputAt(0)->GetType()) {
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      break;
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
+      break;
+    default:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      break;
+  }
   if (cond->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
-  if (cond->NeedsMaterialization()) {
-    LocationSummary* locations = cond->GetLocations();
-    CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
-    // Clear register: setcc only sets the low byte.
-    __ xorl(reg, reg);
-    Location lhs = locations->InAt(0);
-    Location rhs = locations->InAt(1);
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
-    } else if (rhs.IsConstant()) {
-      int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-      if (constant == 0) {
-        __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
-      } else {
-        __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
-      }
-    } else {
-      __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
-    }
-    __ setcc(X86_64Condition(cond->GetCondition()), reg);
+  if (!cond->NeedsMaterialization()) {
+    return;
   }
+
+  LocationSummary* locations = cond->GetLocations();
+  Location lhs = locations->InAt(0);
+  Location rhs = locations->InAt(1);
+  CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
+  Label true_label, false_label;
+
+  switch (cond->InputAt(0)->GetType()) {
+    default:
+      // Integer case.
+
+      // Clear output register: setcc only sets the low byte.
+      __ xorl(reg, reg);
+
+      if (rhs.IsRegister()) {
+        __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
+      } else if (rhs.IsConstant()) {
+        int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
+        if (constant == 0) {
+          __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
+        } else {
+          __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
+        }
+      } else {
+        __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      }
+      __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
+      return;
+    case Primitive::kPrimLong:
+      // Clear output register: setcc only sets the low byte.
+      __ xorl(reg, reg);
+
+      if (rhs.IsRegister()) {
+        __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
+      } else if (rhs.IsConstant()) {
+        int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
+        if (IsInt<32>(value)) {
+          if (value == 0) {
+            __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
+          } else {
+            __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
+          }
+        } else {
+          // Value won't fit in an int.
+          __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
+        }
+      } else {
+        __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      }
+      __ setcc(X86_64IntegerCondition(cond->GetCondition()), reg);
+      return;
+    case Primitive::kPrimFloat: {
+      XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
+      if (rhs.IsConstant()) {
+        float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
+        __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
+      } else if (rhs.IsStackSlot()) {
+        __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      } else {
+        __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
+      }
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
+      if (rhs.IsConstant()) {
+        double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
+        __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
+      } else if (rhs.IsDoubleStackSlot()) {
+        __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      } else {
+        __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
+      }
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    }
+  }
+
+  // Convert the jumps into the result.
+  Label done_label;
+
+  // False case: result = 0.
+  __ Bind(&false_label);
+  __ xorl(reg, reg);
+  __ jmp(&done_label);
+
+  // True case: result = 1.
+  __ Bind(&true_label);
+  __ movl(reg, Immediate(1));
+  __ Bind(&done_label);
 }
 
 void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
@@ -4566,6 +4774,18 @@
   LOG(FATAL) << "Unreachable";
 }
 
+void LocationsBuilderX86_64::VisitFakeString(HFakeString* instruction) {
+  DCHECK(codegen_->IsBaseline());
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
+}
+
+void InstructionCodeGeneratorX86_64::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
+  DCHECK(codegen_->IsBaseline());
+  // Will be generated at use site.
+}
+
 void CodeGeneratorX86_64::Load64BitValue(CpuRegister dest, int64_t value) {
   if (value == 0) {
     __ xorl(dest, dest);
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index c2aa56b..4b90381 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -183,7 +183,7 @@
   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg);
   void HandleBitwiseOperation(HBinaryOperation* operation);
-  void GenerateRemFP(HRem *rem);
+  void GenerateRemFP(HRem* rem);
   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
   void DivByPowerOfTwo(HDiv* instruction);
   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
@@ -202,6 +202,12 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void GenerateCompareTestAndBranch(HIf* if_inst,
+                                    HCondition* condition,
+                                    Label* true_target,
+                                    Label* false_target,
+                                    Label* always_true_target);
+  void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   X86_64Assembler* const assembler_;
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index 246fff9..f545475 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -151,6 +151,15 @@
   return vixl::MemOperand(base.X(), offset);
 }
 
+static inline vixl::MemOperand HeapOperand(const vixl::Register& base,
+                                           const vixl::Register& regoffset,
+                                           vixl::Shift shift = vixl::LSL,
+                                           unsigned shift_amount = 0) {
+  // A heap reference must be 32bit, so fit in a W register.
+  DCHECK(base.IsW());
+  return vixl::MemOperand(base.X(), regoffset, shift, shift_amount);
+}
+
 static inline vixl::MemOperand HeapOperand(const vixl::Register& base, Offset offset) {
   return HeapOperand(base, offset.SizeValue());
 }
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 9679d0a..cfebb77 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -136,6 +136,33 @@
   VisitInstruction(check);
 }
 
+void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) {
+  // Ensure that all exception handlers are catch blocks and that handlers
+  // are not listed multiple times.
+  // Note that a normal-flow successor may be a catch block before CFG
+  // simplification. We only test normal-flow successors in SsaChecker.
+  for (HExceptionHandlerIterator it(*try_boundary); !it.Done(); it.Advance()) {
+    HBasicBlock* handler = it.Current();
+    if (!handler->IsCatchBlock()) {
+      AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
+                            "is not a catch block.",
+                            current_block_->GetBlockId(),
+                            try_boundary->DebugName(),
+                            try_boundary->GetId(),
+                            handler->GetBlockId()));
+    }
+    if (current_block_->GetSuccessors().Contains(
+            handler, /* start_from */ it.CurrentSuccessorIndex() + 1)) {
+      AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.",
+                            handler->GetBlockId(),
+                            try_boundary->DebugName(),
+                            try_boundary->GetId()));
+    }
+  }
+
+  VisitInstruction(try_boundary);
+}
+
 void GraphChecker::VisitInstruction(HInstruction* instruction) {
   if (seen_ids_.IsBitSet(instruction->GetId())) {
     AddError(StringPrintf("Instruction id %d is duplicate in graph.",
@@ -301,11 +328,32 @@
 void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
   super_type::VisitBasicBlock(block);
 
+  // Ensure that catch blocks are not normal successors, and normal blocks are
+  // never exceptional successors.
+  const size_t num_normal_successors = block->NumberOfNormalSuccessors();
+  for (size_t j = 0; j < num_normal_successors; ++j) {
+    HBasicBlock* successor = block->GetSuccessors().Get(j);
+    if (successor->IsCatchBlock()) {
+      AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
+                            successor->GetBlockId(),
+                            block->GetBlockId()));
+    }
+  }
+  for (size_t j = num_normal_successors, e = block->GetSuccessors().Size(); j < e; ++j) {
+    HBasicBlock* successor = block->GetSuccessors().Get(j);
+    if (!successor->IsCatchBlock()) {
+      AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
+                            successor->GetBlockId(),
+                            block->GetBlockId()));
+    }
+  }
+
   // Ensure there is no critical edge (i.e., an edge connecting a
   // block with multiple successors to a block with multiple
-  // predecessors).
-  if (block->GetSuccessors().Size() > 1) {
-    for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
+  // predecessors). Exceptional edges are synthesized and hence
+  // not accounted for.
+  if (block->NumberOfNormalSuccessors() > 1) {
+    for (size_t j = 0, e = block->NumberOfNormalSuccessors(); j < e; ++j) {
       HBasicBlock* successor = block->GetSuccessors().Get(j);
       if (successor->GetPredecessors().Size() > 1) {
         AddError(StringPrintf("Critical edge between blocks %d and %d.",
@@ -326,6 +374,54 @@
     }
   }
 
+  // Ensure try membership information is consistent.
+  HTryBoundary* try_entry = block->GetTryEntry();
+  if (block->IsCatchBlock()) {
+    if (try_entry != nullptr) {
+      AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
+                            "has try entry %s:%d.",
+                            block->GetBlockId(),
+                            try_entry->DebugName(),
+                            try_entry->GetId()));
+    }
+
+    if (block->IsLoopHeader()) {
+      AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
+                            block->GetBlockId()));
+    }
+  } else {
+    for (size_t i = 0; i < block->GetPredecessors().Size(); ++i) {
+      HBasicBlock* predecessor = block->GetPredecessors().Get(i);
+      HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
+      if (try_entry == nullptr) {
+        if (incoming_try_entry != nullptr) {
+          AddError(StringPrintf("Block %d has no try entry but try entry %s:%d follows "
+                                "from predecessor %d.",
+                                block->GetBlockId(),
+                                incoming_try_entry->DebugName(),
+                                incoming_try_entry->GetId(),
+                                predecessor->GetBlockId()));
+        }
+      } else if (incoming_try_entry == nullptr) {
+        AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
+                              "from predecessor %d.",
+                              block->GetBlockId(),
+                              try_entry->DebugName(),
+                              try_entry->GetId(),
+                              predecessor->GetBlockId()));
+      } else if (!incoming_try_entry->HasSameExceptionHandlersAs(*try_entry)) {
+        AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
+                              "with %s:%d that follows from predecessor %d.",
+                              block->GetBlockId(),
+                              try_entry->DebugName(),
+                              try_entry->GetId(),
+                              incoming_try_entry->DebugName(),
+                              incoming_try_entry->GetId(),
+                              predecessor->GetBlockId()));
+      }
+    }
+  }
+
   if (block->IsLoopHeader()) {
     CheckLoop(block);
   }
@@ -472,32 +568,6 @@
                           phi->GetBlock()->GetBlockId()));
   }
 
-  // Ensure the number of inputs of a phi is the same as the number of
-  // its predecessors.
-  const GrowableArray<HBasicBlock*>& predecessors =
-    phi->GetBlock()->GetPredecessors();
-  if (phi->InputCount() != predecessors.Size()) {
-    AddError(StringPrintf(
-        "Phi %d in block %d has %zu inputs, "
-        "but block %d has %zu predecessors.",
-        phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(),
-        phi->GetBlock()->GetBlockId(), predecessors.Size()));
-  } else {
-    // Ensure phi input at index I either comes from the Ith
-    // predecessor or from a block that dominates this predecessor.
-    for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
-      HInstruction* input = phi->InputAt(i);
-      HBasicBlock* predecessor = predecessors.Get(i);
-      if (!(input->GetBlock() == predecessor
-            || input->GetBlock()->Dominates(predecessor))) {
-        AddError(StringPrintf(
-            "Input %d at index %zu of phi %d from block %d is not defined in "
-            "predecessor number %zu nor in a block dominating it.",
-            input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
-            i));
-      }
-    }
-  }
   // Ensure that the inputs have the same primitive kind as the phi.
   for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
     HInstruction* input = phi->InputAt(i);
@@ -516,6 +586,38 @@
                           phi->GetBlock()->GetBlockId(),
                           Primitive::PrettyDescriptor(phi->GetType())));
   }
+
+  if (phi->IsCatchPhi()) {
+    // The number of inputs of a catch phi corresponds to the total number of
+    // throwing instructions caught by this catch block.
+  } else {
+    // Ensure the number of inputs of a non-catch phi is the same as the number
+    // of its predecessors.
+    const GrowableArray<HBasicBlock*>& predecessors =
+      phi->GetBlock()->GetPredecessors();
+    if (phi->InputCount() != predecessors.Size()) {
+      AddError(StringPrintf(
+          "Phi %d in block %d has %zu inputs, "
+          "but block %d has %zu predecessors.",
+          phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(),
+          phi->GetBlock()->GetBlockId(), predecessors.Size()));
+    } else {
+      // Ensure phi input at index I either comes from the Ith
+      // predecessor or from a block that dominates this predecessor.
+      for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
+        HInstruction* input = phi->InputAt(i);
+        HBasicBlock* predecessor = predecessors.Get(i);
+        if (!(input->GetBlock() == predecessor
+              || input->GetBlock()->Dominates(predecessor))) {
+          AddError(StringPrintf(
+              "Input %d at index %zu of phi %d from block %d is not defined in "
+              "predecessor number %zu nor in a block dominating it.",
+              input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
+              i));
+        }
+      }
+    }
+  }
 }
 
 void SSAChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 7c72e23..0e270db 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -48,6 +48,9 @@
   // Check that the HasBoundsChecks() flag is set for bounds checks.
   void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE;
 
+  // Check successors of blocks ending in TryBoundary.
+  void VisitTryBoundary(HTryBoundary* try_boundary) OVERRIDE;
+
   // Check that HCheckCast and HInstanceOf have HLoadClass as second input.
   void VisitCheckCast(HCheckCast* check) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* check) OVERRIDE;
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 504c141..afea403 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -158,12 +158,14 @@
                           std::ostream& output,
                           const char* pass_name,
                           bool is_after_pass,
+                          bool graph_in_bad_state,
                           const CodeGenerator& codegen,
                           const DisassemblyInformation* disasm_info = nullptr)
       : HGraphDelegateVisitor(graph),
         output_(output),
         pass_name_(pass_name),
         is_after_pass_(is_after_pass),
+        graph_in_bad_state_(graph_in_bad_state),
         codegen_(codegen),
         disasm_info_(disasm_info),
         disassembler_(disasm_info_ != nullptr
@@ -251,11 +253,9 @@
   void PrintSuccessors(HBasicBlock* block) {
     AddIndent();
     output_ << "successors";
-    for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
-      if (!block->IsExceptionalSuccessor(i)) {
-        HBasicBlock* successor = block->GetSuccessors().Get(i);
-        output_ << " \"B" << successor->GetBlockId() << "\" ";
-      }
+    for (size_t i = 0; i < block->NumberOfNormalSuccessors(); ++i) {
+      HBasicBlock* successor = block->GetSuccessors().Get(i);
+      output_ << " \"B" << successor->GetBlockId() << "\" ";
     }
     output_<< std::endl;
   }
@@ -263,11 +263,9 @@
   void PrintExceptionHandlers(HBasicBlock* block) {
     AddIndent();
     output_ << "xhandlers";
-    for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
-      if (block->IsExceptionalSuccessor(i)) {
-        HBasicBlock* handler = block->GetSuccessors().Get(i);
-        output_ << " \"B" << handler->GetBlockId() << "\" ";
-      }
+    for (size_t i = block->NumberOfNormalSuccessors(); i < block->GetSuccessors().Size(); ++i) {
+      HBasicBlock* handler = block->GetSuccessors().Get(i);
+      output_ << " \"B" << handler->GetBlockId() << "\" ";
     }
     if (block->IsExitBlock() &&
         (disasm_info_ != nullptr) &&
@@ -351,12 +349,17 @@
 
   void VisitPhi(HPhi* phi) OVERRIDE {
     StartAttributeStream("reg") << phi->GetRegNumber();
+    StartAttributeStream("is_catch_phi") << std::boolalpha << phi->IsCatchPhi() << std::noboolalpha;
   }
 
   void VisitMemoryBarrier(HMemoryBarrier* barrier) OVERRIDE {
     StartAttributeStream("kind") << barrier->GetBarrierKind();
   }
 
+  void VisitMonitorOperation(HMonitorOperation* monitor) OVERRIDE {
+    StartAttributeStream("kind") << (monitor->IsEnter() ? "enter" : "exit");
+  }
+
   void VisitLoadClass(HLoadClass* load_class) OVERRIDE {
     StartAttributeStream("gen_clinit_check") << std::boolalpha
         << load_class->MustGenerateClinitCheck() << std::noboolalpha;
@@ -578,7 +581,11 @@
 
   void Run() {
     StartTag("cfg");
-    std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
+    std::string pass_desc = std::string(pass_name_)
+                          + " ("
+                          + (is_after_pass_ ? "after" : "before")
+                          + (graph_in_bad_state_ ? ", bad_state" : "")
+                          + ")";
     PrintProperty("name", pass_desc.c_str());
     if (disasm_info_ != nullptr) {
       DumpDisassemblyBlockForFrameEntry();
@@ -647,6 +654,7 @@
   std::ostream& output_;
   const char* pass_name_;
   const bool is_after_pass_;
+  const bool graph_in_bad_state_;
   const CodeGenerator& codegen_;
   const DisassemblyInformation* disasm_info_;
   std::unique_ptr<HGraphVisualizerDisassembler> disassembler_;
@@ -662,7 +670,7 @@
 
 void HGraphVisualizer::PrintHeader(const char* method_name) const {
   DCHECK(output_ != nullptr);
-  HGraphVisualizerPrinter printer(graph_, *output_, "", true, codegen_);
+  HGraphVisualizerPrinter printer(graph_, *output_, "", true, false, codegen_);
   printer.StartTag("compilation");
   printer.PrintProperty("name", method_name);
   printer.PrintProperty("method", method_name);
@@ -670,10 +678,17 @@
   printer.EndTag("compilation");
 }
 
-void HGraphVisualizer::DumpGraph(const char* pass_name, bool is_after_pass) const {
+void HGraphVisualizer::DumpGraph(const char* pass_name,
+                                 bool is_after_pass,
+                                 bool graph_in_bad_state) const {
   DCHECK(output_ != nullptr);
   if (!graph_->GetBlocks().IsEmpty()) {
-    HGraphVisualizerPrinter printer(graph_, *output_, pass_name, is_after_pass, codegen_);
+    HGraphVisualizerPrinter printer(graph_,
+                                    *output_,
+                                    pass_name,
+                                    is_after_pass,
+                                    graph_in_bad_state,
+                                    codegen_);
     printer.Run();
   }
 }
@@ -681,8 +696,13 @@
 void HGraphVisualizer::DumpGraphWithDisassembly() const {
   DCHECK(output_ != nullptr);
   if (!graph_->GetBlocks().IsEmpty()) {
-    HGraphVisualizerPrinter printer(
-        graph_, *output_, "disassembly", true, codegen_, codegen_.GetDisassemblyInformation());
+    HGraphVisualizerPrinter printer(graph_,
+                                    *output_,
+                                    "disassembly",
+                                    /* is_after_pass */ true,
+                                    /* graph_in_bad_state */ false,
+                                    codegen_,
+                                    codegen_.GetDisassemblyInformation());
     printer.Run();
   }
 }
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index b6b66df..66588f6 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -104,7 +104,7 @@
                    const CodeGenerator& codegen);
 
   void PrintHeader(const char* method_name) const;
-  void DumpGraph(const char* pass_name, bool is_after_pass = true) const;
+  void DumpGraph(const char* pass_name, bool is_after_pass, bool graph_in_bad_state) const;
   void DumpGraphWithDisassembly() const;
 
  private:
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 62f90c2..b30b6c7 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -54,6 +54,11 @@
   void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
   void VisitAdd(HAdd* instruction) OVERRIDE;
   void VisitAnd(HAnd* instruction) OVERRIDE;
+  void VisitCondition(HCondition* instruction) OVERRIDE;
+  void VisitGreaterThan(HGreaterThan* condition) OVERRIDE;
+  void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) OVERRIDE;
+  void VisitLessThan(HLessThan* condition) OVERRIDE;
+  void VisitLessThanOrEqual(HLessThanOrEqual* condition) OVERRIDE;
   void VisitDiv(HDiv* instruction) OVERRIDE;
   void VisitMul(HMul* instruction) OVERRIDE;
   void VisitNeg(HNeg* instruction) OVERRIDE;
@@ -65,6 +70,7 @@
   void VisitUShr(HUShr* instruction) OVERRIDE;
   void VisitXor(HXor* instruction) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
+  void VisitFakeString(HFakeString* fake_string) OVERRIDE;
   bool IsDominatedByInputNullCheck(HInstruction* instr);
 
   OptimizingCompilerStats* stats_;
@@ -330,7 +336,11 @@
         block->RemoveInstruction(equal);
         RecordSimplification();
       }
+    } else {
+      VisitCondition(equal);
     }
+  } else {
+    VisitCondition(equal);
   }
 }
 
@@ -358,7 +368,11 @@
         block->RemoveInstruction(not_equal);
         RecordSimplification();
       }
+    } else {
+      VisitCondition(not_equal);
     }
+  } else {
+    VisitCondition(not_equal);
   }
 }
 
@@ -485,6 +499,76 @@
   }
 }
 
+void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
+  // Try to fold an HCompare into this HCondition.
+
+  // This simplification is currently supported on x86, x86_64, ARM and ARM64.
+  // TODO: Implement it for MIPS64.
+  InstructionSet instruction_set = GetGraph()->GetInstructionSet();
+  if (instruction_set == kMips64) {
+    return;
+  }
+
+  HInstruction* left = condition->GetLeft();
+  HInstruction* right = condition->GetRight();
+  // We can only replace an HCondition which compares a Compare to 0.
+  // Both 'dx' and 'jack' generate a compare to 0 when compiling a
+  // condition with a long, float or double comparison as input.
+  if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
+    // Conversion is not possible.
+    return;
+  }
+
+  // Is the Compare only used for this purpose?
+  if (!left->GetUses().HasOnlyOneUse()) {
+    // Someone else also wants the result of the compare.
+    return;
+  }
+
+  if (!left->GetEnvUses().IsEmpty()) {
+    // There is a reference to the compare result in an environment. Do we really need it?
+    if (GetGraph()->IsDebuggable()) {
+      return;
+    }
+
+    // We have to ensure that there are no deopt points in the sequence.
+    if (left->HasAnyEnvironmentUseBefore(condition)) {
+      return;
+    }
+  }
+
+  // Clean up any environment uses from the HCompare, if any.
+  left->RemoveEnvironmentUsers();
+
+  // We have decided to fold the HCompare into the HCondition. Transfer the information.
+  condition->SetBias(left->AsCompare()->GetBias());
+
+  // Replace the operands of the HCondition.
+  condition->ReplaceInput(left->InputAt(0), 0);
+  condition->ReplaceInput(left->InputAt(1), 1);
+
+  // Remove the HCompare.
+  left->GetBlock()->RemoveInstruction(left);
+
+  RecordSimplification();
+}
+
 void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   HInstruction* input_other = instruction->GetLeastConstantLeft();
@@ -820,4 +904,46 @@
   }
 }
 
+void InstructionSimplifierVisitor::VisitFakeString(HFakeString* instruction) {
+  HInstruction* actual_string = nullptr;
+
+  // Find the string we need to replace this instruction with. The actual string is
+  // the return value of a StringFactory call.
+  for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
+    HInstruction* use = it.Current()->GetUser();
+    if (use->IsInvokeStaticOrDirect()
+        && use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction)) {
+      use->AsInvokeStaticOrDirect()->RemoveFakeStringArgumentAsLastInput();
+      actual_string = use;
+      break;
+    }
+  }
+
+  // Check that there is no other instruction that thinks it is the factory for that string.
+  if (kIsDebugBuild) {
+    CHECK(actual_string != nullptr);
+    for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
+      HInstruction* use = it.Current()->GetUser();
+      if (use->IsInvokeStaticOrDirect()) {
+        CHECK(!use->AsInvokeStaticOrDirect()->IsStringFactoryFor(instruction));
+      }
+    }
+  }
+
+  // We need to remove any environment uses of the fake string that are not dominated by
+  // `actual_string` to null.
+  for (HUseIterator<HEnvironment*> it(instruction->GetEnvUses()); !it.Done(); it.Advance()) {
+    HEnvironment* environment = it.Current()->GetUser();
+    if (!actual_string->StrictlyDominates(environment->GetHolder())) {
+      environment->RemoveAsUserOfInput(it.Current()->GetIndex());
+      environment->SetRawEnvAt(it.Current()->GetIndex(), nullptr);
+    }
+  }
+
+  // Only uses dominated by `actual_string` must remain. We can safely replace and remove
+  // `instruction`.
+  instruction->ReplaceWith(actual_string);
+  instruction->GetBlock()->RemoveInstruction(instruction);
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index faee2dd..cc4b6f6 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -31,7 +31,7 @@
   InstructionSimplifier(HGraph* graph,
                         OptimizingCompilerStats* stats = nullptr,
                         const char* name = kInstructionSimplifierPassName)
-    : HOptimization(graph, name, stats) {}
+      : HOptimization(graph, name, stats) {}
 
   static constexpr const char* kInstructionSimplifierPassName = "instruction_simplifier";
 
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index f41a782..4b25046 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -427,11 +427,11 @@
     }
   }
 
-  bool ContainsCoreRegister(uint32_t id) {
+  bool ContainsCoreRegister(uint32_t id) const {
     return Contains(core_registers_, id);
   }
 
-  bool ContainsFloatingPointRegister(uint32_t id) {
+  bool ContainsFloatingPointRegister(uint32_t id) const {
     return Contains(floating_point_registers_, id);
   }
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index b82e37c..519fa00 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -98,26 +98,31 @@
 }
 
 void HGraph::BuildDominatorTree() {
+  // (1) Simplify the CFG so that catch blocks have only exceptional incoming
+  //     edges. This invariant simplifies building SSA form because Phis cannot
+  //     collect both normal- and exceptional-flow values at the same time.
+  SimplifyCatchBlocks();
+
   ArenaBitVector visited(arena_, blocks_.Size(), false);
 
-  // (1) Find the back edges in the graph doing a DFS traversal.
+  // (2) Find the back edges in the graph doing a DFS traversal.
   FindBackEdges(&visited);
 
-  // (2) Remove instructions and phis from blocks not visited during
+  // (3) Remove instructions and phis from blocks not visited during
   //     the initial DFS as users from other instructions, so that
   //     users can be safely removed before uses later.
   RemoveInstructionsAsUsersFromDeadBlocks(visited);
 
-  // (3) Remove blocks not visited during the initial DFS.
+  // (4) Remove blocks not visited during the initial DFS.
   //     Step (4) requires dead blocks to be removed from the
   //     predecessors list of live blocks.
   RemoveDeadBlocks(visited);
 
-  // (4) Simplify the CFG now, so that we don't need to recompute
+  // (5) Simplify the CFG now, so that we don't need to recompute
   //     dominators and the reverse post order.
   SimplifyCFG();
 
-  // (5) Compute the dominance information and the reverse post order.
+  // (6) Compute the dominance information and the reverse post order.
   ComputeDominanceInformation();
 }
 
@@ -261,6 +266,83 @@
   info->SetSuspendCheck(first_instruction->AsSuspendCheck());
 }
 
+static bool CheckIfPredecessorAtIsExceptional(const HBasicBlock& block, size_t pred_idx) {
+  HBasicBlock* predecessor = block.GetPredecessors().Get(pred_idx);
+  if (!predecessor->EndsWithTryBoundary()) {
+    // Only edges from HTryBoundary can be exceptional.
+    return false;
+  }
+  HTryBoundary* try_boundary = predecessor->GetLastInstruction()->AsTryBoundary();
+  if (try_boundary->GetNormalFlowSuccessor() == &block) {
+    // This block is the normal-flow successor of `try_boundary`, but it could
+    // also be one of its exception handlers if catch blocks have not been
+    // simplified yet. Predecessors are unordered, so we will consider the first
+    // occurrence to be the normal edge and a possible second occurrence to be
+    // the exceptional edge.
+    return !block.IsFirstIndexOfPredecessor(predecessor, pred_idx);
+  } else {
+    // This is not the normal-flow successor of `try_boundary`, hence it must be
+    // one of its exception handlers.
+    DCHECK(try_boundary->HasExceptionHandler(block));
+    return true;
+  }
+}
+
+void HGraph::SimplifyCatchBlocks() {
+  for (size_t i = 0; i < blocks_.Size(); ++i) {
+    HBasicBlock* catch_block = blocks_.Get(i);
+    if (!catch_block->IsCatchBlock()) {
+      continue;
+    }
+
+    bool exceptional_predecessors_only = true;
+    for (size_t j = 0; j < catch_block->GetPredecessors().Size(); ++j) {
+      if (!CheckIfPredecessorAtIsExceptional(*catch_block, j)) {
+        exceptional_predecessors_only = false;
+        break;
+      }
+    }
+
+    if (!exceptional_predecessors_only) {
+      // Catch block has normal-flow predecessors and needs to be simplified.
+      // Splitting the block before its first instruction moves all its
+      // instructions into `normal_block` and links the two blocks with a Goto.
+      // Afterwards, incoming normal-flow edges are re-linked to `normal_block`,
+      // leaving `catch_block` with the exceptional edges only.
+      // Note that catch blocks with normal-flow predecessors cannot begin with
+      // a MOVE_EXCEPTION instruction, as guaranteed by the verifier.
+      DCHECK(!catch_block->GetFirstInstruction()->IsLoadException());
+      HBasicBlock* normal_block = catch_block->SplitBefore(catch_block->GetFirstInstruction());
+      for (size_t j = 0; j < catch_block->GetPredecessors().Size(); ++j) {
+        if (!CheckIfPredecessorAtIsExceptional(*catch_block, j)) {
+          catch_block->GetPredecessors().Get(j)->ReplaceSuccessor(catch_block, normal_block);
+          --j;
+        }
+      }
+    }
+  }
+}
+
+void HGraph::ComputeTryBlockInformation() {
+  // Iterate in reverse post order to propagate try membership information from
+  // predecessors to their successors.
+  for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    if (block->IsEntryBlock() || block->IsCatchBlock()) {
+      // Catch blocks after simplification have only exceptional predecessors
+      // and hence are never in tries.
+      continue;
+    }
+
+    // Infer try membership from the first predecessor. Having simplified loops,
+    // the first predecessor can never be a back edge and therefore it must have
+    // been visited already and had its try membership set.
+    HBasicBlock* first_predecessor = block->GetPredecessors().Get(0);
+    DCHECK(!block->IsLoopHeader() || !block->GetLoopInformation()->IsBackEdge(*first_predecessor));
+    block->SetTryEntry(first_predecessor->ComputeTryEntryOfSuccessors());
+  }
+}
+
 void HGraph::SimplifyCFG() {
   // Simplify the CFG for future analysis, and code generation:
   // (1): Split critical edges.
@@ -268,9 +350,10 @@
   for (size_t i = 0; i < blocks_.Size(); ++i) {
     HBasicBlock* block = blocks_.Get(i);
     if (block == nullptr) continue;
-    if (block->GetSuccessors().Size() > 1) {
+    if (block->NumberOfNormalSuccessors() > 1) {
       for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
         HBasicBlock* successor = block->GetSuccessors().Get(j);
+        DCHECK(!successor->IsCatchBlock());
         if (successor->GetPredecessors().Size() > 1) {
           SplitCriticalEdge(block, successor);
           --j;
@@ -288,6 +371,11 @@
   for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     if (block->IsLoopHeader()) {
+      if (block->IsCatchBlock()) {
+        // TODO: Dealing with exceptional back edges could be tricky because
+        //       they only approximate the real control flow. Bail out for now.
+        return false;
+      }
       HLoopInformation* info = block->GetLoopInformation();
       if (!info->Populate()) {
         // Abort if the loop is non natural. We currently bailout in such cases.
@@ -940,6 +1028,9 @@
                              GetRight()->AsLongConstant()->GetValue());
     if (GetResultType() == Primitive::kPrimLong) {
       return GetBlock()->GetGraph()->GetLongConstant(value);
+    } else if (GetResultType() == Primitive::kPrimBoolean) {
+      // This can be the result of an HCondition evaluation.
+      return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
     } else {
       DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
       return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
@@ -1083,10 +1174,20 @@
   return new_block;
 }
 
-bool HBasicBlock::IsExceptionalSuccessor(size_t idx) const {
-  return !GetInstructions().IsEmpty()
-      && GetLastInstruction()->IsTryBoundary()
-      && GetLastInstruction()->AsTryBoundary()->IsExceptionalSuccessor(idx);
+HTryBoundary* HBasicBlock::ComputeTryEntryOfSuccessors() const {
+  if (EndsWithTryBoundary()) {
+    HTryBoundary* try_boundary = GetLastInstruction()->AsTryBoundary();
+    if (try_boundary->IsEntry()) {
+      DCHECK(try_entry_ == nullptr);
+      return try_boundary;
+    } else {
+      DCHECK(try_entry_ != nullptr);
+      DCHECK(try_entry_->HasSameExceptionHandlersAs(*try_boundary));
+      return nullptr;
+    }
+  } else {
+    return try_entry_;
+  }
 }
 
 static bool HasOnlyOneInstruction(const HBasicBlock& block) {
@@ -1111,10 +1212,29 @@
   return !GetInstructions().IsEmpty() && GetLastInstruction()->IsIf();
 }
 
+bool HBasicBlock::EndsWithTryBoundary() const {
+  return !GetInstructions().IsEmpty() && GetLastInstruction()->IsTryBoundary();
+}
+
 bool HBasicBlock::HasSinglePhi() const {
   return !GetPhis().IsEmpty() && GetFirstPhi()->GetNext() == nullptr;
 }
 
+bool HTryBoundary::HasSameExceptionHandlersAs(const HTryBoundary& other) const {
+  if (GetBlock()->GetSuccessors().Size() != other.GetBlock()->GetSuccessors().Size()) {
+    return false;
+  }
+
+  // Exception handler lists cannot contain duplicates, which makes it
+  // sufficient to test inclusion only in one direction.
+  for (HExceptionHandlerIterator it(other); !it.Done(); it.Advance()) {
+    if (!HasExceptionHandler(*it.Current())) {
+      return false;
+    }
+  }
+  return true;
+}
+
 size_t HInstructionList::CountSize() const {
   size_t size = 0;
   HInstruction* current = first_instruction_;
@@ -1647,4 +1767,38 @@
   return os;
 }
 
+bool HInstruction::HasAnyEnvironmentUseBefore(HInstruction* other) {
+  // For now, assume that instructions in different blocks may use the
+  // environment.
+  // TODO: Use the control flow to decide if this is true.
+  if (GetBlock() != other->GetBlock()) {
+    return true;
+  }
+
+  // We know that we are in the same block. Walk from 'this' to 'other',
+  // checking to see if there is any instruction with an environment.
+  HInstruction* current = this;
+  for (; current != other && current != nullptr; current = current->GetNext()) {
+    // This is a conservative check, as the instruction result may not be in
+    // the referenced environment.
+    if (current->HasEnvironment()) {
+      return true;
+    }
+  }
+
+  // We should have been called with 'this' before 'other' in the block.
+  // Just confirm this.
+  DCHECK(current != nullptr);
+  return false;
+}
+
+void HInstruction::RemoveEnvironmentUsers() {
+  for (HUseIterator<HEnvironment*> use_it(GetEnvUses()); !use_it.Done(); use_it.Advance()) {
+    HUseListNode<HEnvironment*>* user_node = use_it.Current();
+    HEnvironment* user = user_node->GetUser();
+    user->SetRawEnvAt(user_node->GetIndex(), nullptr);
+  }
+  env_uses_.Clear();
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 04c3963..fd2a04d 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -38,6 +38,7 @@
 class HCurrentMethod;
 class HDoubleConstant;
 class HEnvironment;
+class HFakeString;
 class HFloatConstant;
 class HGraphBuilder;
 class HGraphVisitor;
@@ -48,6 +49,7 @@
 class HNullConstant;
 class HPhi;
 class HSuspendCheck;
+class HTryBoundary;
 class LiveInterval;
 class LocationSummary;
 class SlowPathCode;
@@ -181,6 +183,10 @@
     // visit for eliminating dead phis: a dead phi can only have loop header phi
     // users remaining when being visited.
     if (!AnalyzeNaturalLoops()) return false;
+    // Precompute per-block try membership before entering the SSA builder,
+    // which needs the information to build catch block phis from values of
+    // locals at throwing instructions inside try blocks.
+    ComputeTryBlockInformation();
     TransformToSsa();
     in_ssa_form_ = true;
     return true;
@@ -192,12 +198,17 @@
   void BuildDominatorTree();
   void TransformToSsa();
   void SimplifyCFG();
+  void SimplifyCatchBlocks();
 
   // Analyze all natural loops in this graph. Returns false if one
   // loop is not natural, that is the header does not dominate the
   // back edge.
   bool AnalyzeNaturalLoops() const;
 
+  // Iterate over blocks to compute try block membership. Needs reverse post
+  // order and loop information.
+  void ComputeTryBlockInformation();
+
   // Inline this graph in `outer_graph`, replacing the given `invoke` instruction.
   void InlineInto(HGraph* outer_graph, HInvoke* invoke);
 
@@ -325,6 +336,10 @@
     return invoke_type_;
   }
 
+  InstructionSet GetInstructionSet() const {
+    return instruction_set_;
+  }
+
  private:
   void VisitBlockForDominatorTree(HBasicBlock* block,
                                   HBasicBlock* predecessor,
@@ -725,8 +740,11 @@
     return GetPredecessorIndexOf(predecessor) == idx;
   }
 
-  // Returns whether successor at index `idx` is an exception handler.
-  bool IsExceptionalSuccessor(size_t idx) const;
+  // Returns the number of non-exceptional successors. SsaChecker ensures that
+  // these are stored at the beginning of the successor list.
+  size_t NumberOfNormalSuccessors() const {
+    return EndsWithTryBoundary() ? 1 : GetSuccessors().Size();
+  }
 
   // Split the block into two blocks just before `cursor`. Returns the newly
   // created, latter block. Note that this method will add the block to the
@@ -825,6 +843,15 @@
 
   bool IsInLoop() const { return loop_information_ != nullptr; }
 
+  HTryBoundary* GetTryEntry() const { return try_entry_; }
+  void SetTryEntry(HTryBoundary* try_entry) { try_entry_ = try_entry; }
+  bool IsInTry() const { return try_entry_ != nullptr; }
+
+  // Returns the try entry that this block's successors should have. They will
+  // be in the same try, unless the block ends in a try boundary. In that case,
+  // the appropriate try entry will be returned.
+  HTryBoundary* ComputeTryEntryOfSuccessors() const;
+
   // Returns whether this block dominates the blocked passed as parameter.
   bool Dominates(HBasicBlock* block) const;
 
@@ -841,6 +868,7 @@
 
   bool EndsWithControlFlowInstruction() const;
   bool EndsWithIf() const;
+  bool EndsWithTryBoundary() const;
   bool HasSinglePhi() const;
 
  private:
@@ -859,6 +887,10 @@
   size_t lifetime_end_;
   bool is_catch_block_;
 
+  // If this block is in a try block, `try_entry_` stores one of, possibly
+  // several, TryBoundary instructions entering it.
+  HTryBoundary* try_entry_;
+
   friend class HGraph;
   friend class HInstruction;
 
@@ -910,6 +942,7 @@
   M(DoubleConstant, Constant)                                           \
   M(Equal, Condition)                                                   \
   M(Exit, Instruction)                                                  \
+  M(FakeString, Instruction)                                            \
   M(FloatConstant, Constant)                                            \
   M(Goto, Instruction)                                                  \
   M(GreaterThan, Condition)                                             \
@@ -1335,8 +1368,7 @@
   const uint32_t dex_pc_;
   const InvokeType invoke_type_;
 
-  // The instruction that holds this environment. Only used in debug mode
-  // to ensure the graph is consistent.
+  // The instruction that holds this environment.
   HInstruction* const holder_;
 
   friend class HInstruction;
@@ -1659,6 +1691,14 @@
 
   virtual bool NeedsDexCache() const { return false; }
 
+  // Does this instruction have any use in an environment before
+  // control flow hits 'other'?
+  bool HasAnyEnvironmentUseBefore(HInstruction* other);
+
+  // Remove all references to environment uses of this instruction.
+  // The caller must ensure that this is safe to do.
+  void RemoveEnvironmentUsers();
+
  protected:
   virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0;
   virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0;
@@ -1962,29 +2002,24 @@
 
   // Returns whether `handler` is among its exception handlers (non-zero index
   // successors).
-  bool HasExceptionHandler(HBasicBlock* handler) const {
-    DCHECK(handler->IsCatchBlock());
-    return GetBlock()->GetSuccessors().Contains(handler, /* start_from */ 1);
-  }
-
-  // Returns whether successor at index `idx` is an exception handler.
-  bool IsExceptionalSuccessor(size_t idx) const {
-    DCHECK_LT(idx, GetBlock()->GetSuccessors().Size());
-    bool is_handler = (idx != 0);
-    DCHECK(!is_handler || GetBlock()->GetSuccessors().Get(idx)->IsCatchBlock());
-    return is_handler;
+  bool HasExceptionHandler(const HBasicBlock& handler) const {
+    DCHECK(handler.IsCatchBlock());
+    return GetBlock()->GetSuccessors().Contains(
+        const_cast<HBasicBlock*>(&handler), /* start_from */ 1);
   }
 
   // If not present already, adds `handler` to its block's list of exception
   // handlers.
   void AddExceptionHandler(HBasicBlock* handler) {
-    if (!HasExceptionHandler(handler)) {
+    if (!HasExceptionHandler(*handler)) {
       GetBlock()->AddSuccessor(handler);
     }
   }
 
   bool IsEntry() const { return kind_ == BoundaryKind::kEntry; }
 
+  bool HasSameExceptionHandlersAs(const HTryBoundary& other) const;
+
   DECLARE_INSTRUCTION(TryBoundary);
 
  private:
@@ -1993,6 +2028,24 @@
   DISALLOW_COPY_AND_ASSIGN(HTryBoundary);
 };
 
+// Iterator over exception handlers of a given HTryBoundary, i.e. over
+// exceptional successors of its basic block.
+class HExceptionHandlerIterator : public ValueObject {
+ public:
+  explicit HExceptionHandlerIterator(const HTryBoundary& try_boundary)
+    : block_(*try_boundary.GetBlock()), index_(block_.NumberOfNormalSuccessors()) {}
+
+  bool Done() const { return index_ == block_.GetSuccessors().Size(); }
+  HBasicBlock* Current() const { return block_.GetSuccessors().Get(index_); }
+  size_t CurrentSuccessorIndex() const { return index_; }
+  void Advance() { ++index_; }
+
+ private:
+  const HBasicBlock& block_;
+  size_t index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HExceptionHandlerIterator);
+};
 
 // Deoptimize to interpreter, upon checking a condition.
 class HDeoptimize : public HTemplateInstruction<1> {
@@ -2135,11 +2188,20 @@
   DISALLOW_COPY_AND_ASSIGN(HBinaryOperation);
 };
 
+// The comparison bias applies for floating point operations and indicates how NaN
+// comparisons are treated:
+enum class ComparisonBias {
+  kNoBias,  // bias is not applicable (i.e. for long operation)
+  kGtBias,  // return 1 for NaN comparisons
+  kLtBias,  // return -1 for NaN comparisons
+};
+
 class HCondition : public HBinaryOperation {
  public:
   HCondition(HInstruction* first, HInstruction* second)
       : HBinaryOperation(Primitive::kPrimBoolean, first, second),
-        needs_materialization_(true) {}
+        needs_materialization_(true),
+        bias_(ComparisonBias::kNoBias) {}
 
   bool NeedsMaterialization() const { return needs_materialization_; }
   void ClearNeedsMaterialization() { needs_materialization_ = false; }
@@ -2152,11 +2214,36 @@
 
   virtual IfCondition GetCondition() const = 0;
 
+  virtual IfCondition GetOppositeCondition() const = 0;
+
+  bool IsGtBias() const { return bias_ == ComparisonBias::kGtBias; }
+
+  void SetBias(ComparisonBias bias) { bias_ = bias; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return bias_ == other->AsCondition()->bias_;
+  }
+
+  bool IsFPConditionTrueIfNaN() const {
+    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType()));
+    IfCondition if_cond = GetCondition();
+    return IsGtBias() ? ((if_cond == kCondGT) || (if_cond == kCondGE)) : (if_cond == kCondNE);
+  }
+
+  bool IsFPConditionFalseIfNaN() const {
+    DCHECK(Primitive::IsFloatingPointType(InputAt(0)->GetType()));
+    IfCondition if_cond = GetCondition();
+    return IsGtBias() ? ((if_cond == kCondLT) || (if_cond == kCondLE)) : (if_cond == kCondEQ);
+  }
+
  private:
   // For register allocation purposes, returns whether this instruction needs to be
   // materialized (that is, not just be in the processor flags).
   bool needs_materialization_;
 
+  // Needed if we merge a HCompare into a HCondition.
+  ComparisonBias bias_;
+
   DISALLOW_COPY_AND_ASSIGN(HCondition);
 };
 
@@ -2181,6 +2268,10 @@
     return kCondEQ;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondNE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HEqual);
 };
@@ -2205,6 +2296,10 @@
     return kCondNE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondEQ;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HNotEqual);
 };
@@ -2227,6 +2322,10 @@
     return kCondLT;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondGE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HLessThan);
 };
@@ -2249,6 +2348,10 @@
     return kCondLE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondGT;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual);
 };
@@ -2271,6 +2374,10 @@
     return kCondGT;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondLE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HGreaterThan);
 };
@@ -2293,6 +2400,10 @@
     return kCondGE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondLT;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual);
 };
@@ -2302,18 +2413,10 @@
 // Result is 0 if input0 == input1, 1 if input0 > input1, or -1 if input0 < input1.
 class HCompare : public HBinaryOperation {
  public:
-  // The bias applies for floating point operations and indicates how NaN
-  // comparisons are treated:
-  enum Bias {
-    kNoBias,  // bias is not applicable (i.e. for long operation)
-    kGtBias,  // return 1 for NaN comparisons
-    kLtBias,  // return -1 for NaN comparisons
-  };
-
   HCompare(Primitive::Type type,
            HInstruction* first,
            HInstruction* second,
-           Bias bias,
+           ComparisonBias bias,
            uint32_t dex_pc)
       : HBinaryOperation(Primitive::kPrimInt, first, second), bias_(bias), dex_pc_(dex_pc) {
     DCHECK_EQ(type, first->GetType());
@@ -2338,14 +2441,16 @@
     return bias_ == other->AsCompare()->bias_;
   }
 
-  bool IsGtBias() { return bias_ == kGtBias; }
+  ComparisonBias GetBias() const { return bias_; }
+
+  bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; }
 
   uint32_t GetDexPc() const { return dex_pc_; }
 
   DECLARE_INSTRUCTION(Compare);
 
  private:
-  const Bias bias_;
+  const ComparisonBias bias_;
   const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HCompare);
@@ -2678,9 +2783,11 @@
                         ClinitCheckRequirement clinit_check_requirement)
       : HInvoke(arena,
                 number_of_arguments,
-                // There is one extra argument for the  HCurrentMethod node, and
-                // potentially one other if the clinit check is explicit.
-                clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 2u : 1u,
+                // There is one extra argument for the HCurrentMethod node, and
+                // potentially one other if the clinit check is explicit, and one other
+                // if the method is a string factory.
+                1u + (clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 1u : 0u)
+                   + (string_init_offset ? 1u : 0u),
                 return_type,
                 dex_pc,
                 dex_method_index,
@@ -2725,6 +2832,23 @@
     DCHECK(IsStaticWithImplicitClinitCheck());
   }
 
+  bool IsStringFactoryFor(HFakeString* str) const {
+    if (!IsStringInit()) return false;
+    // +1 for the current method.
+    if (InputCount() == (number_of_arguments_ + 1)) return false;
+    return InputAt(InputCount() - 1)->AsFakeString() == str;
+  }
+
+  void RemoveFakeStringArgumentAsLastInput() {
+    DCHECK(IsStringInit());
+    size_t last_input_index = InputCount() - 1;
+    HInstruction* last_input = InputAt(last_input_index);
+    DCHECK(last_input != nullptr);
+    DCHECK(last_input->IsFakeString()) << last_input->DebugName();
+    RemoveAsUserOfInput(last_input_index);
+    inputs_.DeleteAt(last_input_index);
+  }
+
   // Is this a call to a static method whose declaring class has an
   // explicit intialization check in the graph?
   bool IsStaticWithExplicitClinitCheck() const {
@@ -3283,6 +3407,8 @@
     }
   }
 
+  bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); }
+
   size_t InputCount() const OVERRIDE { return inputs_.Size(); }
 
   void AddInput(HInstruction* input);
@@ -3709,6 +3835,7 @@
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
   bool IsReferrersClass() const { return is_referrers_class_; }
+  bool CanBeNull() const OVERRIDE { return false; }
 
   bool NeedsEnvironment() const OVERRIDE {
     // Will call runtime and load the class if the class is not loaded yet.
@@ -4078,13 +4205,19 @@
   };
 
   HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc)
-    : HTemplateInstruction(SideEffects::None()), kind_(kind), dex_pc_(dex_pc) {
+    : HTemplateInstruction(SideEffects::ChangesSomething()), kind_(kind), dex_pc_(dex_pc) {
     SetRawInputAt(0, object);
   }
 
   // Instruction may throw a Java exception, so we need an environment.
-  bool NeedsEnvironment() const OVERRIDE { return true; }
-  bool CanThrow() const OVERRIDE { return true; }
+  bool NeedsEnvironment() const OVERRIDE { return CanThrow(); }
+
+  bool CanThrow() const OVERRIDE {
+    // Verifier guarantees that monitor-exit cannot throw.
+    // This is important because it allows the HGraphBuilder to remove
+    // a dead throw-catch loop generated for `synchronized` blocks/methods.
+    return IsEnter();
+  }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
@@ -4100,6 +4233,25 @@
   DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
 };
 
+/**
+ * A HInstruction used as a marker for the replacement of new + <init>
+ * of a String to a call to a StringFactory. Only baseline will see
+ * the node at code generation, where it will be be treated as null.
+ * When compiling non-baseline, `HFakeString` instructions are being removed
+ * in the instruction simplifier.
+ */
+class HFakeString : public HTemplateInstruction<0> {
+ public:
+  HFakeString() : HTemplateInstruction(SideEffects::None()) {}
+
+  Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimNot; }
+
+  DECLARE_INSTRUCTION(FakeString);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HFakeString);
+};
+
 class MoveOperands : public ArenaObject<kArenaAllocMisc> {
  public:
   MoveOperands(Location source,
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index bc8b193..3174806 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -132,7 +132,7 @@
   void StartPass(const char* pass_name) {
     // Dump graph first, then start timer.
     if (visualizer_enabled_) {
-      visualizer_.DumpGraph(pass_name, /* is_after_pass */ false);
+      visualizer_.DumpGraph(pass_name, /* is_after_pass */ false, graph_in_bad_state_);
     }
     if (timing_logger_enabled_) {
       timing_logger_.StartTiming(pass_name);
@@ -145,7 +145,7 @@
       timing_logger_.EndTiming();
     }
     if (visualizer_enabled_) {
-      visualizer_.DumpGraph(pass_name, /* is_after_pass */ true);
+      visualizer_.DumpGraph(pass_name, /* is_after_pass */ true, graph_in_bad_state_);
     }
 
     // Validate the HGraph if running in debug mode.
@@ -627,8 +627,8 @@
   // `run_optimizations_` is set explicitly (either through a compiler filter
   // or the debuggable flag). If it is set, we can run baseline. Otherwise, we fall back
   // to Quick.
-  bool can_use_baseline = !run_optimizations_;
-  if (run_optimizations_ && can_optimize && can_allocate_registers) {
+  bool can_use_baseline = !run_optimizations_ && builder.CanUseBaselineForStringInit();
+  if (run_optimizations_ && can_allocate_registers) {
     VLOG(compiler) << "Optimizing " << method_name;
 
     {
@@ -637,16 +637,21 @@
         // We could not transform the graph to SSA, bailout.
         LOG(INFO) << "Skipping compilation of " << method_name << ": it contains a non natural loop";
         MaybeRecordStat(MethodCompilationStat::kNotCompiledCannotBuildSSA);
+        pass_observer.SetGraphInBadState();
         return nullptr;
       }
     }
 
-    return CompileOptimized(graph,
-                            codegen.get(),
-                            compiler_driver,
-                            dex_compilation_unit,
-                            &pass_observer);
-  } else if (shouldOptimize && can_allocate_registers) {
+    if (can_optimize) {
+      return CompileOptimized(graph,
+                              codegen.get(),
+                              compiler_driver,
+                              dex_compilation_unit,
+                              &pass_observer);
+    }
+  }
+
+  if (shouldOptimize && can_allocate_registers) {
     LOG(FATAL) << "Could not allocate registers in optimizing compiler";
     UNREACHABLE();
   } else if (can_use_baseline) {
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 3d6606b..68316c2 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -99,6 +99,12 @@
     return;
   }
 
+  if (!obj->CanBeNull() || obj->IsNullConstant()) {
+    // Null check is dead code and will be removed by DCE.
+    return;
+  }
+  DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
+
   // We only need to bound the type if we have uses in the relevant block.
   // So start with null and create the HBoundType lazily, only if it's needed.
   HBoundType* bound_type = nullptr;
@@ -160,6 +166,7 @@
     // input.
     return;
   }
+  DCHECK(!obj->IsLoadClass()) << "We should not replace HLoadClass instructions";
   for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) {
     HInstruction* user = it.Current()->GetUser();
     if (instanceOfTrueBlock->Dominates(user->GetBlock())) {
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 7b23d02..72ddabe 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -209,6 +209,8 @@
     Location temp = locations->GetTemp(i);
     if (temp.IsRegister() || temp.IsFpuRegister()) {
       BlockRegister(temp, position, position + 1);
+      // Ensure that an explicit temporary register is marked as being allocated.
+      codegen_->AddAllocatedRegister(temp);
     } else {
       DCHECK(temp.IsUnallocated());
       switch (temp.GetPolicy()) {
@@ -507,6 +509,11 @@
       }
 
       if (current->HasRegister()) {
+        if (kIsDebugBuild && log_fatal_on_failure && !current->IsFixed()) {
+          // Only check when an error is fatal. Only tests code ask for non-fatal failures
+          // and test code may not properly fill the right information to the code generator.
+          CHECK(codegen.HasAllocatedRegister(processing_core_registers, current->GetRegister()));
+        }
         BitVector* liveness_of_register = liveness_of_values.Get(current->GetRegister());
         for (size_t j = it.CurrentRange()->GetStart(); j < it.CurrentRange()->GetEnd(); ++j) {
           if (liveness_of_register->IsBitSet(j)) {
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index c37b199..ff2e6ad 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -350,7 +350,9 @@
 void SsaBuilder::VisitBasicBlock(HBasicBlock* block) {
   current_locals_ = GetLocalsFor(block);
 
-  if (block->IsLoopHeader()) {
+  if (block->IsCatchBlock()) {
+    // Catch phis were already created and inputs collected from throwing sites.
+  } else if (block->IsLoopHeader()) {
     // If the block is a loop header, we know we only have visited the pre header
     // because we are visiting in reverse post order. We create phis for all initialized
     // locals from the pre header. Their inputs will be populated at the end of
@@ -551,19 +553,32 @@
 }
 
 void SsaBuilder::VisitInstruction(HInstruction* instruction) {
-  if (!instruction->NeedsEnvironment()) {
-    return;
+  if (instruction->NeedsEnvironment()) {
+    HEnvironment* environment = new (GetGraph()->GetArena()) HEnvironment(
+        GetGraph()->GetArena(),
+        current_locals_->Size(),
+        GetGraph()->GetDexFile(),
+        GetGraph()->GetMethodIdx(),
+        instruction->GetDexPc(),
+        GetGraph()->GetInvokeType(),
+        instruction);
+    environment->CopyFrom(*current_locals_);
+    instruction->SetRawEnvironment(environment);
   }
-  HEnvironment* environment = new (GetGraph()->GetArena()) HEnvironment(
-      GetGraph()->GetArena(),
-      current_locals_->Size(),
-      GetGraph()->GetDexFile(),
-      GetGraph()->GetMethodIdx(),
-      instruction->GetDexPc(),
-      GetGraph()->GetInvokeType(),
-      instruction);
-  environment->CopyFrom(*current_locals_);
-  instruction->SetRawEnvironment(environment);
+
+  // If in a try block, propagate values of locals into catch blocks.
+  if (instruction->GetBlock()->IsInTry() && instruction->CanThrow()) {
+    HTryBoundary* try_block = instruction->GetBlock()->GetTryEntry();
+    for (HExceptionHandlerIterator it(*try_block); !it.Done(); it.Advance()) {
+      GrowableArray<HInstruction*>* handler_locals = GetLocalsFor(it.Current());
+      for (size_t i = 0, e = current_locals_->Size(); i < e; ++i) {
+        HInstruction* local_value = current_locals_->Get(i);
+        if (local_value != nullptr) {
+          handler_locals->Get(i)->AsPhi()->AddInput(local_value);
+        }
+      }
+    }
+  }
 }
 
 void SsaBuilder::VisitTemporary(HTemporary* temp) {
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 1c83c4b..64600db 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -61,9 +61,22 @@
   GrowableArray<HInstruction*>* GetLocalsFor(HBasicBlock* block) {
     GrowableArray<HInstruction*>* locals = locals_for_.Get(block->GetBlockId());
     if (locals == nullptr) {
-      locals = new (GetGraph()->GetArena()) GrowableArray<HInstruction*>(
-          GetGraph()->GetArena(), GetGraph()->GetNumberOfVRegs());
-      locals->SetSize(GetGraph()->GetNumberOfVRegs());
+      const size_t vregs = GetGraph()->GetNumberOfVRegs();
+      ArenaAllocator* arena = GetGraph()->GetArena();
+      locals = new (arena) GrowableArray<HInstruction*>(arena, vregs);
+      locals->SetSize(vregs);
+
+      if (block->IsCatchBlock()) {
+        // We record incoming inputs of catch phis at throwing instructions and
+        // must therefore eagerly create the phis. Unused phis will be removed
+        // in the dead phi analysis.
+        for (size_t i = 0; i < vregs; ++i) {
+          HPhi* phi = new (arena) HPhi(arena, i, 0, Primitive::kPrimVoid);
+          block->AddPhi(phi);
+          locals->Put(i, phi);
+        }
+      }
+
       locals_for_.Put(block->GetBlockId(), locals);
     }
     return locals;
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index 2f2e2d1..917341a 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -114,6 +114,12 @@
       continue;
     }
 
+    if (phi->InputCount() == 0) {
+      DCHECK(phi->IsCatchPhi());
+      DCHECK(phi->IsDead());
+      continue;
+    }
+
     // Find if the inputs of the phi are the same instruction.
     HInstruction* candidate = phi->InputAt(0);
     // A loop phi cannot have itself as the first phi. Note that this
@@ -137,6 +143,11 @@
       continue;
     }
 
+    // The candidate may not dominate a phi in a catch block.
+    if (phi->IsCatchPhi() && !candidate->StrictlyDominates(phi)) {
+      continue;
+    }
+
     if (phi->IsInLoop()) {
       // Because we're updating the users of this phi, we may have new
       // phis candidate for elimination if this phi is in a loop. Add phis that
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 09d2270..0e3e08c 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -252,11 +252,11 @@
   if (offset_ < 0) {
     int32_t off = -offset_;
     CHECK_LT(off, 1024);
-    CHECK_EQ((off & 3 /* 0b11 */), 0);    // Must be multiple of 4.
+    CHECK_ALIGNED(off, 4);
     encoding = (am ^ (1 << kUShift)) | off >> 2;  // Flip U to adjust sign.
   } else {
     CHECK_LT(offset_, 1024);
-    CHECK_EQ((offset_ & 3 /* 0b11 */), 0);    // Must be multiple of 4.
+    CHECK_ALIGNED(offset_, 4);
     encoding =  am | offset_ >> 2;
   }
   encoding |= static_cast<uint32_t>(rn_) << 16;
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 2dde014..5843886 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -101,7 +101,7 @@
   }
 
   // Adjust literal pool labels for padding.
-  DCHECK_EQ(current_code_size & 1u, 0u);
+  DCHECK_ALIGNED(current_code_size, 2);
   uint32_t literals_adjustment = current_code_size + (current_code_size & 2) - buffer_.Size();
   if (literals_adjustment != 0u) {
     for (Literal& literal : literals_) {
@@ -152,7 +152,7 @@
     // Load literal instructions (LDR, LDRD, VLDR) require 4-byte alignment.
     // We don't support byte and half-word literals.
     uint32_t code_size = buffer_.Size();
-    DCHECK_EQ(code_size & 1u, 0u);
+    DCHECK_ALIGNED(code_size, 2);
     if ((code_size & 2u) != 0u) {
       Emit16(0);
     }
@@ -168,7 +168,7 @@
 }
 
 inline int16_t Thumb2Assembler::BEncoding16(int32_t offset, Condition cond) {
-  DCHECK_EQ(offset & 1, 0);
+  DCHECK_ALIGNED(offset, 2);
   int16_t encoding = B15 | B14;
   if (cond != AL) {
     DCHECK(IsInt<9>(offset));
@@ -181,7 +181,7 @@
 }
 
 inline int32_t Thumb2Assembler::BEncoding32(int32_t offset, Condition cond) {
-  DCHECK_EQ(offset & 1, 0);
+  DCHECK_ALIGNED(offset, 2);
   int32_t s = (offset >> 31) & 1;   // Sign bit.
   int32_t encoding = B31 | B30 | B29 | B28 | B15 |
       (s << 26) |                   // Sign bit goes to bit 26.
@@ -205,7 +205,7 @@
 
 inline int16_t Thumb2Assembler::CbxzEncoding16(Register rn, int32_t offset, Condition cond) {
   DCHECK(!IsHighRegister(rn));
-  DCHECK_EQ(offset & 1, 0);
+  DCHECK_ALIGNED(offset, 2);
   DCHECK(IsUint<7>(offset));
   DCHECK(cond == EQ || cond == NE);
   return B15 | B13 | B12 | B8 | (cond == NE ? B11 : 0) | static_cast<int32_t>(rn) |
@@ -250,7 +250,7 @@
 
 inline int16_t Thumb2Assembler::LdrLitEncoding16(Register rt, int32_t offset) {
   DCHECK(!IsHighRegister(rt));
-  DCHECK_EQ(offset & 3, 0);
+  DCHECK_ALIGNED(offset, 4);
   DCHECK(IsUint<10>(offset));
   return B14 | B11 | (static_cast<int32_t>(rt) << 8) | (offset >> 2);
 }
@@ -261,7 +261,7 @@
 }
 
 inline int32_t Thumb2Assembler::LdrdEncoding32(Register rt, Register rt2, Register rn, int32_t offset) {
-  DCHECK_EQ(offset & 3, 0);
+  DCHECK_ALIGNED(offset, 4);
   CHECK(IsUint<10>(offset));
   return B31 | B30 | B29 | B27 |
       B24 /* P = 1 */ | B23 /* U = 1 */ | B22 | 0 /* W = 0 */ | B20 |
@@ -270,7 +270,7 @@
 }
 
 inline int32_t Thumb2Assembler::VldrsEncoding32(SRegister sd, Register rn, int32_t offset) {
-  DCHECK_EQ(offset & 3, 0);
+  DCHECK_ALIGNED(offset, 4);
   CHECK(IsUint<10>(offset));
   return B31 | B30 | B29 | B27 | B26 | B24 |
       B23 /* U = 1 */ | B20 | B11 | B9 |
@@ -281,7 +281,7 @@
 }
 
 inline int32_t Thumb2Assembler::VldrdEncoding32(DRegister dd, Register rn, int32_t offset) {
-  DCHECK_EQ(offset & 3, 0);
+  DCHECK_ALIGNED(offset, 4);
   CHECK(IsUint<10>(offset));
   return B31 | B30 | B29 | B27 | B26 | B24 |
       B23 /* U = 1 */ | B20 | B11 | B9 | B8 |
@@ -294,7 +294,7 @@
 inline int16_t Thumb2Assembler::LdrRtRnImm5Encoding16(Register rt, Register rn, int32_t offset) {
   DCHECK(!IsHighRegister(rt));
   DCHECK(!IsHighRegister(rn));
-  DCHECK_EQ(offset & 3, 0);
+  DCHECK_ALIGNED(offset, 4);
   DCHECK(IsUint<7>(offset));
   return B14 | B13 | B11 |
       (static_cast<int32_t>(rn) << 3) | static_cast<int32_t>(rt) |
@@ -975,6 +975,7 @@
 }
 
 void Thumb2Assembler::b(Label* label, Condition cond) {
+  DCHECK_EQ(next_condition_, AL);
   EmitBranch(cond, label, false, false);
 }
 
@@ -1422,7 +1423,7 @@
           thumb_opcode = 3U /* 0b11 */;
           opcode_shift = 12;
           CHECK_LT(immediate, (1u << 9));
-          CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
+          CHECK_ALIGNED(immediate, 4);
 
           // Remove rd and rn from instruction by orring it with immed and clearing bits.
           rn = R0;
@@ -1436,7 +1437,7 @@
           thumb_opcode = 5U /* 0b101 */;
           opcode_shift = 11;
           CHECK_LT(immediate, (1u << 10));
-          CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
+          CHECK_ALIGNED(immediate, 4);
 
           // Remove rn from instruction.
           rn = R0;
@@ -1473,7 +1474,7 @@
            thumb_opcode = 0x61 /* 0b1100001 */;
            opcode_shift = 7;
            CHECK_LT(immediate, (1u << 9));
-           CHECK_EQ((immediate & 3u /* 0b11 */), 0u);
+           CHECK_ALIGNED(immediate, 4);
 
            // Remove rd and rn from instruction by orring it with immed and clearing bits.
            rn = R0;
@@ -1651,7 +1652,7 @@
 
 inline size_t Thumb2Assembler::Fixup::LiteralPoolPaddingSize(uint32_t current_code_size) {
   // The code size must be a multiple of 2.
-  DCHECK_EQ(current_code_size & 1u, 0u);
+  DCHECK_ALIGNED(current_code_size, 2);
   // If it isn't a multiple of 4, we need to add a 2-byte padding before the literal pool.
   return current_code_size & 2;
 }
@@ -1696,7 +1697,7 @@
       // Load literal instructions round down the PC+4 to a multiple of 4, so if the PC
       // isn't a multiple of 2, we need to adjust. Since we already adjusted for the target
       // being aligned, current PC alignment can be inferred from diff.
-      DCHECK_EQ(diff & 1, 0);
+      DCHECK_ALIGNED(diff, 2);
       diff = diff + (diff & 2);
       DCHECK_GE(diff, 0);
       break;
@@ -2044,7 +2045,7 @@
       if (sp_relative) {
         // SP relative, 10 bit offset.
         CHECK_LT(offset, (1 << 10));
-        CHECK_EQ((offset & 3 /* 0b11 */), 0);
+        CHECK_ALIGNED(offset, 4);
         encoding |= rd << 8 | offset >> 2;
       } else {
         // No SP relative.  The offset is shifted right depending on
@@ -2057,12 +2058,12 @@
         } else if (half) {
           // 6 bit offset, shifted by 1.
           CHECK_LT(offset, (1 << 6));
-          CHECK_EQ((offset & 1 /* 0b1 */), 0);
+          CHECK_ALIGNED(offset, 2);
           offset >>= 1;
         } else {
           // 7 bit offset, shifted by 2.
           CHECK_LT(offset, (1 << 7));
-          CHECK_EQ((offset & 3 /* 0b11 */), 0);
+          CHECK_ALIGNED(offset, 4);
           offset >>= 2;
         }
         encoding |= rn << 3 | offset  << 6;
diff --git a/compiler/utils/arm/constants_arm.h b/compiler/utils/arm/constants_arm.h
index 1513296..6b4daed 100644
--- a/compiler/utils/arm/constants_arm.h
+++ b/compiler/utils/arm/constants_arm.h
@@ -32,8 +32,9 @@
 // Defines constants and accessor classes to assemble, disassemble and
 // simulate ARM instructions.
 //
-// Section references in the code refer to the "ARM Architecture Reference
-// Manual" from July 2005 (available at http://www.arm.com/miscPDFs/14128.pdf)
+// Section references in the code refer to the "ARM Architecture
+// Reference Manual ARMv7-A and ARMv7-R edition", issue C.b (24 July
+// 2012).
 //
 // Constants for specific fields are defined in their respective named enums.
 // General constants are in an anonymous enum in class Instr.
@@ -97,26 +98,32 @@
 std::ostream& operator<<(std::ostream& os, const DRegister& rhs);
 
 
-// Values for the condition field as defined in section A3.2.
+// Values for the condition field as defined in Table A8-1 "Condition
+// codes" (refer to Section A8.3 "Conditional execution").
 enum Condition {  // private marker to avoid generate-operator-out.py from processing.
   kNoCondition = -1,
-  EQ = 0,   // equal
-  NE = 1,   // not equal
-  CS = 2,   // carry set/unsigned higher or same
-  CC = 3,   // carry clear/unsigned lower
-  MI = 4,   // minus/negative
-  PL = 5,   // plus/positive or zero
-  VS = 6,   // overflow
-  VC = 7,   // no overflow
-  HI = 8,   // unsigned higher
-  LS = 9,   // unsigned lower or same
-  GE = 10,  // signed greater than or equal
-  LT = 11,  // signed less than
-  GT = 12,  // signed greater than
-  LE = 13,  // signed less than or equal
-  AL = 14,  // always (unconditional)
-  kSpecialCondition = 15,  // special condition (refer to section A3.2.1)
+  //           Meaning (integer)                      | Meaning (floating-point)
+  //           ---------------------------------------+-----------------------------------------
+  EQ = 0,   // Equal                                  | Equal
+  NE = 1,   // Not equal                              | Not equal, or unordered
+  CS = 2,   // Carry set                              | Greater than, equal, or unordered
+  CC = 3,   // Carry clear                            | Less than
+  MI = 4,   // Minus, negative                        | Less than
+  PL = 5,   // Plus, positive or zero                 | Greater than, equal, or unordered
+  VS = 6,   // Overflow                               | Unordered (i.e. at least one NaN operand)
+  VC = 7,   // No overflow                            | Not unordered
+  HI = 8,   // Unsigned higher                        | Greater than, or unordered
+  LS = 9,   // Unsigned lower or same                 | Less than or equal
+  GE = 10,  // Signed greater than or equal           | Greater than or equal
+  LT = 11,  // Signed less than                       | Less than, or unordered
+  GT = 12,  // Signed greater than                    | Greater than
+  LE = 13,  // Signed less than or equal              | Less than, equal, or unordered
+  AL = 14,  // Always (unconditional)                 | Always (unconditional)
+  kSpecialCondition = 15,  // Special condition (refer to Section A8.3 "Conditional execution").
   kMaxCondition = 16,
+
+  HS = CS,  // HS (unsigned higher or same) is a synonym for CS.
+  LO = CC   // LO (unsigned lower) is a synonym for CC.
 };
 std::ostream& operator<<(std::ostream& os, const Condition& rhs);
 
diff --git a/compiler/utils/array_ref.h b/compiler/utils/array_ref.h
index ff5a77c..303e0d5 100644
--- a/compiler/utils/array_ref.h
+++ b/compiler/utils/array_ref.h
@@ -62,14 +62,14 @@
   }
 
   template <size_t size>
-  constexpr ArrayRef(T (&array)[size])
+  explicit constexpr ArrayRef(T (&array)[size])
     : array_(array), size_(size) {
   }
 
   template <typename U, size_t size>
-  constexpr ArrayRef(U (&array)[size],
-                     typename std::enable_if<std::is_same<T, const U>::value, tag>::type
-                         t ATTRIBUTE_UNUSED = tag())
+  explicit constexpr ArrayRef(U (&array)[size],
+                              typename std::enable_if<std::is_same<T, const U>::value, tag>::type
+                                  t ATTRIBUTE_UNUSED = tag())
     : array_(array), size_(size) {
   }
 
@@ -83,9 +83,9 @@
   }
 
   template <typename U, typename Alloc>
-  ArrayRef(const std::vector<U, Alloc>& v,
-           typename std::enable_if<std::is_same<T, const U>::value, tag>::type
-               t ATTRIBUTE_UNUSED = tag())
+  explicit ArrayRef(const std::vector<U, Alloc>& v,
+                    typename std::enable_if<std::is_same<T, const U>::value, tag>::type
+                        t ATTRIBUTE_UNUSED = tag())
       : array_(v.data()), size_(v.size()) {
   }
 
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index b86bc85..6da5c35 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -953,6 +953,48 @@
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd");
 }
 
+TEST_F(AssemblerX86_64Test, UcomissAddress) {
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM1), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM2), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM3), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), 0));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM4), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
+  const char* expected =
+    "ucomiss 0xc(%RDI,%RBX,4), %xmm0\n"
+    "ucomiss 0xc(%RDI,%R9,4), %xmm1\n"
+    "ucomiss 0xc(%RDI,%R9,4), %xmm2\n"
+    "ucomiss (%R13), %xmm3\n"
+    "ucomiss (%R13,%R9,1), %xmm4\n";
+
+  DriverStr(expected, "ucomiss_address");
+}
+
+TEST_F(AssemblerX86_64Test, UcomisdAddress) {
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM1), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM2), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM3), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), 0));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM4), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
+  const char* expected =
+    "ucomisd 0xc(%RDI,%RBX,4), %xmm0\n"
+    "ucomisd 0xc(%RDI,%R9,4), %xmm1\n"
+    "ucomisd 0xc(%RDI,%R9,4), %xmm2\n"
+    "ucomisd (%R13), %xmm3\n"
+    "ucomisd (%R13,%R9,1), %xmm4\n";
+
+  DriverStr(expected, "ucomisd_address");
+}
+
 // X87
 
 std::string x87_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
diff --git a/dex2oat/Android.mk b/dex2oat/Android.mk
index 321cd75..2c90623 100644
--- a/dex2oat/Android.mk
+++ b/dex2oat/Android.mk
@@ -14,6 +14,15 @@
 # limitations under the License.
 #
 
+# ASan slows down dex2oat by ~3.5x, which translates into extremely slow first
+# boot. Disabled to help speed up SANITIZE_TARGET mode.
+# The supported way of using SANITIZE_TARGET is by first running a normal build,
+# followed by a SANITIZE_TARGET=address build on top of it (in the same build
+# tree). By disabling this module in SANITIZE_TARGET build, we keep the regular,
+# uninstrumented version of it.
+# Bug: 22233158
+ifneq (address,$(strip $(SANITIZE_TARGET)))
+
 LOCAL_PATH := $(call my-dir)
 
 include art/build/Android.executable.mk
@@ -38,16 +47,26 @@
 endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler,art/compiler,target,ndebug,$(dex2oat_target_arch)))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain,art/compiler,target,ndebug,$(dex2oat_target_arch)))
 endif
+
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler,art/compiler,target,debug,$(dex2oat_target_arch)))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain,art/compiler,target,debug,$(dex2oat_target_arch)))
 endif
 
 # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libziparchive-host,art/compiler,host,ndebug,$(dex2oat_host_arch)))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain libziparchive-host,art/compiler,host,ndebug,$(dex2oat_host_arch)))
+  ifeq ($(ART_BUILD_HOST_STATIC),true)
+    $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart libart-compiler libart libziparchive-host libnativehelper libnativebridge libsigchain_dummy libvixl liblog libz libbacktrace libcutils libunwindbacktrace libutils libbase,art/compiler,host,ndebug,$(dex2oat_host_arch),static))
+  endif
 endif
+
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libziparchive-host,art/compiler,host,debug,$(dex2oat_host_arch)))
+  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain libziparchive-host,art/compiler,host,debug,$(dex2oat_host_arch)))
+  ifeq ($(ART_BUILD_HOST_STATIC),true)
+    $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd libartd-compiler libartd libziparchive-host libnativehelper libnativebridge libsigchain_dummy libvixld liblog libz libbacktrace libcutils libunwindbacktrace libutils libbase,art/compiler,host,debug,$(dex2oat_host_arch),static))
+  endif
+endif
+
 endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 74d5c0c..74ec2ed 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -18,7 +18,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
-#include <valgrind.h>
+#include "base/memory_tool.h"
 
 #include <fstream>
 #include <iostream>
@@ -519,7 +519,7 @@
     // the runtime.
     LogCompletionTime();
 
-    if (kIsDebugBuild || (RUNNING_ON_VALGRIND != 0)) {
+    if (kIsDebugBuild || (RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
       delete runtime_;  // See field declaration for why this is manual.
     }
   }
@@ -975,6 +975,8 @@
       case kArm64:
       case kX86:
       case kX86_64:
+      case kMips:
+      case kMips64:
         implicit_null_checks = true;
         implicit_so_checks = true;
         break;
@@ -1038,10 +1040,6 @@
   bool OpenFile() {
     bool create_file = !oat_unstripped_.empty();  // as opposed to using open file descriptor
     if (create_file) {
-      // We're supposed to create this file. If the file already exists, it may be in use currently.
-      // We must not change the content of that file, then. So unlink it first.
-      unlink(oat_unstripped_.c_str());
-
       oat_file_.reset(OS::CreateEmptyFile(oat_unstripped_.c_str()));
       if (oat_location_.empty()) {
         oat_location_ = oat_filename_;
@@ -1129,6 +1127,9 @@
     if (!image_) {
       runtime_options.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr));
     }
+    // Disable libsigchain. We don't don't need it during compilation and it prevents us
+    // from getting a statically linked version of dex2oat (because of dlsym and RTLD_NEXT).
+    runtime_options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
 
     if (!CreateRuntime(runtime_options)) {
       return false;
@@ -2002,7 +2003,7 @@
   // Everything was done, do an explicit exit here to avoid running Runtime destructors that take
   // time (bug 10645725) unless we're a debug build or running on valgrind. Note: The Dex2Oat class
   // should not destruct the runtime in this case.
-  if (!art::kIsDebugBuild && (RUNNING_ON_VALGRIND == 0)) {
+  if (!art::kIsDebugBuild && (RUNNING_ON_MEMORY_TOOL == 0)) {
     exit(result);
   }
   return result;
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
new file mode 100755
index 0000000..c6b4d47
--- /dev/null
+++ b/dexdump/Android.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2015 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.
+
+# TODO(ajcbik): Art-i-fy this makefile
+
+# TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed
+
+LOCAL_PATH:= $(call my-dir)
+
+dexdump_src_files := dexdump_main.cc dexdump.cc
+dexdump_c_includes := art/runtime
+dexdump_libraries := libart
+
+##
+## Build the device command line tool dexdump.
+##
+
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := cc
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_CFLAGS += -Wall
+LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
+LOCAL_MODULE := dexdump2
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
+endif # !SDK_ONLY
+
+##
+## Build the host command line tool dexdump.
+##
+
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := cc
+LOCAL_SRC_FILES := $(dexdump_src_files)
+LOCAL_C_INCLUDES := $(dexdump_c_includes)
+LOCAL_CFLAGS += -Wall
+LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
+LOCAL_MODULE := dexdump2
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
new file mode 100644
index 0000000..84c465f
--- /dev/null
+++ b/dexdump/dexdump.cc
@@ -0,0 +1,1287 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ * Implementation file of the dexdump utility.
+ *
+ * This is a re-implementation of the original dexdump utility that was
+ * based on Dalvik functions in libdex into a new dexdump that is now
+ * based on Art functions in libart instead. The output is identical to
+ * the original for correct DEX files. Error messages may differ, however.
+ * Also, ODEX files are no longer supported.
+ *
+ * The dexdump tool is intended to mimic objdump.  When possible, use
+ * similar command-line arguments.
+ *
+ * Differences between XML output and the "current.xml" file:
+ * - classes in same package are not all grouped together; nothing is sorted
+ * - no "deprecated" on fields and methods
+ * - no "value" on fields
+ * - no parameter names
+ * - no generic signatures on parameters, e.g. type="java.lang.Class&lt;?&gt;"
+ * - class shows declared fields and methods; does not show inherited fields
+ */
+
+#include "dexdump.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <memory>
+#include <vector>
+
+#include "dex_file-inl.h"
+#include "dex_instruction-inl.h"
+
+namespace art {
+
+/*
+ * Options parsed in main driver.
+ */
+struct Options gOptions;
+
+/*
+ * Output file. Defaults to stdout.
+ */
+FILE* gOutFile = stdout;
+
+/*
+ * Data types that match the definitions in the VM specification.
+ */
+typedef uint8_t  u1;
+typedef uint16_t u2;
+typedef uint32_t u4;
+typedef uint64_t u8;
+typedef int32_t  s4;
+typedef int64_t  s8;
+
+/*
+ * Basic information about a field or a method.
+ */
+struct FieldMethodInfo {
+  const char* classDescriptor;
+  const char* name;
+  const char* signature;
+};
+
+/*
+ * Flags for use with createAccessFlagStr().
+ */
+enum AccessFor {
+  kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
+};
+const int kNumFlags = 18;
+
+/*
+ * Gets 2 little-endian bytes.
+ */
+static inline u2 get2LE(unsigned char const* pSrc) {
+  return pSrc[0] | (pSrc[1] << 8);
+}
+
+/*
+ * Converts a single-character primitive type into human-readable form.
+ */
+static const char* primitiveTypeLabel(char typeChar) {
+  switch (typeChar) {
+    case 'B': return "byte";
+    case 'C': return "char";
+    case 'D': return "double";
+    case 'F': return "float";
+    case 'I': return "int";
+    case 'J': return "long";
+    case 'S': return "short";
+    case 'V': return "void";
+    case 'Z': return "boolean";
+    default:  return "UNKNOWN";
+  }  // switch
+}
+
+/*
+ * Converts a type descriptor to human-readable "dotted" form.  For
+ * example, "Ljava/lang/String;" becomes "java.lang.String", and
+ * "[I" becomes "int[]".  Also converts '$' to '.', which means this
+ * form can't be converted back to a descriptor.
+ */
+static char* descriptorToDot(const char* str) {
+  int targetLen = strlen(str);
+  int offset = 0;
+
+  // Strip leading [s; will be added to end.
+  while (targetLen > 1 && str[offset] == '[') {
+    offset++;
+    targetLen--;
+  }  // while
+
+  const int arrayDepth = offset;
+
+  if (targetLen == 1) {
+    // Primitive type.
+    str = primitiveTypeLabel(str[offset]);
+    offset = 0;
+    targetLen = strlen(str);
+  } else {
+    // Account for leading 'L' and trailing ';'.
+    if (targetLen >= 2 && str[offset] == 'L' &&
+        str[offset + targetLen - 1] == ';') {
+      targetLen -= 2;
+      offset++;
+    }
+  }
+
+  // Copy class name over.
+  char* newStr = reinterpret_cast<char*>(
+      malloc(targetLen + arrayDepth * 2 + 1));
+  int i = 0;
+  for (; i < targetLen; i++) {
+    const char ch = str[offset + i];
+    newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
+  }  // for
+
+  // Add the appropriate number of brackets for arrays.
+  for (int j = 0; j < arrayDepth; j++) {
+    newStr[i++] = '[';
+    newStr[i++] = ']';
+  }  // for
+
+  newStr[i] = '\0';
+  return newStr;
+}
+
+/*
+ * Converts the class name portion of a type descriptor to human-readable
+ * "dotted" form.
+ *
+ * Returns a newly-allocated string.
+ */
+static char* descriptorClassToDot(const char* str) {
+  // Reduce to just the class name, trimming trailing ';'.
+  const char* lastSlash = strrchr(str, '/');
+  if (lastSlash == nullptr) {
+    lastSlash = str + 1;  // start past 'L'
+  } else {
+    lastSlash++;          // start past '/'
+  }
+
+  char* newStr = strdup(lastSlash);
+  newStr[strlen(lastSlash) - 1] = '\0';
+  for (char* cp = newStr; *cp != '\0'; cp++) {
+    if (*cp == '$') {
+      *cp = '.';
+    }
+  }  // for
+  return newStr;
+}
+
+/*
+ * Returns a quoted string representing the boolean value.
+ */
+static const char* quotedBool(bool val) {
+  return val ? "\"true\"" : "\"false\"";
+}
+
+/*
+ * Returns a quoted string representing the access flags.
+ */
+static const char* quotedVisibility(u4 accessFlags) {
+  if (accessFlags & kAccPublic) {
+    return "\"public\"";
+  } else if (accessFlags & kAccProtected) {
+    return "\"protected\"";
+  } else if (accessFlags & kAccPrivate) {
+    return "\"private\"";
+  } else {
+    return "\"package\"";
+  }
+}
+
+/*
+ * Counts the number of '1' bits in a word.
+ */
+static int countOnes(u4 val) {
+  val = val - ((val >> 1) & 0x55555555);
+  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+  return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+}
+
+/*
+ * Creates a new string with human-readable access flags.
+ *
+ * In the base language the access_flags fields are type u2; in Dalvik
+ * they're u4.
+ */
+static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
+  static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
+    {
+      "PUBLIC",                /* 0x00001 */
+      "PRIVATE",               /* 0x00002 */
+      "PROTECTED",             /* 0x00004 */
+      "STATIC",                /* 0x00008 */
+      "FINAL",                 /* 0x00010 */
+      "?",                     /* 0x00020 */
+      "?",                     /* 0x00040 */
+      "?",                     /* 0x00080 */
+      "?",                     /* 0x00100 */
+      "INTERFACE",             /* 0x00200 */
+      "ABSTRACT",              /* 0x00400 */
+      "?",                     /* 0x00800 */
+      "SYNTHETIC",             /* 0x01000 */
+      "ANNOTATION",            /* 0x02000 */
+      "ENUM",                  /* 0x04000 */
+      "?",                     /* 0x08000 */
+      "VERIFIED",              /* 0x10000 */
+      "OPTIMIZED",             /* 0x20000 */
+    }, {
+      "PUBLIC",                /* 0x00001 */
+      "PRIVATE",               /* 0x00002 */
+      "PROTECTED",             /* 0x00004 */
+      "STATIC",                /* 0x00008 */
+      "FINAL",                 /* 0x00010 */
+      "SYNCHRONIZED",          /* 0x00020 */
+      "BRIDGE",                /* 0x00040 */
+      "VARARGS",               /* 0x00080 */
+      "NATIVE",                /* 0x00100 */
+      "?",                     /* 0x00200 */
+      "ABSTRACT",              /* 0x00400 */
+      "STRICT",                /* 0x00800 */
+      "SYNTHETIC",             /* 0x01000 */
+      "?",                     /* 0x02000 */
+      "?",                     /* 0x04000 */
+      "MIRANDA",               /* 0x08000 */
+      "CONSTRUCTOR",           /* 0x10000 */
+      "DECLARED_SYNCHRONIZED", /* 0x20000 */
+    }, {
+      "PUBLIC",                /* 0x00001 */
+      "PRIVATE",               /* 0x00002 */
+      "PROTECTED",             /* 0x00004 */
+      "STATIC",                /* 0x00008 */
+      "FINAL",                 /* 0x00010 */
+      "?",                     /* 0x00020 */
+      "VOLATILE",              /* 0x00040 */
+      "TRANSIENT",             /* 0x00080 */
+      "?",                     /* 0x00100 */
+      "?",                     /* 0x00200 */
+      "?",                     /* 0x00400 */
+      "?",                     /* 0x00800 */
+      "SYNTHETIC",             /* 0x01000 */
+      "?",                     /* 0x02000 */
+      "ENUM",                  /* 0x04000 */
+      "?",                     /* 0x08000 */
+      "?",                     /* 0x10000 */
+      "?",                     /* 0x20000 */
+    },
+  };
+
+  // Allocate enough storage to hold the expected number of strings,
+  // plus a space between each.  We over-allocate, using the longest
+  // string above as the base metric.
+  const int kLongest = 21;  // The strlen of longest string above.
+  const int count = countOnes(flags);
+  char* str;
+  char* cp;
+  cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
+
+  for (int i = 0; i < kNumFlags; i++) {
+    if (flags & 0x01) {
+      const char* accessStr = kAccessStrings[forWhat][i];
+      const int len = strlen(accessStr);
+      if (cp != str) {
+        *cp++ = ' ';
+      }
+      memcpy(cp, accessStr, len);
+      cp += len;
+    }
+    flags >>= 1;
+  }  // for
+
+  *cp = '\0';
+  return str;
+}
+
+/*
+ * Copies character data from "data" to "out", converting non-ASCII values
+ * to fprintf format chars or an ASCII filler ('.' or '?').
+ *
+ * The output buffer must be able to hold (2*len)+1 bytes.  The result is
+ * NULL-terminated.
+ */
+static void asciify(char* out, const unsigned char* data, size_t len) {
+  while (len--) {
+    if (*data < 0x20) {
+      // Could do more here, but we don't need them yet.
+      switch (*data) {
+        case '\0':
+          *out++ = '\\';
+          *out++ = '0';
+          break;
+        case '\n':
+          *out++ = '\\';
+          *out++ = 'n';
+          break;
+        default:
+          *out++ = '.';
+          break;
+      }  // switch
+    } else if (*data >= 0x80) {
+      *out++ = '?';
+    } else {
+      *out++ = *data;
+    }
+    data++;
+  }  // while
+  *out = '\0';
+}
+
+/*
+ * Dumps the file header.
+ *
+ * Note that some of the : are misaligned on purpose to preserve
+ * the exact output of the original Dalvik dexdump.
+ */
+static void dumpFileHeader(const DexFile* pDexFile) {
+  const DexFile::Header& pHeader = pDexFile->GetHeader();
+  char sanitized[sizeof(pHeader.magic_) * 2 + 1];
+  fprintf(gOutFile, "DEX file header:\n");
+  asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_));
+  fprintf(gOutFile, "magic               : '%s'\n", sanitized);
+  fprintf(gOutFile, "checksum            : %08x\n", pHeader.checksum_);
+  fprintf(gOutFile, "signature           : %02x%02x...%02x%02x\n",
+          pHeader.signature_[0], pHeader.signature_[1],
+          pHeader.signature_[DexFile::kSha1DigestSize - 2],
+          pHeader.signature_[DexFile::kSha1DigestSize - 1]);
+  fprintf(gOutFile, "file_size           : %d\n", pHeader.file_size_);
+  fprintf(gOutFile, "header_size         : %d\n", pHeader.header_size_);
+  fprintf(gOutFile, "link_size           : %d\n", pHeader.link_size_);
+  fprintf(gOutFile, "link_off            : %d (0x%06x)\n",
+          pHeader.link_off_, pHeader.link_off_);
+  fprintf(gOutFile, "string_ids_size     : %d\n", pHeader.string_ids_size_);
+  fprintf(gOutFile, "string_ids_off      : %d (0x%06x)\n",
+          pHeader.string_ids_off_, pHeader.string_ids_off_);
+  fprintf(gOutFile, "type_ids_size       : %d\n", pHeader.type_ids_size_);
+  fprintf(gOutFile, "type_ids_off        : %d (0x%06x)\n",
+          pHeader.type_ids_off_, pHeader.type_ids_off_);
+  fprintf(gOutFile, "proto_ids_size       : %d\n", pHeader.proto_ids_size_);
+  fprintf(gOutFile, "proto_ids_off        : %d (0x%06x)\n",
+          pHeader.proto_ids_off_, pHeader.proto_ids_off_);
+  fprintf(gOutFile, "field_ids_size      : %d\n", pHeader.field_ids_size_);
+  fprintf(gOutFile, "field_ids_off       : %d (0x%06x)\n",
+          pHeader.field_ids_off_, pHeader.field_ids_off_);
+  fprintf(gOutFile, "method_ids_size     : %d\n", pHeader.method_ids_size_);
+  fprintf(gOutFile, "method_ids_off      : %d (0x%06x)\n",
+          pHeader.method_ids_off_, pHeader.method_ids_off_);
+  fprintf(gOutFile, "class_defs_size     : %d\n", pHeader.class_defs_size_);
+  fprintf(gOutFile, "class_defs_off      : %d (0x%06x)\n",
+          pHeader.class_defs_off_, pHeader.class_defs_off_);
+  fprintf(gOutFile, "data_size           : %d\n", pHeader.data_size_);
+  fprintf(gOutFile, "data_off            : %d (0x%06x)\n\n",
+          pHeader.data_off_, pHeader.data_off_);
+}
+
+/*
+ * Dumps a class_def_item.
+ */
+static void dumpClassDef(const DexFile* pDexFile, int idx) {
+  // General class information.
+  const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
+  fprintf(gOutFile, "Class #%d header:\n", idx);
+  fprintf(gOutFile, "class_idx           : %d\n", pClassDef.class_idx_);
+  fprintf(gOutFile, "access_flags        : %d (0x%04x)\n",
+          pClassDef.access_flags_, pClassDef.access_flags_);
+  fprintf(gOutFile, "superclass_idx      : %d\n", pClassDef.superclass_idx_);
+  fprintf(gOutFile, "interfaces_off      : %d (0x%06x)\n",
+          pClassDef.interfaces_off_, pClassDef.interfaces_off_);
+  fprintf(gOutFile, "source_file_idx     : %d\n", pClassDef.source_file_idx_);
+  fprintf(gOutFile, "annotations_off     : %d (0x%06x)\n",
+          pClassDef.annotations_off_, pClassDef.annotations_off_);
+  fprintf(gOutFile, "class_data_off      : %d (0x%06x)\n",
+          pClassDef.class_data_off_, pClassDef.class_data_off_);
+
+  // Fields and methods.
+  const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
+  if (pEncodedData != nullptr) {
+    ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
+    fprintf(gOutFile, "static_fields_size  : %d\n", pClassData.NumStaticFields());
+    fprintf(gOutFile, "instance_fields_size: %d\n", pClassData.NumInstanceFields());
+    fprintf(gOutFile, "direct_methods_size : %d\n", pClassData.NumDirectMethods());
+    fprintf(gOutFile, "virtual_methods_size: %d\n", pClassData.NumVirtualMethods());
+  } else {
+    fprintf(gOutFile, "static_fields_size  : 0\n");
+    fprintf(gOutFile, "instance_fields_size: 0\n");
+    fprintf(gOutFile, "direct_methods_size : 0\n");
+    fprintf(gOutFile, "virtual_methods_size: 0\n");
+  }
+  fprintf(gOutFile, "\n");
+}
+
+/*
+ * Dumps an interface that a class declares to implement.
+ */
+static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTypeItem, int i) {
+  const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_);
+  if (gOptions.outputFormat == OUTPUT_PLAIN) {
+    fprintf(gOutFile, "    #%d              : '%s'\n", i, interfaceName);
+  } else {
+    char* dotted = descriptorToDot(interfaceName);
+    fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dotted);
+    free(dotted);
+  }
+}
+
+/*
+ * Dumps the catches table associated with the code.
+ */
+static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) {
+  const u4 triesSize = pCode->tries_size_;
+
+  // No catch table.
+  if (triesSize == 0) {
+    fprintf(gOutFile, "      catches       : (none)\n");
+    return;
+  }
+
+  // Dump all table entries.
+  fprintf(gOutFile, "      catches       : %d\n", triesSize);
+  for (u4 i = 0; i < triesSize; i++) {
+    const DexFile::TryItem* pTry = pDexFile->GetTryItems(*pCode, i);
+    const u4 start = pTry->start_addr_;
+    const u4 end = start + pTry->insn_count_;
+    fprintf(gOutFile, "        0x%04x - 0x%04x\n", start, end);
+    for (CatchHandlerIterator it(*pCode, *pTry); it.HasNext(); it.Next()) {
+      const u2 tidx = it.GetHandlerTypeIndex();
+      const char* descriptor =
+          (tidx == DexFile::kDexNoIndex16) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
+      fprintf(gOutFile, "          %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
+    }  // for
+  }  // for
+}
+
+/*
+ * Callback for dumping each positions table entry.
+ */
+static bool dumpPositionsCb(void* /*context*/, u4 address, u4 lineNum) {
+  fprintf(gOutFile, "        0x%04x line=%d\n", address, lineNum);
+  return false;
+}
+
+/*
+ * Callback for dumping locals table entry.
+ */
+static void dumpLocalsCb(void* /*context*/, u2 slot, u4 startAddress, u4 endAddress,
+                         const char* name, const char* descriptor, const char* signature) {
+  fprintf(gOutFile, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
+          startAddress, endAddress, slot, name, descriptor, signature);
+}
+
+/*
+ * Helper for dumpInstruction(), which builds the string
+ * representation for the index in the given instruction. This will
+ * first try to use the given buffer, but if the result won't fit,
+ * then this will allocate a new buffer to hold the result. A pointer
+ * to the buffer which holds the full result is always returned, and
+ * this can be compared with the one passed in, to see if the result
+ * needs to be free()d.
+ */
+static char* indexString(const DexFile* pDexFile,
+                         const Instruction* pDecInsn, char* buf, size_t bufSize) {
+  // Determine index and width of the string.
+  u4 index = 0;
+  u4 width = 4;
+  switch (Instruction::FormatOf(pDecInsn->Opcode())) {
+    // SOME NOT SUPPORTED:
+    // case Instruction::k20bc:
+    case Instruction::k21c:
+    case Instruction::k35c:
+    // case Instruction::k35ms:
+    case Instruction::k3rc:
+    // case Instruction::k3rms:
+    // case Instruction::k35mi:
+    // case Instruction::k3rmi:
+      index = pDecInsn->VRegB();
+      width = 4;
+      break;
+    case Instruction::k31c:
+      index = pDecInsn->VRegB();
+      width = 8;
+      break;
+    case Instruction::k22c:
+    // case Instruction::k22cs:
+      index = pDecInsn->VRegC();
+      width = 4;
+      break;
+    default:
+      break;
+  }  // switch
+
+  // Determine index type.
+  size_t outSize = 0;
+  switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
+    case Instruction::kIndexUnknown:
+      // This function should never get called for this type, but do
+      // something sensible here, just to help with debugging.
+      outSize = snprintf(buf, bufSize, "<unknown-index>");
+      break;
+    case Instruction::kIndexNone:
+      // This function should never get called for this type, but do
+      // something sensible here, just to help with debugging.
+      outSize = snprintf(buf, bufSize, "<no-index>");
+      break;
+    case Instruction::kIndexTypeRef:
+      if (index < pDexFile->GetHeader().type_ids_size_) {
+        const char* tp = pDexFile->StringByTypeIdx(index);
+        outSize = snprintf(buf, bufSize, "%s // type@%0*x", tp, width, index);
+      } else {
+        outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
+      }
+      break;
+    case Instruction::kIndexStringRef:
+      if (index < pDexFile->GetHeader().string_ids_size_) {
+        const char* st = pDexFile->StringDataByIdx(index);
+        outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x", st, width, index);
+      } else {
+        outSize = snprintf(buf, bufSize, "<string?> // string@%0*x", width, index);
+      }
+      break;
+    case Instruction::kIndexMethodRef:
+      if (index < pDexFile->GetHeader().method_ids_size_) {
+        const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
+        const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+        const Signature signature = pDexFile->GetMethodSignature(pMethodId);
+        const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
+        outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
+                           backDescriptor, name, signature.ToString().c_str(), width, index);
+      } else {
+        outSize = snprintf(buf, bufSize, "<method?> // method@%0*x", width, index);
+      }
+      break;
+    case Instruction::kIndexFieldRef:
+      if (index < pDexFile->GetHeader().field_ids_size_) {
+        const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(index);
+        const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
+        const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
+        const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
+        outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
+                           backDescriptor, name, typeDescriptor, width, index);
+      } else {
+        outSize = snprintf(buf, bufSize, "<field?> // field@%0*x", width, index);
+      }
+      break;
+    case Instruction::kIndexVtableOffset:
+      outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
+                         width, index, width, index);
+      break;
+    case Instruction::kIndexFieldOffset:
+      outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
+      break;
+    // SOME NOT SUPPORTED:
+    // case Instruction::kIndexVaries:
+    // case Instruction::kIndexInlineMethod:
+    default:
+      outSize = snprintf(buf, bufSize, "<?>");
+      break;
+  }  // switch
+
+  // Determine success of string construction.
+  if (outSize >= bufSize) {
+    // The buffer wasn't big enough; allocate and retry. Note:
+    // snprintf() doesn't count the '\0' as part of its returned
+    // size, so we add explicit space for it here.
+    outSize++;
+    buf = reinterpret_cast<char*>(malloc(outSize));
+    if (buf == nullptr) {
+      return nullptr;
+    }
+    return indexString(pDexFile, pDecInsn, buf, outSize);
+  }
+  return buf;
+}
+
+/*
+ * Dumps a single instruction.
+ */
+static void dumpInstruction(const DexFile* pDexFile,
+                            const DexFile::CodeItem* pCode,
+                            u4 codeOffset, u4 insnIdx, u4 insnWidth,
+                            const Instruction* pDecInsn) {
+  // Address of instruction (expressed as byte offset).
+  fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
+
+  // Dump (part of) raw bytes.
+  const u2* insns = pCode->insns_;
+  for (u4 i = 0; i < 8; i++) {
+    if (i < insnWidth) {
+      if (i == 7) {
+        fprintf(gOutFile, " ... ");
+      } else {
+        // Print 16-bit value in little-endian order.
+        const u1* bytePtr = (const u1*) &insns[insnIdx + i];
+        fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
+      }
+    } else {
+      fputs("     ", gOutFile);
+    }
+  }  // for
+
+  // Dump pseudo-instruction or opcode.
+  if (pDecInsn->Opcode() == Instruction::NOP) {
+    const u2 instr = get2LE((const u1*) &insns[insnIdx]);
+    if (instr == Instruction::kPackedSwitchSignature) {
+      fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
+    } else if (instr == Instruction::kSparseSwitchSignature) {
+      fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
+    } else if (instr == Instruction::kArrayDataSignature) {
+      fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
+    } else {
+      fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
+    }
+  } else {
+    fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
+  }
+
+  // Set up additional argument.
+  char indexBufChars[200];
+  char *indexBuf = indexBufChars;
+  if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
+    indexBuf = indexString(pDexFile, pDecInsn,
+                           indexBufChars, sizeof(indexBufChars));
+  }
+
+  // Dump the instruction.
+  //
+  // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
+  //
+  switch (Instruction::FormatOf(pDecInsn->Opcode())) {
+    case Instruction::k10x:        // op
+      break;
+    case Instruction::k12x:        // op vA, vB
+      fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
+      break;
+    case Instruction::k11n:        // op vA, #+B
+      fprintf(gOutFile, " v%d, #int %d // #%x",
+              pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
+      break;
+    case Instruction::k11x:        // op vAA
+      fprintf(gOutFile, " v%d", pDecInsn->VRegA());
+      break;
+    case Instruction::k10t:        // op +AA
+    case Instruction::k20t:        // op +AAAA
+      {
+        const s4 targ = (s4) pDecInsn->VRegA();
+        fprintf(gOutFile, " %04x // %c%04x",
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+      }
+      break;
+    case Instruction::k22x:        // op vAA, vBBBB
+      fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
+      break;
+    case Instruction::k21t:        // op vAA, +BBBB
+      {
+        const s4 targ = (s4) pDecInsn->VRegB();
+        fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+      }
+      break;
+    case Instruction::k21s:        // op vAA, #+BBBB
+      fprintf(gOutFile, " v%d, #int %d // #%x",
+              pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
+      break;
+    case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
+      // The printed format varies a bit based on the actual opcode.
+      if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
+        const s4 value = pDecInsn->VRegB() << 16;
+        fprintf(gOutFile, " v%d, #int %d // #%x",
+                pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
+      } else {
+        const s8 value = ((s8) pDecInsn->VRegB()) << 48;
+        fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
+                pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
+      }
+      break;
+    case Instruction::k21c:        // op vAA, thing@BBBB
+    case Instruction::k31c:        // op vAA, thing@BBBBBBBB
+      fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf);
+      break;
+    case Instruction::k23x:        // op vAA, vBB, vCC
+      fprintf(gOutFile, " v%d, v%d, v%d",
+              pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
+      break;
+    case Instruction::k22b:        // op vAA, vBB, #+CC
+      fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
+              pDecInsn->VRegA(), pDecInsn->VRegB(),
+              (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
+      break;
+    case Instruction::k22t:        // op vA, vB, +CCCC
+      {
+        const s4 targ = (s4) pDecInsn->VRegC();
+        fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
+                pDecInsn->VRegA(), pDecInsn->VRegB(),
+                insnIdx + targ,
+                (targ < 0) ? '-' : '+',
+                (targ < 0) ? -targ : targ);
+      }
+      break;
+    case Instruction::k22s:        // op vA, vB, #+CCCC
+      fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
+              pDecInsn->VRegA(), pDecInsn->VRegB(),
+              (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
+      break;
+    case Instruction::k22c:        // op vA, vB, thing@CCCC
+    // NOT SUPPORTED:
+    // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
+      fprintf(gOutFile, " v%d, v%d, %s",
+              pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf);
+      break;
+    case Instruction::k30t:
+      fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
+      break;
+    case Instruction::k31i:        // op vAA, #+BBBBBBBB
+      {
+        // This is often, but not always, a float.
+        union {
+          float f;
+          u4 i;
+        } conv;
+        conv.i = pDecInsn->VRegB();
+        fprintf(gOutFile, " v%d, #float %f // #%08x",
+                pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
+      }
+      break;
+    case Instruction::k31t:       // op vAA, offset +BBBBBBBB
+      fprintf(gOutFile, " v%d, %08x // +%08x",
+              pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
+      break;
+    case Instruction::k32x:        // op vAAAA, vBBBB
+      fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
+      break;
+    case Instruction::k35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB
+    // NOT SUPPORTED:
+    // case Instruction::k35ms:       // [opt] invoke-virtual+super
+    // case Instruction::k35mi:       // [opt] inline invoke
+      {
+        u4 arg[5];
+        pDecInsn->GetVarArgs(arg);
+        fputs(" {", gOutFile);
+        for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
+          if (i == 0) {
+            fprintf(gOutFile, "v%d", arg[i]);
+          } else {
+            fprintf(gOutFile, ", v%d", arg[i]);
+          }
+        }  // for
+        fprintf(gOutFile, "}, %s", indexBuf);
+      }
+      break;
+    case Instruction::k3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
+    // NOT SUPPORTED:
+    // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
+    // case Instruction::k3rmi:       // [opt] execute-inline/range
+      {
+        // This doesn't match the "dx" output when some of the args are
+        // 64-bit values -- dx only shows the first register.
+        fputs(" {", gOutFile);
+        for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
+          if (i == 0) {
+            fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
+          } else {
+            fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
+          }
+        }  // for
+        fprintf(gOutFile, "}, %s", indexBuf);
+      }
+      break;
+    case Instruction::k51l:        // op vAA, #+BBBBBBBBBBBBBBBB
+      {
+        // This is often, but not always, a double.
+        union {
+          double d;
+          u8 j;
+        } conv;
+        conv.j = pDecInsn->WideVRegB();
+        fprintf(gOutFile, " v%d, #double %f // #%016" PRIx64,
+                pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
+      }
+      break;
+    // NOT SUPPORTED:
+    // case Instruction::k00x:        // unknown op or breakpoint
+    //    break;
+    default:
+      fprintf(gOutFile, " ???");
+      break;
+  }  // switch
+
+  fputc('\n', gOutFile);
+
+  if (indexBuf != indexBufChars) {
+    free(indexBuf);
+  }
+}
+
+/*
+ * Dumps a bytecode disassembly.
+ */
+static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
+                          const DexFile::CodeItem* pCode, u4 codeOffset) {
+  const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
+  const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+  const Signature signature = pDexFile->GetMethodSignature(pMethodId);
+  const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
+
+  // Generate header.
+  char* tmp = descriptorToDot(backDescriptor);
+  fprintf(gOutFile, "%06x:                                        "
+          "|[%06x] %s.%s:%s\n",
+          codeOffset, codeOffset, tmp, name, signature.ToString().c_str());
+  free(tmp);
+
+  // Iterate over all instructions.
+  const u2* insns = pCode->insns_;
+  for (u4 insnIdx = 0; insnIdx < pCode->insns_size_in_code_units_;) {
+    const Instruction* instruction = Instruction::At(&insns[insnIdx]);
+    const u4 insnWidth = instruction->SizeInCodeUnits();
+    if (insnWidth == 0) {
+      fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
+      break;
+    }
+    dumpInstruction(pDexFile, pCode, codeOffset, insnIdx, insnWidth, instruction);
+    insnIdx += insnWidth;
+  }  // for
+}
+
+/*
+ * Dumps code of a method.
+ */
+static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
+                     const DexFile::CodeItem* pCode, u4 codeOffset) {
+  fprintf(gOutFile, "      registers     : %d\n", pCode->registers_size_);
+  fprintf(gOutFile, "      ins           : %d\n", pCode->ins_size_);
+  fprintf(gOutFile, "      outs          : %d\n", pCode->outs_size_);
+  fprintf(gOutFile, "      insns size    : %d 16-bit code units\n",
+          pCode->insns_size_in_code_units_);
+
+  // Bytecode disassembly, if requested.
+  if (gOptions.disassemble) {
+    dumpBytecodes(pDexFile, idx, pCode, codeOffset);
+  }
+
+  // Try-catch blocks.
+  dumpCatches(pDexFile, pCode);
+
+  // Positions and locals table in the debug info.
+  bool is_static = (flags & kAccStatic) != 0;
+  fprintf(gOutFile, "      positions     : \n");
+  pDexFile->DecodeDebugInfo(
+      pCode, is_static, idx, dumpPositionsCb, nullptr, nullptr);
+  fprintf(gOutFile, "      locals        : \n");
+  pDexFile->DecodeDebugInfo(
+      pCode, is_static, idx, nullptr, dumpLocalsCb, nullptr);
+}
+
+/*
+ * Dumps a method.
+ */
+static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags,
+                       const DexFile::CodeItem* pCode, u4 codeOffset, int i) {
+  // Bail for anything private if export only requested.
+  if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
+    return;
+  }
+
+  const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
+  const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+  const Signature signature = pDexFile->GetMethodSignature(pMethodId);
+  char* typeDescriptor = strdup(signature.ToString().c_str());
+  const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
+  char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
+
+  if (gOptions.outputFormat == OUTPUT_PLAIN) {
+    fprintf(gOutFile, "    #%d              : (in %s)\n", i, backDescriptor);
+    fprintf(gOutFile, "      name          : '%s'\n", name);
+    fprintf(gOutFile, "      type          : '%s'\n", typeDescriptor);
+    fprintf(gOutFile, "      access        : 0x%04x (%s)\n", flags, accessStr);
+    if (pCode == nullptr) {
+      fprintf(gOutFile, "      code          : (none)\n");
+    } else {
+      fprintf(gOutFile, "      code          -\n");
+      dumpCode(pDexFile, idx, flags, pCode, codeOffset);
+    }
+    if (gOptions.disassemble) {
+      fputc('\n', gOutFile);
+    }
+  } else if (gOptions.outputFormat == OUTPUT_XML) {
+    const bool constructor = (name[0] == '<');
+
+    // Method name and prototype.
+    if (constructor) {
+      char* tmp = descriptorClassToDot(backDescriptor);
+      fprintf(gOutFile, "<constructor name=\"%s\"\n", tmp);
+      free(tmp);
+      tmp = descriptorToDot(backDescriptor);
+      fprintf(gOutFile, " type=\"%s\"\n", tmp);
+      free(tmp);
+    } else {
+      fprintf(gOutFile, "<method name=\"%s\"\n", name);
+      const char* returnType = strrchr(typeDescriptor, ')');
+      if (returnType == nullptr) {
+        fprintf(stderr, "bad method type descriptor '%s'\n", typeDescriptor);
+        goto bail;
+      }
+      char* tmp = descriptorToDot(returnType+1);
+      fprintf(gOutFile, " return=\"%s\"\n", tmp);
+      free(tmp);
+      fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
+      fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
+      fprintf(gOutFile, " synchronized=%s\n", quotedBool(
+          (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
+    }
+
+    // Additional method flags.
+    fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
+    fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
+    // The "deprecated=" not knowable w/o parsing annotations.
+    fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
+
+    // Parameters.
+    if (typeDescriptor[0] != '(') {
+      fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
+      goto bail;
+    }
+    char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
+    const char* base = typeDescriptor + 1;
+    int argNum = 0;
+    while (*base != ')') {
+      char* cp = tmpBuf;
+      while (*base == '[') {
+        *cp++ = *base++;
+      }
+      if (*base == 'L') {
+        // Copy through ';'.
+        do {
+          *cp = *base++;
+        } while (*cp++ != ';');
+      } else {
+        // Primitive char, copy it.
+        if (strchr("ZBCSIFJD", *base) == NULL) {
+          fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
+          goto bail;
+        }
+        *cp++ = *base++;
+      }
+      // Null terminate and display.
+      *cp++ = '\0';
+      char* tmp = descriptorToDot(tmpBuf);
+      fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
+                        "</parameter>\n", argNum++, tmp);
+      free(tmp);
+    }  // while
+    free(tmpBuf);
+    if (constructor) {
+      fprintf(gOutFile, "</constructor>\n");
+    } else {
+      fprintf(gOutFile, "</method>\n");
+    }
+  }
+
+ bail:
+  free(typeDescriptor);
+  free(accessStr);
+}
+
+/*
+ * Dumps a static (class) field.
+ */
+static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) {
+  // Bail for anything private if export only requested.
+  if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
+    return;
+  }
+
+  const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(idx);
+  const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
+  const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
+  const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
+  char* accessStr = createAccessFlagStr(flags, kAccessForField);
+
+  if (gOptions.outputFormat == OUTPUT_PLAIN) {
+    fprintf(gOutFile, "    #%d              : (in %s)\n", i, backDescriptor);
+    fprintf(gOutFile, "      name          : '%s'\n", name);
+    fprintf(gOutFile, "      type          : '%s'\n", typeDescriptor);
+    fprintf(gOutFile, "      access        : 0x%04x (%s)\n", flags, accessStr);
+  } else if (gOptions.outputFormat == OUTPUT_XML) {
+    fprintf(gOutFile, "<field name=\"%s\"\n", name);
+    char *tmp = descriptorToDot(typeDescriptor);
+    fprintf(gOutFile, " type=\"%s\"\n", tmp);
+    free(tmp);
+    fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
+    fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
+    // The "value=" is not knowable w/o parsing annotations.
+    fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
+    fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
+    // The "deprecated=" is not knowable w/o parsing annotations.
+    fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
+    fprintf(gOutFile, ">\n</field>\n");
+  }
+
+  free(accessStr);
+}
+
+/*
+ * Dumps an instance field.
+ */
+static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) {
+  dumpSField(pDexFile, idx, flags, i);
+}
+
+/*
+ * Dumps the class.
+ *
+ * Note "idx" is a DexClassDef index, not a DexTypeId index.
+ *
+ * If "*pLastPackage" is nullptr or does not match the current class' package,
+ * the value will be replaced with a newly-allocated string.
+ */
+static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
+  const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
+
+  // Omitting non-public class.
+  if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
+    return;
+  }
+
+  // For the XML output, show the package name.  Ideally we'd gather
+  // up the classes, sort them, and dump them alphabetically so the
+  // package name wouldn't jump around, but that's not a great plan
+  // for something that needs to run on the device.
+  const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
+  if (!(classDescriptor[0] == 'L' &&
+        classDescriptor[strlen(classDescriptor)-1] == ';')) {
+    // Arrays and primitives should not be defined explicitly. Keep going?
+    fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
+  } else if (gOptions.outputFormat == OUTPUT_XML) {
+    char* mangle = strdup(classDescriptor + 1);
+    mangle[strlen(mangle)-1] = '\0';
+
+    // Reduce to just the package name.
+    char* lastSlash = strrchr(mangle, '/');
+    if (lastSlash != nullptr) {
+      *lastSlash = '\0';
+    } else {
+      *mangle = '\0';
+    }
+
+    for (char* cp = mangle; *cp != '\0'; cp++) {
+      if (*cp == '/') {
+        *cp = '.';
+      }
+    }  // for
+
+    if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
+      // Start of a new package.
+      if (*pLastPackage != nullptr) {
+        fprintf(gOutFile, "</package>\n");
+      }
+      fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
+      free(*pLastPackage);
+      *pLastPackage = mangle;
+    } else {
+      free(mangle);
+    }
+  }
+
+  // General class information.
+  char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
+  const char* superclassDescriptor;
+  if (pClassDef.superclass_idx_ == DexFile::kDexNoIndex16) {
+    superclassDescriptor = nullptr;
+  } else {
+    superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
+  }
+  if (gOptions.outputFormat == OUTPUT_PLAIN) {
+    fprintf(gOutFile, "Class #%d            -\n", idx);
+    fprintf(gOutFile, "  Class descriptor  : '%s'\n", classDescriptor);
+    fprintf(gOutFile, "  Access flags      : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
+    if (superclassDescriptor != nullptr) {
+      fprintf(gOutFile, "  Superclass        : '%s'\n", superclassDescriptor);
+    }
+    fprintf(gOutFile, "  Interfaces        -\n");
+  } else {
+    char* tmp = descriptorClassToDot(classDescriptor);
+    fprintf(gOutFile, "<class name=\"%s\"\n", tmp);
+    free(tmp);
+    if (superclassDescriptor != nullptr) {
+      tmp = descriptorToDot(superclassDescriptor);
+      fprintf(gOutFile, " extends=\"%s\"\n", tmp);
+      free(tmp);
+    }
+    fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
+    fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
+    fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
+    // The "deprecated=" not knowable w/o parsing annotations.
+    fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
+    fprintf(gOutFile, ">\n");
+  }
+
+  // Interfaces.
+  const DexFile::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
+  if (pInterfaces != nullptr) {
+    for (u4 i = 0; i < pInterfaces->Size(); i++) {
+      dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
+    }  // for
+  }
+
+  // Fields and methods.
+  const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
+  if (pEncodedData == nullptr) {
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+      fprintf(gOutFile, "  Static fields     -\n");
+      fprintf(gOutFile, "  Instance fields   -\n");
+      fprintf(gOutFile, "  Direct methods    -\n");
+      fprintf(gOutFile, "  Virtual methods   -\n");
+    }
+  } else {
+    ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+      fprintf(gOutFile, "  Static fields     -\n");
+    }
+    for (int i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) {
+      dumpSField(pDexFile, pClassData.GetMemberIndex(),
+                           pClassData.GetRawMemberAccessFlags(), i);
+    }  // for
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+      fprintf(gOutFile, "  Instance fields   -\n");
+    }
+    for (int i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) {
+      dumpIField(pDexFile, pClassData.GetMemberIndex(),
+                          pClassData.GetRawMemberAccessFlags(), i);
+    }  // for
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+      fprintf(gOutFile, "  Direct methods    -\n");
+    }
+    for (int i = 0; pClassData.HasNextDirectMethod(); i++, pClassData.Next()) {
+      dumpMethod(pDexFile, pClassData.GetMemberIndex(),
+                           pClassData.GetRawMemberAccessFlags(),
+                           pClassData.GetMethodCodeItem(),
+                           pClassData.GetMethodCodeItemOffset(), i);
+    }  // for
+    if (gOptions.outputFormat == OUTPUT_PLAIN) {
+      fprintf(gOutFile, "  Virtual methods   -\n");
+    }
+    for (int i = 0; pClassData.HasNextVirtualMethod(); i++, pClassData.Next()) {
+      dumpMethod(pDexFile, pClassData.GetMemberIndex(),
+                           pClassData.GetRawMemberAccessFlags(),
+                           pClassData.GetMethodCodeItem(),
+                           pClassData.GetMethodCodeItemOffset(), i);
+    }  // for
+  }
+
+  // End of class.
+  if (gOptions.outputFormat == OUTPUT_PLAIN) {
+    const char* fileName;
+    if (pClassDef.source_file_idx_ != DexFile::kDexNoIndex) {
+      fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
+    } else {
+      fileName = "unknown";
+    }
+    fprintf(gOutFile, "  source_file_idx   : %d (%s)\n\n",
+            pClassDef.source_file_idx_, fileName);
+  } else if (gOptions.outputFormat == OUTPUT_XML) {
+    fprintf(gOutFile, "</class>\n");
+  }
+
+  free(accessStr);
+}
+
+/*
+ * Dumps the requested sections of the file.
+ */
+static void processDexFile(const char* fileName, const DexFile* pDexFile) {
+  if (gOptions.verbose) {
+    fprintf(gOutFile, "Opened '%s', DEX version '%.3s'\n",
+            fileName, pDexFile->GetHeader().magic_ + 4);
+  }
+
+  // Headers.
+  if (gOptions.showFileHeaders) {
+    dumpFileHeader(pDexFile);
+  }
+
+  // Open XML context.
+  if (gOptions.outputFormat == OUTPUT_XML) {
+    fprintf(gOutFile, "<api>\n");
+  }
+
+  // Iterate over all classes.
+  char* package = nullptr;
+  const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
+  for (u4 i = 0; i < classDefsSize; i++) {
+    if (gOptions.showSectionHeaders) {
+      dumpClassDef(pDexFile, i);
+    }
+    dumpClass(pDexFile, i, &package);
+  }  // for
+
+  // Free the last package allocated.
+  if (package != nullptr) {
+    fprintf(gOutFile, "</package>\n");
+    free(package);
+  }
+
+  // Close XML context.
+  if (gOptions.outputFormat == OUTPUT_XML) {
+    fprintf(gOutFile, "</api>\n");
+  }
+}
+
+/*
+ * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
+ */
+int processFile(const char* fileName) {
+  if (gOptions.verbose) {
+    fprintf(gOutFile, "Processing '%s'...\n", fileName);
+  }
+
+  // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
+  // all of which are Zip archives with "classes.dex" inside. The compressed
+  // data needs to be extracted to a temp file, the location of which varies.
+  //
+  // TODO(ajcbik): fix following issues
+  //
+  // (1) gOptions.tempFileName is not accounted for
+  // (2) gOptions.ignoreBadChecksum is not accounted for
+  //
+  std::string error_msg;
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  if (!DexFile::Open(fileName, fileName, &error_msg, &dex_files)) {
+    // Display returned error message to user. Note that this error behavior
+    // differs from the error messages shown by the original Dalvik dexdump.
+    fputs(error_msg.c_str(), stderr);
+    fputc('\n', stderr);
+    return -1;
+  }
+
+  // Success. Either report checksum verification or process
+  // all dex files found in given file.
+  if (gOptions.checksumOnly) {
+    fprintf(gOutFile, "Checksum verified\n");
+  } else {
+    for (size_t i = 0; i < dex_files.size(); i++) {
+      processDexFile(fileName, dex_files[i].get());
+    }
+  }
+  return 0;
+}
+
+}  // namespace art
diff --git a/dexdump/dexdump.h b/dexdump/dexdump.h
new file mode 100644
index 0000000..f2cd16a
--- /dev/null
+++ b/dexdump/dexdump.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ * Header file of the dexdump utility.
+ *
+ * This is a re-implementation of the original dexdump utility that was
+ * based on Dalvik functions in libdex into a new dexdump that is now
+ * based on Art functions in libart instead. The output is identical to
+ * the original for correct DEX files. Error messages may differ, however.
+ * Also, ODEX files are no longer supported.
+ */
+
+#ifndef ART_DEXDUMP_DEXDUMP_H_
+#define ART_DEXDUMP_DEXDUMP_H_
+
+#include <stdint.h>
+#include <stdio.h>
+
+namespace art {
+
+/* Supported output formats. */
+enum OutputFormat {
+  OUTPUT_PLAIN = 0,  // default
+  OUTPUT_XML,        // XML-style
+};
+
+/* Command-line options. */
+struct Options {
+  bool checksumOnly;
+  bool disassemble;
+  bool exportsOnly;
+  bool ignoreBadChecksum;
+  bool showFileHeaders;
+  bool showSectionHeaders;
+  bool verbose;
+  OutputFormat outputFormat;
+  const char* outputFileName;
+  const char* tempFileName;
+};
+
+/* Prototypes. */
+extern struct Options gOptions;
+extern FILE* gOutFile;
+int processFile(const char* fileName);
+
+}  // namespace art
+
+#endif  // ART_DEXDUMP_DEXDUMP_H_
diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc
new file mode 100644
index 0000000..9be0922
--- /dev/null
+++ b/dexdump/dexdump_main.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ * Main driver of the dexdump utility.
+ *
+ * This is a re-implementation of the original dexdump utility that was
+ * based on Dalvik functions in libdex into a new dexdump that is now
+ * based on Art functions in libart instead. The output is identical to
+ * the original for correct DEX files. Error messages may differ, however.
+ * Also, ODEX files are no longer supported.
+ */
+
+#include "dexdump.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mem_map.h"
+#include "runtime.h"
+
+namespace art {
+
+static const char* gProgName = "dexdump";
+
+/*
+ * Shows usage.
+ */
+static void usage(void) {
+  fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+  fprintf(stderr, "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-o outfile]"
+                  " [-t tempfile] dexfile...\n", gProgName);
+  fprintf(stderr, "\n");
+  fprintf(stderr, " -c : verify checksum and exit\n");
+  fprintf(stderr, " -d : disassemble code sections\n");
+  fprintf(stderr, " -f : display summary information from file header\n");
+  fprintf(stderr, " -h : display file header details\n");
+  fprintf(stderr, " -i : ignore checksum failures\n");
+  fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
+  fprintf(stderr, " -o : output file name (defaults to stdout)\n");
+  fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
+}
+
+/*
+ * Main driver of the dexdump utility.
+ */
+int dexdumpDriver(int argc, char** argv) {
+  // Art specific set up.
+  InitLogging(argv);
+  MemMap::Init();
+
+  // Reset options.
+  bool wantUsage = false;
+  memset(&gOptions, 0, sizeof(gOptions));
+  gOptions.verbose = true;
+
+  // Parse all arguments.
+  while (1) {
+    const int ic = getopt(argc, argv, "cdfhil:t:o:");
+    if (ic < 0) {
+      break;  // done
+    }
+    switch (ic) {
+      case 'c':  // verify the checksum then exit
+        gOptions.checksumOnly = true;
+        break;
+      case 'd':  // disassemble Dalvik instructions
+        gOptions.disassemble = true;
+        break;
+      case 'f':  // dump outer file header
+        gOptions.showFileHeaders = true;
+        break;
+      case 'h':  // dump section headers, i.e. all meta-data
+        gOptions.showSectionHeaders = true;
+        break;
+      case 'i':  // continue even if checksum is bad
+        gOptions.ignoreBadChecksum = true;
+        break;
+      case 'l':  // layout
+        if (strcmp(optarg, "plain") == 0) {
+          gOptions.outputFormat = OUTPUT_PLAIN;
+        } else if (strcmp(optarg, "xml") == 0) {
+          gOptions.outputFormat = OUTPUT_XML;
+          gOptions.verbose = false;
+          gOptions.exportsOnly = true;
+        } else {
+          wantUsage = true;
+        }
+        break;
+      case 't':  // temp file, used when opening compressed Jar
+        gOptions.tempFileName = optarg;
+        break;
+      case 'o':  // output file
+        gOptions.outputFileName = optarg;
+        break;
+      default:
+        wantUsage = true;
+        break;
+    }  // switch
+  }  // while
+
+  // Detect early problems.
+  if (optind == argc) {
+    fprintf(stderr, "%s: no file specified\n", gProgName);
+    wantUsage = true;
+  }
+  if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
+    fprintf(stderr, "Can't specify both -c and -i\n");
+    wantUsage = true;
+  }
+  if (wantUsage) {
+    usage();
+    return 2;
+  }
+
+  // Open alternative output file.
+  if (gOptions.outputFileName) {
+    gOutFile = fopen(gOptions.outputFileName, "w");
+    if (!gOutFile) {
+      fprintf(stderr, "Can't open %s\n", gOptions.outputFileName);
+      return 1;
+    }
+  }
+
+  // Process all files supplied on command line.
+  int result = 0;
+  while (optind < argc) {
+    result |= processFile(argv[optind++]);
+  }  // while
+  return result != 0;
+}
+
+}  // namespace art
+
+int main(int argc, char** argv) {
+  return art::dexdumpDriver(argc, argv);
+}
diff --git a/dexdump/dexdump_test.cc b/dexdump/dexdump_test.cc
new file mode 100644
index 0000000..d9b210d
--- /dev/null
+++ b/dexdump/dexdump_test.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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 <string>
+#include <vector>
+#include <sstream>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/stringprintf.h"
+#include "common_runtime_test.h"
+#include "runtime/arch/instruction_set.h"
+#include "runtime/gc/heap.h"
+#include "runtime/gc/space/image_space.h"
+#include "runtime/os.h"
+#include "runtime/utils.h"
+#include "utils.h"
+
+namespace art {
+
+class DexDumpTest : public CommonRuntimeTest {
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTest::SetUp();
+    // Dogfood our own lib core dex file.
+    dex_file_ = GetLibCoreDexFileName();
+  }
+
+  // Runs test with given arguments.
+  bool Exec(const std::vector<std::string>& args, std::string* error_msg) {
+    // TODO(ajcbik): dexdump2 -> dexdump
+    std::string file_path = GetTestAndroidRoot();
+    if (IsHost()) {
+      file_path += "/bin/dexdump2";
+    } else {
+      file_path += "/xbin/dexdump2";
+    }
+    EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
+    std::vector<std::string> exec_argv = { file_path };
+    exec_argv.insert(exec_argv.end(), args.begin(), args.end());
+    return ::art::Exec(exec_argv, error_msg);
+  }
+
+  std::string dex_file_;
+};
+
+
+TEST_F(DexDumpTest, NoInputFileGiven) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexDumpTest, CantOpenOutput) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({"-o", "/joho", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexDumpTest, BadFlagCombination) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({"-c", "-i", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexDumpTest, FullPlainOutput) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec({"-d", "-f", "-h", "-l", "plain", "-o", "/dev/null",
+    dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexDumpTest, XMLOutput) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec({"-l", "xml", "-o", "/dev/null",
+    dex_file_}, &error_msg)) << error_msg;
+}
+
+}  // namespace art
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
new file mode 100755
index 0000000..988fe03
--- /dev/null
+++ b/dexlist/Android.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2015 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.
+
+# TODO(ajcbik): Art-i-fy this makefile
+
+# TODO(ajcbik): rename dexlist2 into dexlist when Dalvik version is removed
+
+LOCAL_PATH:= $(call my-dir)
+
+dexlist_src_files := dexlist.cc
+dexlist_c_includes := art/runtime
+dexlist_libraries := libart
+
+##
+## Build the device command line tool dexlist.
+##
+
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := cc
+LOCAL_SRC_FILES := $(dexlist_src_files)
+LOCAL_C_INCLUDES := $(dexlist_c_includes)
+LOCAL_CFLAGS += -Wall
+LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
+LOCAL_MODULE := dexlist2
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
+endif # !SDK_ONLY
+
+##
+## Build the host command line tool dexlist.
+##
+
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := cc
+LOCAL_SRC_FILES := $(dexlist_src_files)
+LOCAL_C_INCLUDES := $(dexlist_c_includes)
+LOCAL_CFLAGS += -Wall
+LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
+LOCAL_MODULE := dexlist2
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
new file mode 100644
index 0000000..d8fd242
--- /dev/null
+++ b/dexlist/dexlist.cc
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2015 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.
+ *
+ * Implementation file of the dexlist utility.
+ *
+ * This is a re-implementation of the original dexlist utility that was
+ * based on Dalvik functions in libdex into a new dexlist that is now
+ * based on Art functions in libart instead. The output is identical to
+ * the original for correct DEX files. Error messages may differ, however.
+ *
+ * List all methods in all concrete classes in one or more DEX files.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "dex_file-inl.h"
+#include "mem_map.h"
+#include "runtime.h"
+
+namespace art {
+
+static const char* gProgName = "dexlist";
+
+/* Command-line options. */
+static struct {
+  char* argCopy;
+  const char* classToFind;
+  const char* methodToFind;
+  const char* outputFileName;
+} gOptions;
+
+/*
+ * Output file. Defaults to stdout.
+ */
+static FILE* gOutFile = stdout;
+
+/*
+ * Data types that match the definitions in the VM specification.
+ */
+typedef uint8_t  u1;
+typedef uint32_t u4;
+typedef uint64_t u8;
+
+/*
+ * Returns a newly-allocated string for the "dot version" of the class
+ * name for the given type descriptor. That is, The initial "L" and
+ * final ";" (if any) have been removed and all occurrences of '/'
+ * have been changed to '.'.
+ */
+static char* descriptorToDot(const char* str) {
+  size_t at = strlen(str);
+  if (str[0] == 'L') {
+    at -= 2;  // Two fewer chars to copy.
+    str++;
+  }
+  char* newStr = reinterpret_cast<char*>(malloc(at + 1));
+  newStr[at] = '\0';
+  while (at > 0) {
+    at--;
+    newStr[at] = (str[at] == '/') ? '.' : str[at];
+  }
+  return newStr;
+}
+
+/*
+ * Positions table callback; we just want to catch the number of the
+ * first line in the method, which *should* correspond to the first
+ * entry from the table.  (Could also use "min" here.)
+ */
+static bool positionsCb(void* context, u4 /*address*/, u4 lineNum) {
+  int* pFirstLine = reinterpret_cast<int *>(context);
+  if (*pFirstLine == -1) {
+    *pFirstLine = lineNum;
+  }
+  return 0;
+}
+
+/*
+ * Dumps a method.
+ */
+static void dumpMethod(const DexFile* pDexFile,
+                       const char* fileName, u4 idx, u4 flags,
+                       const DexFile::CodeItem* pCode, u4 codeOffset) {
+  // Abstract and native methods don't get listed.
+  if (pCode == nullptr || codeOffset == 0) {
+    return;
+  }
+
+  // Method information.
+  const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
+  const char* methodName = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+  const char* classDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
+  char* className = descriptorToDot(classDescriptor);
+  const u4 insnsOff = codeOffset + 0x10;
+
+  // Don't list methods that do not match a particular query.
+  if (gOptions.methodToFind != nullptr &&
+      (strcmp(gOptions.classToFind, className) != 0 ||
+       strcmp(gOptions.methodToFind, methodName) != 0)) {
+    free(className);
+    return;
+  }
+
+  // If the filename is empty, then set it to something printable.
+  if (fileName == nullptr || fileName[0] == 0) {
+    fileName = "(none)";
+  }
+
+  // Find the first line.
+  int firstLine = -1;
+  bool is_static = (flags & kAccStatic) != 0;
+  pDexFile->DecodeDebugInfo(
+     pCode, is_static, idx, positionsCb, nullptr, &firstLine);
+
+  // Method signature.
+  const Signature signature = pDexFile->GetMethodSignature(pMethodId);
+  char* typeDesc = strdup(signature.ToString().c_str());
+
+  // Dump actual method information.
+  fprintf(gOutFile, "0x%08x %d %s %s %s %s %d\n",
+          insnsOff, pCode->insns_size_in_code_units_ * 2,
+          className, methodName, typeDesc, fileName, firstLine);
+
+  free(typeDesc);
+  free(className);
+}
+
+/*
+ * Runs through all direct and virtual methods in the class.
+ */
+void dumpClass(const DexFile* pDexFile, u4 idx) {
+  const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
+
+  const char* fileName;
+  if (pClassDef.source_file_idx_ == DexFile::kDexNoIndex) {
+    fileName = nullptr;
+  } else {
+    fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
+  }
+
+  const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
+  if (pEncodedData != nullptr) {
+    ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
+    // Skip the fields.
+    for (; pClassData.HasNextStaticField(); pClassData.Next()) {}
+    for (; pClassData.HasNextInstanceField(); pClassData.Next()) {}
+    // Direct methods.
+    for (; pClassData.HasNextDirectMethod(); pClassData.Next()) {
+      dumpMethod(pDexFile, fileName,
+                 pClassData.GetMemberIndex(),
+                 pClassData.GetRawMemberAccessFlags(),
+                 pClassData.GetMethodCodeItem(),
+                 pClassData.GetMethodCodeItemOffset());
+    }
+    // Virtual methods.
+    for (; pClassData.HasNextVirtualMethod(); pClassData.Next()) {
+      dumpMethod(pDexFile, fileName,
+                 pClassData.GetMemberIndex(),
+                 pClassData.GetRawMemberAccessFlags(),
+                 pClassData.GetMethodCodeItem(),
+                 pClassData.GetMethodCodeItemOffset());
+    }
+  }
+}
+
+/*
+ * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
+ */
+static int processFile(const char* fileName) {
+  // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
+  // all of which are Zip archives with "classes.dex" inside.
+  std::string error_msg;
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  if (!DexFile::Open(fileName, fileName, &error_msg, &dex_files)) {
+    fputs(error_msg.c_str(), stderr);
+    fputc('\n', stderr);
+    return -1;
+  }
+
+  // Success. Iterate over all dex files found in given file.
+  fprintf(gOutFile, "#%s\n", fileName);
+  for (size_t i = 0; i < dex_files.size(); i++) {
+    // Iterate over all classes in one dex file.
+    const DexFile* pDexFile = dex_files[i].get();
+    const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
+    for (u4 idx = 0; idx < classDefsSize; idx++) {
+      dumpClass(pDexFile, idx);
+    }
+  }
+  return 0;
+}
+
+/*
+ * Shows usage.
+ */
+static void usage(void) {
+  fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+  fprintf(stderr, "%s: [-m p.c.m] [-o outfile] dexfile...\n", gProgName);
+  fprintf(stderr, "\n");
+}
+
+/*
+ * Main driver of the dexlist utility.
+ */
+int dexlistDriver(int argc, char** argv) {
+  // Art specific set up.
+  InitLogging(argv);
+  MemMap::Init();
+
+  // Reset options.
+  bool wantUsage = false;
+  memset(&gOptions, 0, sizeof(gOptions));
+
+  // Parse all arguments.
+  while (1) {
+    const int ic = getopt(argc, argv, "o:m:");
+    if (ic < 0) {
+      break;  // done
+    }
+    switch (ic) {
+      case 'o':  // output file
+        gOptions.outputFileName = optarg;
+        break;
+      case 'm':
+        // If -m x.y.z is given, then find all instances of the
+        // fully-qualified method name. This isn't really what
+        // dexlist is for, but it's easy to do it here.
+        {
+          gOptions.argCopy = strdup(optarg);
+          char* meth = strrchr(gOptions.argCopy, '.');
+          if (meth == nullptr) {
+            fprintf(stderr, "Expected: package.Class.method\n");
+            wantUsage = true;
+          } else {
+            *meth = '\0';
+            gOptions.classToFind = gOptions.argCopy;
+            gOptions.methodToFind = meth + 1;
+          }
+        }
+        break;
+      default:
+        wantUsage = true;
+        break;
+    }  // switch
+  }  // while
+
+  // Detect early problems.
+  if (optind == argc) {
+    fprintf(stderr, "%s: no file specified\n", gProgName);
+    wantUsage = true;
+  }
+  if (wantUsage) {
+    usage();
+    free(gOptions.argCopy);
+    return 2;
+  }
+
+  // Open alternative output file.
+  if (gOptions.outputFileName) {
+    gOutFile = fopen(gOptions.outputFileName, "w");
+    if (!gOutFile) {
+      fprintf(stderr, "Can't open %s\n", gOptions.outputFileName);
+      free(gOptions.argCopy);
+      return 1;
+    }
+  }
+
+  // Process all files supplied on command line. If one of them fails we
+  // continue on, only returning a failure at the end.
+  int result = 0;
+  while (optind < argc) {
+    result |= processFile(argv[optind++]);
+  }  // while
+
+  free(gOptions.argCopy);
+  return result != 0;
+}
+
+}  // namespace art
+
+int main(int argc, char** argv) {
+  return art::dexlistDriver(argc, argv);
+}
+
diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc
new file mode 100644
index 0000000..7b1b63d
--- /dev/null
+++ b/dexlist/dexlist_test.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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 <string>
+#include <vector>
+#include <sstream>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/stringprintf.h"
+#include "common_runtime_test.h"
+#include "runtime/arch/instruction_set.h"
+#include "runtime/gc/heap.h"
+#include "runtime/gc/space/image_space.h"
+#include "runtime/os.h"
+#include "runtime/utils.h"
+#include "utils.h"
+
+namespace art {
+
+class DexListTest : public CommonRuntimeTest {
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTest::SetUp();
+    // Dogfood our own lib core dex file.
+    dex_file_ = GetLibCoreDexFileName();
+  }
+
+  // Runs test with given arguments.
+  bool Exec(const std::vector<std::string>& args, std::string* error_msg) {
+    // TODO(ajcbik): dexlist2 -> dexlist
+    std::string file_path = GetTestAndroidRoot();
+    if (IsHost()) {
+      file_path += "/bin/dexlist2";
+    } else {
+      file_path += "/xbin/dexlist2";
+    }
+    EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
+    std::vector<std::string> exec_argv = { file_path };
+    exec_argv.insert(exec_argv.end(), args.begin(), args.end());
+    return ::art::Exec(exec_argv, error_msg);
+  }
+
+  std::string dex_file_;
+};
+
+
+TEST_F(DexListTest, NoInputFileGiven) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, CantOpenOutput) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({"-o", "/joho", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, IllFormedMethod) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({"-m", "joho", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, FullOutput) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec({"-o", "/dev/null", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, MethodOutput) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec({"-o", "/dev/null", "-m", "java.lang.Object.toString",
+    dex_file_}, &error_msg)) << error_msg;
+}
+
+}  // namespace art
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index f324881..dce5206 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -548,10 +548,6 @@
           os << "  entryPointFromJni: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromJniPtrSize(pointer_size)) << ", ";
-          os << "  entryPointFromInterpreter: "
-             << reinterpret_cast<const void*>(
-                    art_method->GetEntryPointFromInterpreterPtrSize(pointer_size))
-             << ", ";
           os << "  entryPointFromQuickCompiledCode: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
@@ -631,10 +627,6 @@
           os << "  entryPointFromJni: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromJniPtrSize(pointer_size)) << ", ";
-          os << "  entryPointFromInterpreter: "
-             << reinterpret_cast<const void*>(
-                    art_method->GetEntryPointFromInterpreterPtrSize(pointer_size))
-             << ", ";
           os << "  entryPointFromQuickCompiledCode: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index b3801b3..e0d7708 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -599,6 +599,9 @@
       os << std::flush;
       return false;
     }
+
+    VariableIndentationOutputStream vios(&os);
+    ScopedIndentation indent1(&vios);
     for (size_t class_def_index = 0;
          class_def_index < dex_file->NumClassDefs();
          class_def_index++) {
@@ -617,10 +620,8 @@
          << " (" << oat_class.GetStatus() << ")"
          << " (" << oat_class.GetType() << ")\n";
       // TODO: include bitmap here if type is kOatClassSomeCompiled?
-      Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indented_os(&indent_filter);
       if (options_.list_classes_) continue;
-      if (!DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def, &stop_analysis)) {
+      if (!DumpOatClass(&vios, oat_class, *(dex_file.get()), class_def, &stop_analysis)) {
         success = false;
       }
       if (stop_analysis) {
@@ -720,20 +721,21 @@
     }
   }
 
-  bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
+  bool DumpOatClass(VariableIndentationOutputStream* vios,
+                    const OatFile::OatClass& oat_class, const DexFile& dex_file,
                     const DexFile::ClassDef& class_def, bool* stop_analysis) {
     bool success = true;
     bool addr_found = false;
     const uint8_t* class_data = dex_file.GetClassData(class_def);
     if (class_data == nullptr) {  // empty class such as a marker interface?
-      os << std::flush;
+      vios->Stream() << std::flush;
       return success;
     }
     ClassDataItemIterator it(dex_file, class_data);
     SkipAllFields(it);
     uint32_t class_method_index = 0;
     while (it.HasNextDirectMethod()) {
-      if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
+      if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
                          it.GetMemberIndex(), it.GetMethodCodeItem(),
                          it.GetRawMemberAccessFlags(), &addr_found)) {
         success = false;
@@ -746,7 +748,7 @@
       it.Next();
     }
     while (it.HasNextVirtualMethod()) {
-      if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
+      if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
                          it.GetMemberIndex(), it.GetMethodCodeItem(),
                          it.GetRawMemberAccessFlags(), &addr_found)) {
         success = false;
@@ -759,7 +761,7 @@
       it.Next();
     }
     DCHECK(!it.HasNext());
-    os << std::flush;
+    vios->Stream() << std::flush;
     return success;
   }
 
@@ -768,7 +770,8 @@
   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
 
-  bool DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
+  bool DumpOatMethod(VariableIndentationOutputStream* vios,
+                     const DexFile::ClassDef& class_def,
                      uint32_t class_method_index,
                      const OatFile::OatClass& oat_class, const DexFile& dex_file,
                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
@@ -782,16 +785,11 @@
     }
 
     std::string pretty_method = PrettyMethod(dex_method_idx, dex_file, true);
-    os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
-                       class_method_index, pretty_method.c_str(),
-                       dex_method_idx);
+    vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
+                                   class_method_index, pretty_method.c_str(),
+                                   dex_method_idx);
     if (options_.list_methods_) return success;
 
-    Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-    std::unique_ptr<std::ostream> indent1_os(new std::ostream(&indent1_filter));
-    Indenter indent2_filter(indent1_os->rdbuf(), kIndentChar, kIndentBy1Count);
-    std::unique_ptr<std::ostream> indent2_os(new std::ostream(&indent2_filter));
-
     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
@@ -805,137 +803,147 @@
       }
     }
 
+    // Everything below is indented at least once.
+    ScopedIndentation indent1(vios);
+
     {
-      *indent1_os << "DEX CODE:\n";
-      DumpDexCode(*indent2_os, dex_file, code_item);
+      vios->Stream() << "DEX CODE:\n";
+      ScopedIndentation indent2(vios);
+      DumpDexCode(vios->Stream(), dex_file, code_item);
     }
 
     std::unique_ptr<verifier::MethodVerifier> verifier;
     if (Runtime::Current() != nullptr) {
-      *indent1_os << "VERIFIER TYPE ANALYSIS:\n";
-      verifier.reset(DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item,
+      vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
+      ScopedIndentation indent2(vios);
+      verifier.reset(DumpVerifier(vios,
+                                  dex_method_idx, &dex_file, class_def, code_item,
                                   method_access_flags));
     }
     {
-      *indent1_os << "OatMethodOffsets ";
+      vios->Stream() << "OatMethodOffsets ";
       if (options_.absolute_addresses_) {
-        *indent1_os << StringPrintf("%p ", oat_method_offsets);
+        vios->Stream() << StringPrintf("%p ", oat_method_offsets);
       }
-      *indent1_os << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
       if (oat_method_offsets_offset > oat_file_.Size()) {
-        *indent1_os << StringPrintf(
+        vios->Stream() << StringPrintf(
             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
             oat_method_offsets_offset, oat_file_.Size());
         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
-        os << std::flush;
+        vios->Stream() << std::flush;
         return false;
       }
 
-      *indent2_os << StringPrintf("code_offset: 0x%08x ", code_offset);
+      ScopedIndentation indent2(vios);
+      vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
       if (aligned_code_begin > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "code offset 0x%08x is past end of file 0x%08zx.\n",
-                                    aligned_code_begin, oat_file_.Size());
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "code offset 0x%08x is past end of file 0x%08zx.\n",
+                                       aligned_code_begin, oat_file_.Size());
         success = false;
       }
-      *indent2_os << "\n";
+      vios->Stream() << "\n";
 
-      *indent2_os << "gc_map: ";
+      vios->Stream() << "gc_map: ";
       if (options_.absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetGcMap());
+        vios->Stream() << StringPrintf("%p ", oat_method.GetGcMap());
       }
       uint32_t gc_map_offset = oat_method.GetGcMapOffset();
-      *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
       if (gc_map_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
-                                    gc_map_offset, oat_file_.Size());
+        vios->Stream() << StringPrintf("WARNING: "
+                           "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
+                           gc_map_offset, oat_file_.Size());
         success = false;
       } else if (options_.dump_raw_gc_map_) {
-        Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent3_os(&indent3_filter);
-        DumpGcMap(indent3_os, oat_method, code_item);
+        ScopedIndentation indent3(vios);
+        DumpGcMap(vios->Stream(), oat_method, code_item);
       }
     }
     {
-      *indent1_os << "OatQuickMethodHeader ";
+      vios->Stream() << "OatQuickMethodHeader ";
       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
 
       if (options_.absolute_addresses_) {
-        *indent1_os << StringPrintf("%p ", method_header);
+        vios->Stream() << StringPrintf("%p ", method_header);
       }
-      *indent1_os << StringPrintf("(offset=0x%08x)\n", method_header_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
       if (method_header_offset > oat_file_.Size()) {
-        *indent1_os << StringPrintf(
+        vios->Stream() << StringPrintf(
             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
             method_header_offset, oat_file_.Size());
         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
-        os << std::flush;
+        vios->Stream() << std::flush;
         return false;
       }
 
-      *indent2_os << "mapping_table: ";
+      ScopedIndentation indent2(vios);
+      vios->Stream() << "mapping_table: ";
       if (options_.absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetMappingTable());
+        vios->Stream() << StringPrintf("%p ", oat_method.GetMappingTable());
       }
       uint32_t mapping_table_offset = oat_method.GetMappingTableOffset();
-      *indent2_os << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
       if (mapping_table_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "mapping table offset 0x%08x is past end of file 0x%08zx. "
-                                    "mapping table offset was loaded from offset 0x%08x.\n",
-                                    mapping_table_offset, oat_file_.Size(),
-                                    oat_method.GetMappingTableOffsetOffset());
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "mapping table offset 0x%08x is past end of file 0x%08zx. "
+                                       "mapping table offset was loaded from offset 0x%08x.\n",
+                                       mapping_table_offset, oat_file_.Size(),
+                                       oat_method.GetMappingTableOffsetOffset());
         success = false;
       } else if (options_.dump_raw_mapping_table_) {
-        Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent3_os(&indent3_filter);
-        DumpMappingTable(indent3_os, oat_method);
+        ScopedIndentation indent3(vios);
+        DumpMappingTable(vios, oat_method);
       }
 
-      *indent2_os << "vmap_table: ";
+      vios->Stream() << "vmap_table: ";
       if (options_.absolute_addresses_) {
-        *indent2_os << StringPrintf("%p ", oat_method.GetVmapTable());
+        vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
       }
       uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
-      *indent2_os << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
+      vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
       if (vmap_table_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "vmap table offset 0x%08x is past end of file 0x%08zx. "
-                                    "vmap table offset was loaded from offset 0x%08x.\n",
-                                    vmap_table_offset, oat_file_.Size(),
-                                    oat_method.GetVmapTableOffsetOffset());
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "vmap table offset 0x%08x is past end of file 0x%08zx. "
+                                       "vmap table offset was loaded from offset 0x%08x.\n",
+                                       vmap_table_offset, oat_file_.Size(),
+                                       oat_method.GetVmapTableOffsetOffset());
         success = false;
       } else if (options_.dump_vmap_) {
-        DumpVmapData(*indent2_os, oat_method, code_item);
+        DumpVmapData(vios, oat_method, code_item);
       }
     }
     {
-      *indent1_os << "QuickMethodFrameInfo\n";
+      vios->Stream() << "QuickMethodFrameInfo\n";
 
-      *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
-      *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
-      DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false);
-      *indent2_os << "\n";
-      *indent2_os << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
-      DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
-      *indent2_os << "\n";
+      ScopedIndentation indent2(vios);
+      vios->Stream()
+          << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
+      vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
+      DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
+      vios->Stream() << "\n";
+      vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
+      DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
+      vios->Stream() << "\n";
     }
     {
-        // Based on spill masks from QuickMethodFrameInfo so placed
-        // after it is dumped, but useful for understanding quick
-        // code, so dumped here.
-        DumpVregLocations(*indent2_os, oat_method, code_item);
+      // Based on spill masks from QuickMethodFrameInfo so placed
+      // after it is dumped, but useful for understanding quick
+      // code, so dumped here.
+      ScopedIndentation indent2(vios);
+      DumpVregLocations(vios->Stream(), oat_method, code_item);
     }
     {
-      *indent1_os << "CODE: ";
+      vios->Stream() << "CODE: ";
       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
       if (code_size_offset > oat_file_.Size()) {
-        *indent2_os << StringPrintf("WARNING: "
-                                    "code size offset 0x%08x is past end of file 0x%08zx.",
-                                    code_size_offset, oat_file_.Size());
+        ScopedIndentation indent2(vios);
+        vios->Stream() << StringPrintf("WARNING: "
+                                       "code size offset 0x%08x is past end of file 0x%08zx.",
+                                       code_size_offset, oat_file_.Size());
         success = false;
       } else {
         const void* code = oat_method.GetQuickCode();
@@ -943,49 +951,52 @@
         uint64_t aligned_code_end = aligned_code_begin + code_size;
 
         if (options_.absolute_addresses_) {
-          *indent1_os << StringPrintf("%p ", code);
+          vios->Stream() << StringPrintf("%p ", code);
         }
-        *indent1_os << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
-                                    code_offset,
-                                    code_size_offset,
-                                    code_size,
-                                    code != nullptr ? "..." : "");
+        vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
+                                       code_offset,
+                                       code_size_offset,
+                                       code_size,
+                                       code != nullptr ? "..." : "");
 
+        ScopedIndentation indent2(vios);
         if (aligned_code_begin > oat_file_.Size()) {
-          *indent2_os << StringPrintf("WARNING: "
-                                      "start of code at 0x%08x is past end of file 0x%08zx.",
-                                      aligned_code_begin, oat_file_.Size());
+          vios->Stream() << StringPrintf("WARNING: "
+                                         "start of code at 0x%08x is past end of file 0x%08zx.",
+                                         aligned_code_begin, oat_file_.Size());
           success = false;
         } else if (aligned_code_end > oat_file_.Size()) {
-          *indent2_os << StringPrintf("WARNING: "
-                                      "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
-                                      "code size is 0x%08x loaded from offset 0x%08x.\n",
-                                      aligned_code_end, oat_file_.Size(),
-                                      code_size, code_size_offset);
+          vios->Stream() << StringPrintf(
+              "WARNING: "
+              "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
+              "code size is 0x%08x loaded from offset 0x%08x.\n",
+              aligned_code_end, oat_file_.Size(),
+              code_size, code_size_offset);
           success = false;
           if (options_.disassemble_code_) {
             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
-              DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
+              DumpCode(vios, verifier.get(), oat_method, code_item, true, kPrologueBytes);
             }
           }
         } else if (code_size > kMaxCodeSize) {
-          *indent2_os << StringPrintf("WARNING: "
-                                      "code size %d is bigger than max expected threshold of %d. "
-                                      "code size is 0x%08x loaded from offset 0x%08x.\n",
-                                      code_size, kMaxCodeSize,
-                                      code_size, code_size_offset);
+          vios->Stream() << StringPrintf(
+              "WARNING: "
+              "code size %d is bigger than max expected threshold of %d. "
+              "code size is 0x%08x loaded from offset 0x%08x.\n",
+              code_size, kMaxCodeSize,
+              code_size, code_size_offset);
           success = false;
           if (options_.disassemble_code_) {
             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
-              DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
+              DumpCode(vios, verifier.get(), oat_method, code_item, true, kPrologueBytes);
             }
           }
         } else if (options_.disassemble_code_) {
-          DumpCode(*indent2_os, verifier.get(), oat_method, code_item, !success, 0);
+          DumpCode(vios, verifier.get(), oat_method, code_item, !success, 0);
         }
       }
     }
-    os << std::flush;
+    vios->Stream() << std::flush;
     return success;
   }
 
@@ -1013,7 +1024,7 @@
   }
 
   // Display data stored at the the vmap offset of an oat method.
-  void DumpVmapData(std::ostream& os,
+  void DumpVmapData(VariableIndentationOutputStream* vios,
                     const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem* code_item) {
     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
@@ -1022,24 +1033,30 @@
       if (raw_code_info != nullptr) {
         CodeInfo code_info(raw_code_info);
         DCHECK(code_item != nullptr);
-        DumpCodeInfo(os, code_info, oat_method, *code_item);
+        ScopedIndentation indent1(vios);
+        DumpCodeInfo(vios, code_info, oat_method, *code_item);
       }
+    } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) {
+      // We don't encode the size in the table, so just emit that we have quickened
+      // information.
+      ScopedIndentation indent(vios);
+      vios->Stream() << "quickened data\n";
     } else {
       // Otherwise, display the vmap table.
       const uint8_t* raw_table = oat_method.GetVmapTable();
       if (raw_table != nullptr) {
         VmapTable vmap_table(raw_table);
-        DumpVmapTable(os, oat_method, vmap_table);
+        DumpVmapTable(vios->Stream(), oat_method, vmap_table);
       }
     }
   }
 
   // Display a CodeInfo object emitted by the optimizing compiler.
-  void DumpCodeInfo(std::ostream& os,
+  void DumpCodeInfo(VariableIndentationOutputStream* vios,
                     const CodeInfo& code_info,
                     const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem& code_item) {
-    code_info.Dump(os,
+    code_info.Dump(vios,
                    oat_method.GetCodeOffset(),
                    code_item.registers_size_,
                    options_.dump_code_info_stack_maps_);
@@ -1177,48 +1194,50 @@
     }
   }
 
-  void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
+  void DumpMappingTable(VariableIndentationOutputStream* vios,
+                        const OatFile::OatMethod& oat_method) {
     const void* quick_code = oat_method.GetQuickCode();
     if (quick_code == nullptr) {
       return;
     }
     MappingTable table(oat_method.GetMappingTable());
     if (table.TotalSize() != 0) {
-      Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indent_os(&indent_filter);
       if (table.PcToDexSize() != 0) {
         typedef MappingTable::PcToDexIterator It;
-        os << "suspend point mappings {\n";
+        vios->Stream() << "suspend point mappings {\n";
         for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
-          indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
+          ScopedIndentation indent1(vios);
+          vios->Stream() << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
         }
-        os << "}\n";
+        vios->Stream() << "}\n";
       }
       if (table.DexToPcSize() != 0) {
         typedef MappingTable::DexToPcIterator It;
-        os << "catch entry mappings {\n";
+        vios->Stream() << "catch entry mappings {\n";
         for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
-          indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
+          ScopedIndentation indent1(vios);
+          vios->Stream() << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
         }
-        os << "}\n";
+        vios->Stream() << "}\n";
       }
     }
   }
 
-  uint32_t DumpInformationAtOffset(std::ostream& os,
+  uint32_t DumpInformationAtOffset(VariableIndentationOutputStream* vios,
                                    const OatFile::OatMethod& oat_method,
                                    const DexFile::CodeItem* code_item,
                                    size_t offset,
                                    bool suspend_point_mapping) {
     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
       if (suspend_point_mapping) {
-        DumpDexRegisterMapAtOffset(os, oat_method, code_item, offset);
+        ScopedIndentation indent1(vios);
+        DumpDexRegisterMapAtOffset(vios, oat_method, code_item, offset);
       }
       // The return value is not used in the case of a method compiled
       // with the optimizing compiler.
       return DexFile::kDexNoIndex;
     } else {
-      return DumpMappingAtOffset(os, oat_method, offset, suspend_point_mapping);
+      return DumpMappingAtOffset(vios->Stream(), oat_method, offset, suspend_point_mapping);
     }
   }
 
@@ -1331,10 +1350,24 @@
     // If the native GC map is null and the Dex `code_item` is not
     // null, then this method has been compiled with the optimizing
     // compiler.
-    return oat_method.GetGcMap() == nullptr && code_item != nullptr;
+    return oat_method.GetQuickCode() != nullptr &&
+           oat_method.GetGcMap() == nullptr &&
+           code_item != nullptr;
   }
 
-  void DumpDexRegisterMapAtOffset(std::ostream& os,
+  // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
+  // the dextodex compiler?
+  static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method,
+                                                  const DexFile::CodeItem* code_item) {
+    // If the quick code is null, the Dex `code_item` is not
+    // null, and the vmap table is not null, then this method has been compiled
+    // with the dextodex compiler.
+    return oat_method.GetQuickCode() == nullptr &&
+           oat_method.GetVmapTable() != nullptr &&
+           code_item != nullptr;
+  }
+
+  void DumpDexRegisterMapAtOffset(VariableIndentationOutputStream* vios,
                                   const OatFile::OatMethod& oat_method,
                                   const DexFile::CodeItem* code_item,
                                   size_t offset) {
@@ -1349,13 +1382,14 @@
       StackMapEncoding encoding = code_info.ExtractEncoding();
       StackMap stack_map = code_info.GetStackMapForNativePcOffset(offset, encoding);
       if (stack_map.IsValid()) {
-        stack_map.Dump(
-            os, code_info, encoding, oat_method.GetCodeOffset(), code_item->registers_size_);
+        stack_map.Dump(vios, code_info, encoding, oat_method.GetCodeOffset(),
+                       code_item->registers_size_);
       }
     }
   }
 
-  verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
+  verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
+                                         uint32_t dex_method_idx,
                                          const DexFile* dex_file,
                                          const DexFile::ClassDef& class_def,
                                          const DexFile::CodeItem* code_item,
@@ -1367,14 +1401,15 @@
           hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
       DCHECK(options_.class_loader_ != nullptr);
       return verifier::MethodVerifier::VerifyMethodAndDump(
-          soa.Self(), os, dex_method_idx, dex_file, dex_cache, *options_.class_loader_, &class_def,
-          code_item, nullptr, method_access_flags);
+          soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
+          &class_def, code_item, nullptr, method_access_flags);
     }
 
     return nullptr;
   }
 
-  void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier,
+  void DumpCode(VariableIndentationOutputStream* vios,
+                verifier::MethodVerifier* verifier,
                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
                 bool bad_input, size_t code_size) {
     const void* quick_code = oat_method.GetQuickCode();
@@ -1383,22 +1418,23 @@
       code_size = oat_method.GetQuickCodeSize();
     }
     if (code_size == 0 || quick_code == nullptr) {
-      os << "NO CODE!\n";
+      vios->Stream() << "NO CODE!\n";
       return;
     } else {
       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
       size_t offset = 0;
       while (offset < code_size) {
         if (!bad_input) {
-          DumpInformationAtOffset(os, oat_method, code_item, offset, false);
+          DumpInformationAtOffset(vios, oat_method, code_item, offset, false);
         }
-        offset += disassembler_->Dump(os, quick_native_pc + offset);
+        offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
         if (!bad_input) {
-          uint32_t dex_pc = DumpInformationAtOffset(os, oat_method, code_item, offset, true);
+          uint32_t dex_pc =
+              DumpInformationAtOffset(vios, oat_method, code_item, offset, true);
           if (dex_pc != DexFile::kDexNoIndex) {
-            DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
+            DumpGcMapAtNativePcOffset(vios->Stream(), oat_method, code_item, offset);
             if (verifier != nullptr) {
-              DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc);
+              DumpVRegsAtDexPc(vios->Stream(), verifier, oat_method, code_item, dex_pc);
             }
           }
         }
@@ -1420,12 +1456,16 @@
   explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
                        const ImageHeader& image_header, OatDumperOptions* oat_dumper_options)
       : os_(os),
+        vios_(os),
+        indent1_(&vios_),
         image_space_(image_space),
         image_header_(image_header),
         oat_dumper_options_(oat_dumper_options) {}
 
   bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::ostream& os = *os_;
+    std::ostream& indent_os = vios_.Stream();
+
     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
 
     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
@@ -1453,20 +1493,17 @@
 
     {
       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
-      Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indent1_os(&indent1_filter);
       static_assert(arraysize(image_roots_descriptions_) ==
           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
       for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
         const char* image_root_description = image_roots_descriptions_[i];
         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
-        indent1_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
+        indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
         if (image_root_object->IsObjectArray()) {
-          Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
-          std::ostream indent2_os(&indent2_filter);
           mirror::ObjectArray<mirror::Object>* image_root_object_array
               = image_root_object->AsObjectArray<mirror::Object>();
+          ScopedIndentation indent2(&vios_);
           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
             mirror::Object* value = image_root_object_array->Get(j);
             size_t run = 0;
@@ -1478,20 +1515,22 @@
               }
             }
             if (run == 0) {
-              indent2_os << StringPrintf("%d: ", j);
+              indent_os << StringPrintf("%d: ", j);
             } else {
-              indent2_os << StringPrintf("%d to %zd: ", j, j + run);
+              indent_os << StringPrintf("%d to %zd: ", j, j + run);
               j = j + run;
             }
             if (value != nullptr) {
-              PrettyObjectValue(indent2_os, value->GetClass(), value);
+              PrettyObjectValue(indent_os, value->GetClass(), value);
             } else {
-              indent2_os << j << ": null\n";
+              indent_os << j << ": null\n";
             }
           }
         }
       }
+    }
 
+    {
       os << "METHOD ROOTS\n";
       static_assert(arraysize(image_methods_descriptions_) ==
           static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
@@ -1499,7 +1538,7 @@
         auto image_root = static_cast<ImageHeader::ImageMethod>(i);
         const char* description = image_methods_descriptions_[i];
         auto* image_method = image_header_.GetImageMethod(image_root);
-        indent1_os << StringPrintf("%s: %p\n", description, image_method);
+        indent_os << StringPrintf("%s: %p\n", description, image_method);
       }
     }
     os << "\n";
@@ -1556,11 +1595,6 @@
       }
     }
     {
-      std::ostream* saved_os = os_;
-      Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-      std::ostream indent_os(&indent_filter);
-      os_ = &indent_os;
-
       // Mark dex caches.
       dex_cache_arrays_.clear();
       {
@@ -1596,7 +1630,6 @@
       // Dump the large objects separately.
       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
       indent_os << "\n";
-      os_ = saved_os;
     }
     os << "STATS:\n" << std::flush;
     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
@@ -1618,9 +1651,10 @@
     stats_.alignment_bytes += bitmap_section.Offset() - image_header_.GetImageSize();
     stats_.bitmap_bytes += bitmap_section.Size();
     stats_.art_field_bytes += field_section.Size();
-    stats_.art_method_bytes += method_section.Size();
+    // RoundUp to 8 bytes to match the intern table alignment expectation.
+    stats_.art_method_bytes += RoundUp(method_section.Size(), sizeof(uint64_t));
     stats_.interned_strings_bytes += intern_section.Size();
-    stats_.Dump(os);
+    stats_.Dump(os, indent_os);
     os << "\n";
 
     os << std::flush;
@@ -1759,7 +1793,8 @@
     state->stats_.object_bytes += object_bytes;
     state->stats_.alignment_bytes += alignment_bytes;
 
-    std::ostream& os = *state->os_;
+    std::ostream& os = state->vios_.Stream();
+
     mirror::Class* obj_class = obj->GetClass();
     if (obj_class->IsArrayClass()) {
       os << StringPrintf("%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
@@ -1774,9 +1809,8 @@
     } else {
       os << StringPrintf("%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
     }
-    Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-    std::ostream indent_os(&indent_filter);
-    DumpFields(indent_os, obj, obj_class);
+    ScopedIndentation indent1(&state->vios_);
+    DumpFields(os, obj, obj_class);
     const auto image_pointer_size =
         InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
     if (obj->IsObjectArray()) {
@@ -1792,25 +1826,24 @@
           }
         }
         if (run == 0) {
-          indent_os << StringPrintf("%d: ", i);
+          os << StringPrintf("%d: ", i);
         } else {
-          indent_os << StringPrintf("%d to %zd: ", i, i + run);
+          os << StringPrintf("%d to %zd: ", i, i + run);
           i = i + run;
         }
         mirror::Class* value_class =
             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
-        PrettyObjectValue(indent_os, value_class, value);
+        PrettyObjectValue(os, value_class, value);
       }
     } else if (obj->IsClass()) {
       mirror::Class* klass = obj->AsClass();
       ArtField* sfields = klass->GetSFields();
       const size_t num_fields = klass->NumStaticFields();
       if (num_fields != 0) {
-        indent_os << "STATICS:\n";
-        Indenter indent2_filter(indent_os.rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent2_os(&indent2_filter);
+        os << "STATICS:\n";
+        ScopedIndentation indent2(&state->vios_);
         for (size_t i = 0; i < num_fields; i++) {
-          PrintField(indent2_os, &sfields[i], sfields[i].GetDeclaringClass());
+          PrintField(os, &sfields[i], sfields[i].GetDeclaringClass());
         }
       }
     } else {
@@ -1826,9 +1859,9 @@
           for (int32_t j = i + 1; j < length &&
               elem == arr->GetElementPtrSize<void*>(j, image_pointer_size); j++, run++) { }
           if (run == 0) {
-            indent_os << StringPrintf("%d: ", i);
+            os << StringPrintf("%d: ", i);
           } else {
-            indent_os << StringPrintf("%d to %zd: ", i, i + run);
+            os << StringPrintf("%d to %zd: ", i, i + run);
             i = i + run;
           }
           auto offset = reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin();
@@ -1840,7 +1873,7 @@
           } else {
             msg = "Unknown type";
           }
-          indent_os << StringPrintf("%p   %s\n", elem, msg.c_str());
+          os << StringPrintf("%p   %s\n", elem, msg.c_str());
         }
       }
     }
@@ -1889,10 +1922,14 @@
         state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
       }
 
-      size_t vmap_table_bytes = state->ComputeOatSize(
-          method->GetVmapTable(image_pointer_size), &first_occurrence);
-      if (first_occurrence) {
-        state->stats_.vmap_table_bytes += vmap_table_bytes;
+      size_t vmap_table_bytes = 0u;
+      if (!method->IsOptimized(image_pointer_size)) {
+        // Method compiled with the optimizing compiler have no vmap table.
+        vmap_table_bytes = state->ComputeOatSize(
+            method->GetVmapTable(image_pointer_size), &first_occurrence);
+        if (first_occurrence) {
+          state->stats_.vmap_table_bytes += vmap_table_bytes;
+        }
       }
 
       const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method);
@@ -1915,7 +1952,7 @@
 
       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
       indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
-      dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
+                                dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
 
       size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
           vmap_table_bytes + quick_oat_code_size + ArtMethod::ObjectSize(image_pointer_size);
@@ -2130,12 +2167,11 @@
       os << "\n" << std::flush;
     }
 
-    void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    void Dump(std::ostream& os, std::ostream& indent_os)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       {
         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
-        Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent_os(&indent_filter);
         indent_os << StringPrintf("header_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
                                   "object_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
                                   "art_field_bytes       =  %8zd (%2.0f%% of art file bytes)\n"
@@ -2228,7 +2264,13 @@
     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
     kLargeMethodDexBytes = 16000
   };
+
+  // For performance, use the *os_ directly for anything that doesn't need indentation
+  // and prepare an indentation stream with default indentation 1.
   std::ostream* os_;
+  VariableIndentationOutputStream vios_;
+  ScopedIndentation indent1_;
+
   gc::space::ImageSpace& image_space_;
   const ImageHeader& image_header_;
   std::unique_ptr<OatDumper> oat_dumper_;
diff --git a/patchoat/Android.mk b/patchoat/Android.mk
index 68ca923..8f9ffca 100644
--- a/patchoat/Android.mk
+++ b/patchoat/Android.mk
@@ -30,16 +30,16 @@
 endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,target,ndebug,$(patchoat_arch)))
+  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,target,ndebug,$(patchoat_arch)))
 endif
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,target,debug,$(patchoat_arch)))
+  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,target,debug,$(patchoat_arch)))
 endif
 
 # We always build patchoat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,host,ndebug))
+  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,host,ndebug))
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils,art/compiler,host,debug))
+  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,host,debug))
 endif
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 0401727..dbd1d23 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -138,6 +138,7 @@
   std::string img = "-Ximage:" + image_location;
   options.push_back(std::make_pair(img.c_str(), nullptr));
   options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
+  options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
   if (!Runtime::Create(options, false)) {
     LOG(ERROR) << "Unable to initialize runtime";
     return false;
@@ -233,6 +234,7 @@
   std::string img = "-Ximage:" + image_location;
   options.push_back(std::make_pair(img.c_str(), nullptr));
   options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
+  options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
   if (!Runtime::Create(options, false)) {
     LOG(ERROR) << "Unable to initialize runtime";
     return false;
@@ -649,8 +651,6 @@
   copy->SetDexCacheResolvedTypes(RelocatedAddressOfPointer(object->GetDexCacheResolvedTypes()));
   copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer(
       object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size);
-  copy->SetEntryPointFromInterpreterPtrSize(RelocatedAddressOfPointer(
-      object->GetEntryPointFromInterpreterPtrSize(pointer_size)), pointer_size);
   copy->SetEntryPointFromJniPtrSize(RelocatedAddressOfPointer(
       object->GetEntryPointFromJniPtrSize(pointer_size)), pointer_size);
 }
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 19079cb..7f103a4 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -369,6 +369,7 @@
 
 # $(1): target or host
 # $(2): ndebug or debug
+# $(3): static or shared (empty means shared, applies only for host)
 define build-libart
   ifneq ($(1),target)
     ifneq ($(1),host)
@@ -383,6 +384,7 @@
 
   art_target_or_host := $(1)
   art_ndebug_or_debug := $(2)
+  art_static_or_shared := $(3)
 
   include $$(CLEAR_VARS)
   # Clang assembler has problem with macros in asm_support_x86.S, http://b/17443165,
@@ -403,7 +405,12 @@
   endif
 
   LOCAL_MODULE_TAGS := optional
-  LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+  ifeq ($$(art_static_or_shared),static)
+    LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+  else
+    LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+  endif
 
   ifeq ($$(art_target_or_host),target)
     LOCAL_SRC_FILES := $$(LIBART_TARGET_SRC_FILES)
@@ -431,8 +438,11 @@
   LOCAL_LDFLAGS := $$(LIBART_LDFLAGS)
   ifeq ($$(art_target_or_host),target)
     LOCAL_LDFLAGS += $$(LIBART_TARGET_LDFLAGS)
-  else
+  else #host
     LOCAL_LDFLAGS += $$(LIBART_HOST_LDFLAGS)
+    ifeq ($$(art_static_or_shared),static)
+      LOCAL_LDFLAGS += -static
+    endif
   endif
   $$(foreach arch,$$(ART_TARGET_SUPPORTED_ARCH), \
     $$(eval LOCAL_LDFLAGS_$$(arch) := $$(LIBART_TARGET_LDFLAGS_$$(arch))))
@@ -467,8 +477,12 @@
   LOCAL_C_INCLUDES += art/sigchainlib
   LOCAL_C_INCLUDES += art
 
-  LOCAL_SHARED_LIBRARIES := libnativehelper libnativebridge libsigchain
-  LOCAL_SHARED_LIBRARIES += libbacktrace
+  ifeq ($$(art_static_or_shared),static)
+    LOCAL_STATIC_LIBRARIES := libnativehelper libnativebridge libsigchain_dummy libbacktrace
+  else
+    LOCAL_SHARED_LIBRARIES := libnativehelper libnativebridge libsigchain libbacktrace
+  endif
+
   ifeq ($$(art_target_or_host),target)
     LOCAL_SHARED_LIBRARIES += libdl
     # ZipArchive support, the order matters here to get all symbols.
@@ -478,9 +492,15 @@
     # For liblog, atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted.
     LOCAL_SHARED_LIBRARIES += libcutils
   else # host
-    LOCAL_SHARED_LIBRARIES += libziparchive-host libz-host
-    # For ashmem_create_region.
-    LOCAL_SHARED_LIBRARIES += libcutils
+    ifeq ($$(art_static_or_shared),static)
+      LOCAL_STATIC_LIBRARIES += libziparchive-host libz
+      # For ashmem_create_region.
+      LOCAL_STATIC_LIBRARIES += libcutils
+    else
+      LOCAL_SHARED_LIBRARIES += libziparchive-host libz-host
+      # For ashmem_create_region.
+      LOCAL_SHARED_LIBRARIES += libcutils
+    endif
   endif
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $$(LOCAL_PATH)/Android.mk
@@ -499,7 +519,11 @@
     endif
     include $$(BUILD_SHARED_LIBRARY)
   else # host
-    include $$(BUILD_HOST_SHARED_LIBRARY)
+    ifeq ($$(art_static_or_shared),static)
+      include $$(BUILD_HOST_STATIC_LIBRARY)
+    else
+      include $$(BUILD_HOST_SHARED_LIBRARY)
+    endif
   endif
 
   # Clear locally defined variables.
@@ -508,15 +532,22 @@
   ENUM_OPERATOR_OUT_GEN :=
   art_target_or_host :=
   art_ndebug_or_debug :=
+  art_static_or_shared :=
 endef
 
 # We always build dex2oat and dependencies, even if the host build is otherwise disabled, since
 # they are used to cross compile for the target.
 ifeq ($(ART_BUILD_HOST_NDEBUG),true)
   $(eval $(call build-libart,host,ndebug))
+  ifeq ($(ART_BUILD_HOST_STATIC),true)
+    $(eval $(call build-libart,host,ndebug,static))
+  endif
 endif
 ifeq ($(ART_BUILD_HOST_DEBUG),true)
   $(eval $(call build-libart,host,debug))
+  ifeq ($(ART_BUILD_HOST_STATIC),true)
+    $(eval $(call build-libart,host,debug,static))
+  endif
 endif
 
 ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index ca3ca1d..068f458 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -325,25 +325,25 @@
      * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
      * pointing back to the original caller.
      */
-.macro INVOKE_TRAMPOLINE c_name, cxx_name
+.macro INVOKE_TRAMPOLINE_BODY cxx_name
     .extern \cxx_name
-ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case allocation triggers GC
     mov    r2, r9                         @ pass Thread::Current
     mov    r3, sp
-    .cfi_adjust_cfa_offset 16
-    bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
-    .cfi_adjust_cfa_offset -16
+    bl     \cxx_name                      @ (method_idx, this, Thread*, SP)
     mov    r12, r1                        @ save Method*->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     cbz    r0, 1f                         @ did we find the target? if not go to exception delivery
     bx     r12                            @ tail call to target
 1:
     DELIVER_PENDING_EXCEPTION
+.endm
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ENTRY \c_name
+    INVOKE_TRAMPOLINE_BODY \cxx_name
 END \c_name
 .endm
 
-INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
@@ -896,7 +896,7 @@
      */
 ENTRY art_quick_imt_conflict_trampoline
     mov    r0, r12
-    b art_quick_invoke_interface_trampoline
+    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 614936b..6d9b44a 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -450,9 +450,8 @@
      *
      * Clobbers xIP0.
      */
-.macro INVOKE_TRAMPOLINE c_name, cxx_name
+.macro INVOKE_TRAMPOLINE_BODY cxx_name
     .extern \cxx_name
-ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
@@ -466,10 +465,13 @@
     br     xIP0                           // tail call to target
 1:
     DELIVER_PENDING_EXCEPTION
+.endm
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ENTRY \c_name
+    INVOKE_TRAMPOLINE_BODY \cxx_name
 END \c_name
 .endm
 
-INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
@@ -1429,9 +1431,10 @@
      * Called to resolve an imt conflict. xIP1 is a hidden argument that holds the target method's
      * dex method index.
      */
+    .extern artInvokeInterfaceTrampoline
 ENTRY art_quick_imt_conflict_trampoline
     mov    x0, xIP1
-    b art_quick_invoke_interface_trampoline
+    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
 END art_quick_imt_conflict_trampoline
 
 ENTRY art_quick_resolution_trampoline
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index ff04106..09a018e 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -267,6 +267,10 @@
   qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;
   static_assert(!IsDirectEntrypoint(kQuickThrowStackOverflow), "Non-direct C stub marked direct.");
 
+  // Deoptimize
+  qpoints->pDeoptimize = art_quick_deoptimize;
+  static_assert(!IsDirectEntrypoint(kQuickDeoptimize), "Non-direct C stub marked direct.");
+
   // Atomic 64-bit load/store
   qpoints->pA64Load = QuasiAtomic::Read64;
   static_assert(IsDirectEntrypoint(kQuickA64Load), "Non-direct C stub marked direct.");
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index abe495b..8ea78eb 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -17,11 +17,17 @@
 
 #include "fault_handler.h"
 #include <sys/ucontext.h>
+#include "art_method-inl.h"
 #include "base/macros.h"
 #include "globals.h"
 #include "base/logging.h"
 #include "base/hex_dump.h"
+#include "registers_mips.h"
+#include "thread.h"
+#include "thread-inl.h"
 
+extern "C" void art_quick_throw_stack_overflow();
+extern "C" void art_quick_throw_null_pointer_exception();
 
 //
 // Mips specific fault handler functions.
@@ -33,16 +39,52 @@
                                       void* context ATTRIBUTE_UNUSED) {
 }
 
-void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED,
-                                             void* context ATTRIBUTE_UNUSED,
-                                             ArtMethod** out_method ATTRIBUTE_UNUSED,
-                                             uintptr_t* out_return_pc ATTRIBUTE_UNUSED,
-                                             uintptr_t* out_sp ATTRIBUTE_UNUSED) {
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
+                                             ArtMethod** out_method,
+                                             uintptr_t* out_return_pc, uintptr_t* out_sp) {
+  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  *out_sp = static_cast<uintptr_t>(sc->sc_regs[29]);   // SP register
+  VLOG(signals) << "sp: " << *out_sp;
+  if (*out_sp == 0) {
+    return;
+  }
+
+  // In the case of a stack overflow, the stack is not valid and we can't
+  // get the method from the top of the stack.  However it's in r0.
+  uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);  // BVA addr
+  uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
+      reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kMips));
+  if (overflow_addr == fault_addr) {
+    *out_method = reinterpret_cast<ArtMethod*>(sc->sc_regs[4]);  // A0 register
+  } else {
+    // The method is at the top of the stack.
+    *out_method = *reinterpret_cast<ArtMethod**>(*out_sp);
+  }
+
+  // Work out the return PC.  This will be the address of the instruction
+  // following the faulting ldr/str instruction.
+
+  VLOG(signals) << "pc: " << std::hex
+      << static_cast<void*>(reinterpret_cast<uint8_t*>(sc->sc_pc));
+
+  *out_return_pc = sc->sc_pc + 4;
 }
 
 bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
-                                void* context ATTRIBUTE_UNUSED) {
-  return false;
+                                void* context) {
+  // The code that looks for the catch location needs to know the value of the
+  // PC at the point of call.  For Null checks we insert a GC map that is immediately after
+  // the load/store instruction that might cause the fault.
+
+  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+
+  sc->sc_regs[31] = sc->sc_pc + 4;      // RA needs to point to gc map location
+  sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception);
+  sc->sc_regs[25] = sc->sc_pc;          // make sure T9 points to the function
+  VLOG(signals) << "Generating null pointer exception";
+  return true;
 }
 
 bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
@@ -50,8 +92,51 @@
   return false;
 }
 
-bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
-                                  void* context ATTRIBUTE_UNUSED) {
-  return false;
+// Stack overflow fault handler.
+//
+// This checks that the fault address is equal to the current stack pointer
+// minus the overflow region size (16K typically). The instruction that
+// generates this signal is:
+//
+// lw zero, -16384(sp)
+//
+// It will fault if sp is inside the protected region on the stack.
+//
+// If we determine this is a stack overflow we need to move the stack pointer
+// to the overflow region below the protected region.
+
+bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info, void* context) {
+  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
+  VLOG(signals) << "sigcontext: " << std::hex << sc;
+
+  uintptr_t sp = sc->sc_regs[29];  // SP register
+  VLOG(signals) << "sp: " << std::hex << sp;
+
+  uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);  // BVA addr
+  VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
+  VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
+    ", fault_addr: " << fault_addr;
+
+  uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kMips);
+
+  // Check that the fault address is the value expected for a stack overflow.
+  if (fault_addr != overflow_addr) {
+    VLOG(signals) << "Not a stack overflow";
+    return false;
+  }
+
+  VLOG(signals) << "Stack overflow found";
+
+  // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from.
+  // The value of RA must be the same as it was when we entered the code that
+  // caused this fault.  This will be inserted into a callee save frame by
+  // the function to which this handler returns (art_quick_throw_stack_overflow).
+  sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
+  sc->sc_regs[25] = sc->sc_pc;          // make sure T9 points to the function
+
+  // The kernel will now return to the address in sc->arm_pc.
+  return true;
 }
 }       // namespace art
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index cc1de43..2819f92 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -459,9 +459,8 @@
      * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
      * pointing back to the original caller.
      */
-.macro INVOKE_TRAMPOLINE c_name, cxx_name
+.macro INVOKE_TRAMPOLINE_BODY cxx_name
     .extern \cxx_name
-ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
     move  $a2, rSELF                       # pass Thread::Current
     jal   \cxx_name                        # (method_idx, this, Thread*, $sp)
@@ -474,10 +473,13 @@
     nop
 1:
     DELIVER_PENDING_EXCEPTION
+.endm
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ENTRY \c_name
+    INVOKE_TRAMPOLINE_BODY \cxx_name
 END \c_name
 .endm
 
-INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
@@ -1103,9 +1105,8 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    la      $t9, art_quick_invoke_interface_trampoline
-    jalr    $zero, $t9
     move    $a0, $t0
+    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc
index 321c27b..4904af9 100644
--- a/runtime/arch/mips64/entrypoints_init_mips64.cc
+++ b/runtime/arch/mips64/entrypoints_init_mips64.cc
@@ -176,6 +176,9 @@
   qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception;
   qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;
 
+  // Deoptimize
+  qpoints->pDeoptimize = art_quick_deoptimize;
+
   // TODO - use lld/scd instructions for Mips64
   // Atomic 64-bit load/store
   qpoints->pA64Load = QuasiAtomic::Read64;
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index 277c2b2..4abfcf1 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -17,11 +17,17 @@
 
 #include "fault_handler.h"
 #include <sys/ucontext.h>
+#include "art_method-inl.h"
 #include "base/macros.h"
 #include "globals.h"
 #include "base/logging.h"
 #include "base/hex_dump.h"
+#include "registers_mips64.h"
+#include "thread.h"
+#include "thread-inl.h"
 
+extern "C" void art_quick_throw_stack_overflow();
+extern "C" void art_quick_throw_null_pointer_exception();
 
 //
 // Mips64 specific fault handler functions.
@@ -33,16 +39,52 @@
                                       void* context ATTRIBUTE_UNUSED) {
 }
 
-void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED,
-                                             void* context ATTRIBUTE_UNUSED,
-                                             ArtMethod** out_method ATTRIBUTE_UNUSED,
-                                             uintptr_t* out_return_pc ATTRIBUTE_UNUSED,
-                                             uintptr_t* out_sp ATTRIBUTE_UNUSED) {
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
+                                             ArtMethod** out_method,
+                                             uintptr_t* out_return_pc, uintptr_t* out_sp) {
+  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  *out_sp = static_cast<uintptr_t>(sc->sc_regs[29]);   // SP register
+  VLOG(signals) << "sp: " << *out_sp;
+  if (*out_sp == 0) {
+    return;
+  }
+
+  // In the case of a stack overflow, the stack is not valid and we can't
+  // get the method from the top of the stack.  However it's in r0.
+  uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);  // BVA addr
+  uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
+      reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kMips64));
+  if (overflow_addr == fault_addr) {
+    *out_method = reinterpret_cast<ArtMethod*>(sc->sc_regs[4]);  // A0 register
+  } else {
+    // The method is at the top of the stack.
+    *out_method = *reinterpret_cast<ArtMethod**>(*out_sp);
+  }
+
+  // Work out the return PC.  This will be the address of the instruction
+  // following the faulting ldr/str instruction.
+
+  VLOG(signals) << "pc: " << std::hex
+      << static_cast<void*>(reinterpret_cast<uint8_t*>(sc->sc_pc));
+
+  *out_return_pc = sc->sc_pc + 4;
 }
 
 bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
-                                void* context ATTRIBUTE_UNUSED) {
-  return false;
+                                void* context) {
+  // The code that looks for the catch location needs to know the value of the
+  // PC at the point of call.  For Null checks we insert a GC map that is immediately after
+  // the load/store instruction that might cause the fault.
+
+  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+
+  sc->sc_regs[31] = sc->sc_pc + 4;      // RA needs to point to gc map location
+  sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception);
+  sc->sc_regs[25] = sc->sc_pc;          // make sure T9 points to the function
+  VLOG(signals) << "Generating null pointer exception";
+  return true;
 }
 
 bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
@@ -50,8 +92,51 @@
   return false;
 }
 
-bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
-                                  void* context ATTRIBUTE_UNUSED) {
-  return false;
+// Stack overflow fault handler.
+//
+// This checks that the fault address is equal to the current stack pointer
+// minus the overflow region size (16K typically). The instruction that
+// generates this signal is:
+//
+// lw zero, -16384(sp)
+//
+// It will fault if sp is inside the protected region on the stack.
+//
+// If we determine this is a stack overflow we need to move the stack pointer
+// to the overflow region below the protected region.
+
+bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info, void* context) {
+  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
+  VLOG(signals) << "sigcontext: " << std::hex << sc;
+
+  uintptr_t sp = sc->sc_regs[29];  // SP register
+  VLOG(signals) << "sp: " << std::hex << sp;
+
+  uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);  // BVA addr
+  VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
+  VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
+    ", fault_addr: " << fault_addr;
+
+  uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kMips64);
+
+  // Check that the fault address is the value expected for a stack overflow.
+  if (fault_addr != overflow_addr) {
+    VLOG(signals) << "Not a stack overflow";
+    return false;
+  }
+
+  VLOG(signals) << "Stack overflow found";
+
+  // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from.
+  // The value of RA must be the same as it was when we entered the code that
+  // caused this fault.  This will be inserted into a callee save frame by
+  // the function to which this handler returns (art_quick_throw_stack_overflow).
+  sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
+  sc->sc_regs[25] = sc->sc_pc;          // make sure T9 points to the function
+
+  // The kernel will now return to the address in sc->arm_pc.
+  return true;
 }
 }       // namespace art
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 37c6c5b..abca70b 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -525,9 +525,8 @@
      * On success this wrapper will restore arguments and *jump* to the target, leaving the ra
      * pointing back to the original caller.
      */
-.macro INVOKE_TRAMPOLINE c_name, cxx_name
+.macro INVOKE_TRAMPOLINE_BODY cxx_name
     .extern \cxx_name
-ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
     move  $a2, rSELF                       # pass Thread::Current
     jal   \cxx_name                        # (method_idx, this, Thread*, $sp)
@@ -541,10 +540,13 @@
     nop
 1:
     DELIVER_PENDING_EXCEPTION
+.endm
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ENTRY \c_name
+    INVOKE_TRAMPOLINE_BODY \cxx_name
 END \c_name
 .endm
 
-INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
@@ -1369,10 +1371,8 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    dla     $t9, art_quick_invoke_interface_trampoline
-    .cpreturn
-    jalr    $zero, $t9
     move    $a0, $t0
+    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
diff --git a/runtime/arch/x86/jni_entrypoints_x86.S b/runtime/arch/x86/jni_entrypoints_x86.S
index 5d27e47..aca5a37 100644
--- a/runtime/arch/x86/jni_entrypoints_x86.S
+++ b/runtime/arch/x86/jni_entrypoints_x86.S
@@ -23,6 +23,7 @@
     subl LITERAL(8), %esp         // align stack
     CFI_ADJUST_CFA_OFFSET(8)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    CFI_ADJUST_CFA_OFFSET(4)
     call SYMBOL(artFindNativeMethod)  // (Thread*)
     addl LITERAL(12), %esp        // remove argument & padding
     CFI_ADJUST_CFA_OFFSET(-12)
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index c9bc977..7086b5b 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -293,8 +293,7 @@
      * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
      * pointing back to the original caller.
      */
-MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
-    DEFINE_FUNCTION RAW_VAR(c_name, 0)
+MACRO1(INVOKE_TRAMPOLINE_BODY, cxx_name)
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME ebx, ebx
     movl %esp, %edx  // remember SP
 
@@ -304,7 +303,7 @@
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ecx                      // pass arg2
     PUSH eax                      // pass arg1
-    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, Thread*, SP)
+    call VAR(cxx_name, 0)         // cxx_name(arg1, arg2, arg3, Thread*, SP)
     movl %edx, %edi               // save code pointer in EDI
     addl MACRO_LITERAL(20), %esp  // Pop arguments skip eax
     CFI_ADJUST_CFA_OFFSET(-20)
@@ -334,10 +333,13 @@
     addl MACRO_LITERAL(4), %esp   // Pop code pointer off stack
     CFI_ADJUST_CFA_OFFSET(-4)
     DELIVER_PENDING_EXCEPTION
+END_MACRO
+MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
+    INVOKE_TRAMPOLINE_BODY RAW_VAR(cxx_name, 1)
     END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
-INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
@@ -1111,7 +1113,7 @@
     POP eax                       // pop arguments
     POP ecx
     addl LITERAL(4), %esp
-    CFI_ADJUST_CFA_OFFSET(-12)
+    CFI_ADJUST_CFA_OFFSET(-4)
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  ebx, ebx  // save all registers as basis for long jump context
     // Outgoing argument set up
     PUSH eax                      // alignment padding
@@ -1183,8 +1185,8 @@
     PUSH eax
 #else
     pushl MIRROR_OBJECT_CLASS_OFFSET(%edx)  // pass arg2 - type of the value to be stored
-#endif
     CFI_ADJUST_CFA_OFFSET(4)
+#endif
     PUSH ebx                      // pass arg1 - component type of the array
     call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
     addl LITERAL(16), %esp        // pop arguments
@@ -1415,7 +1417,7 @@
      */
 DEFINE_FUNCTION art_quick_imt_conflict_trampoline
     movd %xmm7, %eax              // get target method index stored in xmm7
-    jmp SYMBOL(art_quick_invoke_interface_trampoline)
+    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
 END_FUNCTION art_quick_imt_conflict_trampoline
 
 DEFINE_FUNCTION art_quick_resolution_trampoline
@@ -1429,6 +1431,7 @@
     call SYMBOL(artQuickResolutionTrampoline) // (Method* called, receiver, Thread*, SP)
     movl %eax, %edi               // remember code pointer in EDI
     addl LITERAL(16), %esp        // pop arguments
+    CFI_ADJUST_CFA_OFFSET(-16)
     test %eax, %eax               // if code pointer is null goto deliver pending exception
     jz 1f
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME_AND_JUMP
@@ -1559,6 +1562,7 @@
     PUSH eax                      // Pass Method*.
     call SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, LR)
     addl LITERAL(28), %esp        // Pop arguments upto saved Method*.
+    CFI_ADJUST_CFA_OFFSET(-28)
     movl 60(%esp), %edi           // Restore edi.
     movl %eax, 60(%esp)           // Place code* over edi, just under return pc.
     movl SYMBOL(art_quick_instrumentation_exit)@GOT(%ebx), %ebx
@@ -1578,11 +1582,13 @@
     movl 52(%esp), %ebp           // Restore ebp.
     movl 56(%esp), %esi           // Restore esi.
     addl LITERAL(60), %esp        // Wind stack back upto code*.
+    CFI_ADJUST_CFA_OFFSET(-60)
     ret                           // Call method (and pop).
 END_FUNCTION art_quick_instrumentation_entry
 
 DEFINE_FUNCTION art_quick_instrumentation_exit
     pushl LITERAL(0)              // Push a fake return PC as there will be none on the stack.
+    CFI_ADJUST_CFA_OFFSET(4)
     SETUP_REFS_ONLY_CALLEE_SAVE_FRAME ebx, ebx
     mov  %esp, %ecx               // Remember SP
     subl LITERAL(8), %esp         // Save float return value.
@@ -1611,6 +1617,7 @@
     CFI_ADJUST_CFA_OFFSET(-8)
     RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
     addl LITERAL(4), %esp         // Remove fake return pc.
+    CFI_ADJUST_CFA_OFFSET(-4)
     jmp   *%ecx                   // Return.
 END_FUNCTION art_quick_instrumentation_exit
 
@@ -1619,7 +1626,7 @@
      * will long jump to the upcall with a special exception of -1.
      */
 DEFINE_FUNCTION art_quick_deoptimize
-    pushl %ebx                    // Entry point for a jump. Fake that we were called.
+    PUSH ebx                      // Entry point for a jump. Fake that we were called.
 .globl SYMBOL(art_quick_deoptimize_from_compiled_slow_path)  // Entry point for real calls
                                                              // from compiled slow paths.
 SYMBOL(art_quick_deoptimize_from_compiled_slow_path):
@@ -1682,8 +1689,8 @@
 DEFINE_FUNCTION art_nested_signal_return
     SETUP_GOT_NOSAVE ebx            // sets %ebx for call into PLT
     movl LITERAL(1), %ecx
-    pushl %ecx                      // second arg to longjmp (1)
-    pushl %eax                      // first arg to longjmp (jmp_buf)
+    PUSH ecx                        // second arg to longjmp (1)
+    PUSH eax                        // first arg to longjmp (jmp_buf)
     call PLT_SYMBOL(longjmp)
     int3                            // won't get here.
 END_FUNCTION art_nested_signal_return
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 7d86c3a..ad89bca 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -353,8 +353,7 @@
      *
      * Adapted from x86 code.
      */
-MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
-    DEFINE_FUNCTION VAR(c_name, 0)
+MACRO1(INVOKE_TRAMPOLINE_BODY, cxx_name)
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
@@ -362,7 +361,7 @@
     movq %gs:THREAD_SELF_OFFSET, %rdx                      // pass Thread
     movq %rsp, %rcx                                        // pass SP
 
-    call VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, Thread*, SP)
+    call VAR(cxx_name, 0)                   // cxx_name(arg1, arg2, Thread*, SP)
                                                            // save the code pointer
     movq %rax, %rdi
     movq %rdx, %rax
@@ -375,10 +374,13 @@
     jmp *%rax
 1:
     DELIVER_PENDING_EXCEPTION
-    END_FUNCTION VAR(c_name, 0)
+END_MACRO
+MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
+    DEFINE_FUNCTION RAW_VAR(c_name, 0)
+    INVOKE_TRAMPOLINE_BODY RAW_VAR(cxx_name, 1)
+    END_FUNCTION RAW_VAR(c_name, 0)
 END_MACRO
 
-INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
 
 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
@@ -1352,7 +1354,7 @@
     int3
 #else
     movq %rax, %rdi
-    jmp art_quick_invoke_interface_trampoline
+    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
 #endif  // __APPLE__
 END_FUNCTION art_quick_imt_conflict_trampoline
 
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 4a1e2c4..e8c47d9 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -43,9 +43,6 @@
 class PointerArray;
 }  // namespace mirror
 
-typedef void (EntryPointFromInterpreter)(Thread* self, const DexFile::CodeItem* code_item,
-                                         ShadowFrame* shadow_frame, JValue* result);
-
 class ArtMethod FINAL {
  public:
   ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0),
@@ -272,23 +269,6 @@
   void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  EntryPointFromInterpreter* GetEntryPointFromInterpreter() {
-    return GetEntryPointFromInterpreterPtrSize(sizeof(void*));
-  }
-  EntryPointFromInterpreter* GetEntryPointFromInterpreterPtrSize(size_t pointer_size) {
-    return GetEntryPoint<EntryPointFromInterpreter*>(
-        EntryPointFromInterpreterOffset(pointer_size), pointer_size);
-  }
-
-  void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) {
-    SetEntryPointFromInterpreterPtrSize(entry_point_from_interpreter, sizeof(void*));
-  }
-  void SetEntryPointFromInterpreterPtrSize(EntryPointFromInterpreter* entry_point_from_interpreter,
-                                           size_t pointer_size) {
-    SetEntryPoint(EntryPointFromInterpreterOffset(pointer_size), entry_point_from_interpreter,
-                  pointer_size);
-  }
-
   const void* GetEntryPointFromQuickCompiledCode() {
     return GetEntryPointFromQuickCompiledCodePtrSize(sizeof(void*));
   }
@@ -398,11 +378,6 @@
 
   void UnregisterNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static MemberOffset EntryPointFromInterpreterOffset(size_t pointer_size) {
-    return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
-        PtrSizedFields, entry_point_from_interpreter_) / sizeof(void*) * pointer_size);
-  }
-
   static MemberOffset EntryPointFromJniOffset(size_t pointer_size) {
     return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
         PtrSizedFields, entry_point_from_jni_) / sizeof(void*) * pointer_size);
@@ -573,10 +548,6 @@
   // PACKED(4) is necessary for the correctness of
   // RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size).
   struct PACKED(4) PtrSizedFields {
-    // Method dispatch from the interpreter invokes this pointer which may cause a bridge into
-    // compiled code.
-    void* entry_point_from_interpreter_;
-
     // Pointer to JNI function registered to this method, or a function to resolve the JNI function.
     void* entry_point_from_jni_;
 
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 10ed0f4..b1d0841 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -89,7 +89,7 @@
             art::Thread::ThinLockIdOffset<__SIZEOF_POINTER__>().Int32Value())
 
 // Offset of field Thread::tlsPtr_.card_table.
-#define THREAD_CARD_TABLE_OFFSET 128
+#define THREAD_CARD_TABLE_OFFSET 136
 ADD_TEST_EQ(THREAD_CARD_TABLE_OFFSET,
             art::Thread::CardTableOffset<__SIZEOF_POINTER__>().Int32Value())
 
@@ -108,7 +108,7 @@
 ADD_TEST_EQ(THREAD_SELF_OFFSET,
             art::Thread::SelfOffset<__SIZEOF_POINTER__>().Int32Value())
 
-#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 147 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 150 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
             art::Thread::ThreadLocalPosOffset<__SIZEOF_POINTER__>().Int32Value())
 #define THREAD_LOCAL_END_OFFSET (THREAD_LOCAL_POS_OFFSET + __SIZEOF_POINTER__)
@@ -189,11 +189,11 @@
 ADD_TEST_EQ(ART_METHOD_DEX_CACHE_TYPES_OFFSET,
             art::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())
 
-#define ART_METHOD_QUICK_CODE_OFFSET_32 36
+#define ART_METHOD_QUICK_CODE_OFFSET_32 32
 ADD_TEST_EQ(ART_METHOD_QUICK_CODE_OFFSET_32,
             art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value())
 
-#define ART_METHOD_QUICK_CODE_OFFSET_64 48
+#define ART_METHOD_QUICK_CODE_OFFSET_64 40
 ADD_TEST_EQ(ART_METHOD_QUICK_CODE_OFFSET_64,
             art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(8).Int32Value())
 
diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc
index 8f2d94b..e5832e1 100644
--- a/runtime/base/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -23,11 +23,11 @@
 #include "mem_map.h"
 #include "mutex.h"
 #include "thread-inl.h"
-#include <memcheck/memcheck.h>
+#include "base/memory_tool.h"
 
 namespace art {
 
-static constexpr size_t kValgrindRedZoneBytes = 8;
+static constexpr size_t kMemoryToolRedZoneBytes = 8;
 constexpr size_t Arena::kDefaultSize;
 
 template <bool kCount>
@@ -217,9 +217,9 @@
 }
 
 void ArenaPool::FreeArenaChain(Arena* first) {
-  if (UNLIKELY(RUNNING_ON_VALGRIND > 0)) {
+  if (UNLIKELY(RUNNING_ON_MEMORY_TOOL > 0)) {
     for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
-      VALGRIND_MAKE_MEM_UNDEFINED(arena->memory_, arena->bytes_allocated_);
+      MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
     }
   }
   if (first != nullptr) {
@@ -255,7 +255,7 @@
     end_(nullptr),
     ptr_(nullptr),
     arena_head_(nullptr),
-    running_on_valgrind_(RUNNING_ON_VALGRIND > 0) {
+    is_running_on_memory_tool_(RUNNING_ON_MEMORY_TOOL) {
 }
 
 void ArenaAllocator::UpdateBytesAllocated() {
@@ -267,7 +267,7 @@
 }
 
 void* ArenaAllocator::AllocValgrind(size_t bytes, ArenaAllocKind kind) {
-  size_t rounded_bytes = RoundUp(bytes + kValgrindRedZoneBytes, 8);
+  size_t rounded_bytes = RoundUp(bytes + kMemoryToolRedZoneBytes, 8);
   if (UNLIKELY(ptr_ + rounded_bytes > end_)) {
     // Obtain a new block.
     ObtainNewArenaForAllocation(rounded_bytes);
@@ -282,7 +282,7 @@
   for (uint8_t* ptr = ret; ptr < ptr_; ++ptr) {
     CHECK_EQ(*ptr, 0U);
   }
-  VALGRIND_MAKE_MEM_NOACCESS(ret + bytes, rounded_bytes - bytes);
+  MEMORY_TOOL_MAKE_NOACCESS(ret + bytes, rounded_bytes - bytes);
   return ret;
 }
 
diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h
index d9723b5..d977941 100644
--- a/runtime/base/arena_allocator.h
+++ b/runtime/base/arena_allocator.h
@@ -207,7 +207,7 @@
 
   // Returns zeroed memory.
   void* Alloc(size_t bytes, ArenaAllocKind kind = kArenaAllocMisc) ALWAYS_INLINE {
-    if (UNLIKELY(running_on_valgrind_)) {
+    if (UNLIKELY(is_running_on_memory_tool_)) {
       return AllocValgrind(bytes, kind);
     }
     bytes = RoundUp(bytes, kAlignment);
@@ -280,7 +280,7 @@
   uint8_t* end_;
   uint8_t* ptr_;
   Arena* arena_head_;
-  bool running_on_valgrind_;
+  bool is_running_on_memory_tool_;
 
   template <typename U>
   friend class ArenaAllocatorAdapter;
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 7972158..6f45dc8 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -137,7 +137,7 @@
 }
 
 template<int n, typename T>
-static inline bool IsAligned(T x) {
+static constexpr bool IsAligned(T x) {
   static_assert((n & (n - 1)) == 0, "n is not a power of two");
   return (x & (n - 1)) == 0;
 }
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index aba3762..03980e3 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -66,7 +66,7 @@
   while (max_ < new_max) {
     // If we have reached the maximum number of buckets, merge buckets together.
     if (frequency_.size() >= max_buckets_) {
-      CHECK(IsAligned<2>(frequency_.size()));
+      CHECK_ALIGNED(frequency_.size(), 2);
       // We double the width of each bucket to reduce the number of buckets by a factor of 2.
       bucket_width_ *= 2;
       const size_t limit = frequency_.size() / 2;
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 35b50d1..93d4edc 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -17,7 +17,6 @@
 #ifndef ART_RUNTIME_BASE_LOGGING_H_
 #define ART_RUNTIME_BASE_LOGGING_H_
 
-#include <memory>
 #include <ostream>
 
 #include "base/macros.h"
diff --git a/runtime/base/memory_tool.h b/runtime/base/memory_tool.h
new file mode 100644
index 0000000..e0bdcfe
--- /dev/null
+++ b/runtime/base/memory_tool.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 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_RUNTIME_BASE_MEMORY_TOOL_H_
+#define ART_RUNTIME_BASE_MEMORY_TOOL_H_
+
+#include <stddef.h>
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(address_sanitizer)
+
+#include <sanitizer/asan_interface.h>
+#define ADDRESS_SANITIZER
+
+#ifdef ART_ENABLE_ADDRESS_SANITIZER
+#define MEMORY_TOOL_MAKE_NOACCESS(p, s) __asan_poison_memory_region(p, s)
+#define MEMORY_TOOL_MAKE_UNDEFINED(p, s) __asan_unpoison_memory_region(p, s)
+#define MEMORY_TOOL_MAKE_DEFINED(p, s) __asan_unpoison_memory_region(p, s)
+#else
+#define MEMORY_TOOL_MAKE_NOACCESS(p, s) do { (void)(p); (void)(s); } while (0)
+#define MEMORY_TOOL_MAKE_UNDEFINED(p, s) do { (void)(p); (void)(s); } while (0)
+#define MEMORY_TOOL_MAKE_DEFINED(p, s) do { (void)(p); (void)(s); } while (0)
+#endif
+
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#define RUNNING_ON_MEMORY_TOOL 1U
+constexpr bool kMemoryToolIsValgrind = false;
+constexpr bool kMemoryToolDetectsLeaks = true;
+constexpr bool kMemoryToolAddsRedzones = true;
+constexpr size_t kMemoryToolStackGuardSizeScale = 2;
+
+#else
+
+#include <valgrind.h>
+#include <memcheck/memcheck.h>
+#define MEMORY_TOOL_MAKE_NOACCESS(p, s) VALGRIND_MAKE_MEM_NOACCESS(p, s)
+#define MEMORY_TOOL_MAKE_UNDEFINED(p, s) VALGRIND_MAKE_MEM_UNDEFINED(p, s)
+#define MEMORY_TOOL_MAKE_DEFINED(p, s) VALGRIND_MAKE_MEM_DEFINED(p, s)
+#define ATTRIBUTE_NO_SANITIZE_ADDRESS
+#define RUNNING_ON_MEMORY_TOOL RUNNING_ON_VALGRIND
+constexpr bool kMemoryToolIsValgrind = true;
+constexpr bool kMemoryToolDetectsLeaks = true;
+constexpr bool kMemoryToolAddsRedzones = true;
+constexpr size_t kMemoryToolStackGuardSizeScale = 1;
+
+#endif
+
+#endif  // ART_RUNTIME_BASE_MEMORY_TOOL_H_
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 87840e7..bd8de87 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -218,6 +218,16 @@
 #endif
 }
 
+inline void MutatorMutex::TransitionFromRunnableToSuspended(Thread* self) {
+  AssertSharedHeld(self);
+  RegisterAsUnlocked(self);
+}
+
+inline void MutatorMutex::TransitionFromSuspendedToRunnable(Thread* self) {
+  RegisterAsLocked(self);
+  AssertSharedHeld(self);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_BASE_MUTEX_INL_H_
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 5c6065d..e48d170 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -47,7 +47,7 @@
 Mutex* Locks::logging_lock_ = nullptr;
 Mutex* Locks::mem_maps_lock_ = nullptr;
 Mutex* Locks::modify_ldt_lock_ = nullptr;
-ReaderWriterMutex* Locks::mutator_lock_ = nullptr;
+MutatorMutex* Locks::mutator_lock_ = nullptr;
 Mutex* Locks::profiler_lock_ = nullptr;
 Mutex* Locks::reference_processor_lock_ = nullptr;
 Mutex* Locks::reference_queue_cleared_references_lock_ = nullptr;
@@ -738,6 +738,11 @@
   return os;
 }
 
+std::ostream& operator<<(std::ostream& os, const MutatorMutex& mu) {
+  mu.Dump(os);
+  return os;
+}
+
 ConditionVariable::ConditionVariable(const char* name, Mutex& guard)
     : name_(name), guard_(guard) {
 #if ART_USE_FUTEXES
@@ -958,7 +963,7 @@
 
     UPDATE_CURRENT_LOCK_LEVEL(kMutatorLock);
     DCHECK(mutator_lock_ == nullptr);
-    mutator_lock_ = new ReaderWriterMutex("mutator lock", current_lock_level);
+    mutator_lock_ = new MutatorMutex("mutator lock", current_lock_level);
 
     UPDATE_CURRENT_LOCK_LEVEL(kHeapBitmapLock);
     DCHECK(heap_bitmap_lock_ == nullptr);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 678d55b..f87467a 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -44,6 +44,7 @@
 namespace art {
 
 class LOCKABLE ReaderWriterMutex;
+class LOCKABLE MutatorMutex;
 class ScopedContentionRecorder;
 class Thread;
 
@@ -138,6 +139,7 @@
 
   virtual bool IsMutex() const { return false; }
   virtual bool IsReaderWriterMutex() const { return false; }
+  virtual bool IsMutatorMutex() const { return false; }
 
   virtual void Dump(std::ostream& os) const = 0;
 
@@ -385,6 +387,36 @@
   DISALLOW_COPY_AND_ASSIGN(ReaderWriterMutex);
 };
 
+// MutatorMutex is a special kind of ReaderWriterMutex created specifically for the
+// Locks::mutator_lock_ mutex. The behaviour is identical to the ReaderWriterMutex except that
+// thread state changes also play a part in lock ownership. The mutator_lock_ will not be truly
+// held by any mutator threads. However, a thread in the kRunnable state is considered to have
+// shared ownership of the mutator lock and therefore transitions in and out of the kRunnable
+// state have associated implications on lock ownership. Extra methods to handle the state
+// transitions have been added to the interface but are only accessible to the methods dealing
+// with state transitions. The thread state and flags attributes are used to ensure thread state
+// transitions are consistent with the permitted behaviour of the mutex.
+//
+// *) The most important consequence of this behaviour is that all threads must be in one of the
+// suspended states before exclusive ownership of the mutator mutex is sought.
+//
+std::ostream& operator<<(std::ostream& os, const MutatorMutex& mu);
+class LOCKABLE MutatorMutex : public ReaderWriterMutex {
+ public:
+  explicit MutatorMutex(const char* name, LockLevel level = kDefaultMutexLevel)
+    : ReaderWriterMutex(name, level) {}
+  ~MutatorMutex() {}
+
+  virtual bool IsMutatorMutex() const { return true; }
+
+ private:
+  friend class Thread;
+  void TransitionFromRunnableToSuspended(Thread* self) UNLOCK_FUNCTION() ALWAYS_INLINE;
+  void TransitionFromSuspendedToRunnable(Thread* self) SHARED_LOCK_FUNCTION() ALWAYS_INLINE;
+
+  DISALLOW_COPY_AND_ASSIGN(MutatorMutex);
+};
+
 // ConditionVariables allow threads to queue and sleep. Threads may then be resumed individually
 // (Signal) or all at once (Broadcast).
 class ConditionVariable {
@@ -495,35 +527,28 @@
   // Guards allocation entrypoint instrumenting.
   static Mutex* instrument_entrypoints_lock_;
 
-  // The mutator_lock_ is used to allow mutators to execute in a shared (reader) mode or to block
-  // mutators by having an exclusive (writer) owner. In normal execution each mutator thread holds
-  // a share on the mutator_lock_. The garbage collector may also execute with shared access but
-  // at times requires exclusive access to the heap (not to be confused with the heap meta-data
-  // guarded by the heap_lock_ below). When the garbage collector requires exclusive access it asks
-  // the mutators to suspend themselves which also involves usage of the thread_suspend_count_lock_
-  // to cover weaknesses in using ReaderWriterMutexes with ConditionVariables. We use a condition
-  // variable to wait upon in the suspension logic as releasing and then re-acquiring a share on
-  // the mutator lock doesn't necessarily allow the exclusive user (e.g the garbage collector)
-  // chance to acquire the lock.
+  // A barrier is used to synchronize the GC/Debugger thread with mutator threads. When GC/Debugger
+  // thread wants to suspend all mutator threads, it needs to wait for all mutator threads to pass
+  // a barrier. Threads that are already suspended will get their barrier passed by the GC/Debugger
+  // thread; threads in the runnable state will pass the barrier when they transit to the suspended
+  // state. GC/Debugger thread will be woken up when all mutator threads are suspended.
   //
   // Thread suspension:
-  // Shared users                                  | Exclusive user
-  // (holding mutator lock and in kRunnable state) |   .. running ..
+  // mutator thread                                | GC/Debugger
+  //   .. running ..                               |   .. running ..
   //   .. running ..                               | Request thread suspension by:
   //   .. running ..                               |   - acquiring thread_suspend_count_lock_
   //   .. running ..                               |   - incrementing Thread::suspend_count_ on
   //   .. running ..                               |     all mutator threads
   //   .. running ..                               |   - releasing thread_suspend_count_lock_
-  //   .. running ..                               | Block trying to acquire exclusive mutator lock
+  //   .. running ..                               | Block wait for all threads to pass a barrier
   // Poll Thread::suspend_count_ and enter full    |   .. blocked ..
   // suspend code.                                 |   .. blocked ..
-  // Change state to kSuspended                    |   .. blocked ..
-  // x: Release share on mutator_lock_             | Carry out exclusive access
-  // Acquire thread_suspend_count_lock_            |   .. exclusive ..
-  // while Thread::suspend_count_ > 0              |   .. exclusive ..
-  //   - wait on Thread::resume_cond_              |   .. exclusive ..
-  //     (releases thread_suspend_count_lock_)     |   .. exclusive ..
-  //   .. waiting ..                               | Release mutator_lock_
+  // Change state to kSuspended (pass the barrier) | Wake up when all threads pass the barrier
+  // x: Acquire thread_suspend_count_lock_         |   .. running ..
+  // while Thread::suspend_count_ > 0              |   .. running ..
+  //   - wait on Thread::resume_cond_              |   .. running ..
+  //     (releases thread_suspend_count_lock_)     |   .. running ..
   //   .. waiting ..                               | Request thread resumption by:
   //   .. waiting ..                               |   - acquiring thread_suspend_count_lock_
   //   .. waiting ..                               |   - decrementing Thread::suspend_count_ on
@@ -531,29 +556,13 @@
   //   .. waiting ..                               |   - notifying on Thread::resume_cond_
   //    - re-acquire thread_suspend_count_lock_    |   - releasing thread_suspend_count_lock_
   // Release thread_suspend_count_lock_            |  .. running ..
-  // Acquire share on mutator_lock_                |  .. running ..
-  //  - This could block but the thread still      |  .. running ..
-  //    has a state of kSuspended and so this      |  .. running ..
-  //    isn't an issue.                            |  .. running ..
-  // Acquire thread_suspend_count_lock_            |  .. running ..
-  //  - we poll here as we're transitioning into   |  .. running ..
-  //    kRunnable and an individual thread suspend |  .. running ..
-  //    request (e.g for debugging) won't try      |  .. running ..
-  //    to acquire the mutator lock (which would   |  .. running ..
-  //    block as we hold the mutator lock). This   |  .. running ..
-  //    poll ensures that if the suspender thought |  .. running ..
-  //    we were suspended by incrementing our      |  .. running ..
-  //    Thread::suspend_count_ and then reading    |  .. running ..
-  //    our state we go back to waiting on         |  .. running ..
-  //    Thread::resume_cond_.                      |  .. running ..
-  // can_go_runnable = Thread::suspend_count_ == 0 |  .. running ..
-  // Release thread_suspend_count_lock_            |  .. running ..
-  // if can_go_runnable                            |  .. running ..
-  //   Change state to kRunnable                   |  .. running ..
-  // else                                          |  .. running ..
-  //   Goto x                                      |  .. running ..
+  // Change to kRunnable                           |  .. running ..
+  //  - this uses a CAS operation to ensure the    |  .. running ..
+  //    suspend request flag isn't raised as the   |  .. running ..
+  //    state is changed                           |  .. running ..
+  //  - if the CAS operation fails then goto x     |  .. running ..
   //  .. running ..                                |  .. running ..
-  static ReaderWriterMutex* mutator_lock_ ACQUIRED_AFTER(instrument_entrypoints_lock_);
+  static MutatorMutex* mutator_lock_ ACQUIRED_AFTER(instrument_entrypoints_lock_);
 
   // Allow reader-writer mutual exclusion on the mark and live bitmaps of the heap.
   static ReaderWriterMutex* heap_bitmap_lock_ ACQUIRED_AFTER(mutator_lock_);
diff --git a/runtime/base/scoped_arena_allocator.cc b/runtime/base/scoped_arena_allocator.cc
index 4a7be38..d823edd 100644
--- a/runtime/base/scoped_arena_allocator.cc
+++ b/runtime/base/scoped_arena_allocator.cc
@@ -17,11 +17,11 @@
 #include "scoped_arena_allocator.h"
 
 #include "arena_allocator.h"
-#include <memcheck/memcheck.h>
+#include "base/memory_tool.h"
 
 namespace art {
 
-static constexpr size_t kValgrindRedZoneBytes = 8;
+static constexpr size_t kMemoryToolRedZoneBytes = 8;
 
 ArenaStack::ArenaStack(ArenaPool* arena_pool)
   : DebugStackRefCounter(),
@@ -30,7 +30,7 @@
     top_arena_(nullptr),
     top_ptr_(nullptr),
     top_end_(nullptr),
-    running_on_valgrind_(RUNNING_ON_VALGRIND > 0) {
+    is_running_on_memory_tool_(RUNNING_ON_MEMORY_TOOL > 0) {
 }
 
 ArenaStack::~ArenaStack() {
@@ -92,7 +92,7 @@
 }
 
 void* ArenaStack::AllocValgrind(size_t bytes, ArenaAllocKind kind) {
-  size_t rounded_bytes = RoundUp(bytes + kValgrindRedZoneBytes, 8);
+  size_t rounded_bytes = RoundUp(bytes + kMemoryToolRedZoneBytes, 8);
   uint8_t* ptr = top_ptr_;
   if (UNLIKELY(static_cast<size_t>(top_end_ - ptr) < rounded_bytes)) {
     ptr = AllocateFromNextArena(rounded_bytes);
@@ -100,8 +100,8 @@
   }
   CurrentStats()->RecordAlloc(bytes, kind);
   top_ptr_ = ptr + rounded_bytes;
-  VALGRIND_MAKE_MEM_UNDEFINED(ptr, bytes);
-  VALGRIND_MAKE_MEM_NOACCESS(ptr + bytes, rounded_bytes - bytes);
+  MEMORY_TOOL_MAKE_UNDEFINED(ptr, bytes);
+  MEMORY_TOOL_MAKE_NOACCESS(ptr + bytes, rounded_bytes - bytes);
   return ptr;
 }
 
diff --git a/runtime/base/scoped_arena_allocator.h b/runtime/base/scoped_arena_allocator.h
index bbedeac..ca514e4 100644
--- a/runtime/base/scoped_arena_allocator.h
+++ b/runtime/base/scoped_arena_allocator.h
@@ -64,7 +64,7 @@
 
   // Private - access via ScopedArenaAllocator or ScopedArenaAllocatorAdapter.
   void* Alloc(size_t bytes, ArenaAllocKind kind) ALWAYS_INLINE {
-    if (UNLIKELY(running_on_valgrind_)) {
+    if (UNLIKELY(is_running_on_memory_tool_)) {
       return AllocValgrind(bytes, kind);
     }
     size_t rounded_bytes = RoundUp(bytes, 8);
@@ -88,7 +88,7 @@
   uint8_t* top_ptr_;
   uint8_t* top_end_;
 
-  const bool running_on_valgrind_;
+  const bool is_running_on_memory_tool_;
 
   friend class ScopedArenaAllocator;
   template <typename T>
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 23c5942..122c35f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -55,6 +55,7 @@
 #include "linear_alloc.h"
 #include "oat.h"
 #include "oat_file.h"
+#include "oat_file-inl.h"
 #include "oat_file_assistant.h"
 #include "object_lock.h"
 #include "mirror/class.h"
@@ -248,13 +249,13 @@
     if (!gaps->empty() && gaps->top().size >= n) {
       FieldGap gap = gaps->top();
       gaps->pop();
-      DCHECK(IsAligned<n>(gap.start_offset));
+      DCHECK_ALIGNED(gap.start_offset, n);
       field->SetOffset(MemberOffset(gap.start_offset));
       if (gap.size > n) {
         AddFieldGap(gap.start_offset + n, gap.start_offset + gap.size, gaps);
       }
     } else {
-      DCHECK(IsAligned<n>(field_offset->Uint32Value()));
+      DCHECK_ALIGNED(field_offset->Uint32Value(), n);
       field->SetOffset(*field_offset);
       *field_offset = MemberOffset(field_offset->Uint32Value() + n);
     }
@@ -1195,13 +1196,9 @@
       if (kIsDebugBuild && !method->IsRuntimeMethod()) {
         CHECK(method->GetDeclaringClass() != nullptr);
       }
-      if (!method->IsNative()) {
-        method->SetEntryPointFromInterpreterPtrSize(
-            artInterpreterToInterpreterBridge, image_pointer_size_);
-        if (!method->IsRuntimeMethod() && method != runtime->GetResolutionMethod()) {
-          method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
-                                                            image_pointer_size_);
-        }
+      if (!method->IsNative() && !method->IsRuntimeMethod() && !method->IsResolutionMethod()) {
+        method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
+                                                          image_pointer_size_);
       }
     }
   }
@@ -2206,11 +2203,6 @@
 
   // Install entry point from interpreter.
   bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
-  if (enter_interpreter && !method->IsNative()) {
-    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
-  } else {
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
-  }
 
   if (method->IsAbstract()) {
     method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
@@ -3516,7 +3508,6 @@
   // At runtime the method looks like a reference and argument saving method, clone the code
   // related parameters from this method.
   out->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
-  out->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
 }
 
 void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const {
@@ -5183,7 +5174,7 @@
       field_offset = MemberOffset(RoundUp(field_offset.Uint32Value(), 4));
       AddFieldGap(old_offset.Uint32Value(), field_offset.Uint32Value(), &gaps);
     }
-    DCHECK(IsAligned<sizeof(mirror::HeapReference<mirror::Object>)>(field_offset.Uint32Value()));
+    DCHECK_ALIGNED(field_offset.Uint32Value(), sizeof(mirror::HeapReference<mirror::Object>));
     grouped_and_sorted_fields.pop_front();
     num_reference_fields++;
     field->SetOffset(field_offset);
@@ -5647,18 +5638,15 @@
                                                const void* method_code) const {
   OatFile::OatMethod oat_method = CreateOatMethod(method_code);
   oat_method.LinkMethod(method);
-  method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
 }
 
 void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const {
   if (!method->IsNative()) {
-    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
     method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
   } else {
     const void* quick_method_code = GetQuickGenericJniStub();
     OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code);
     oat_method.LinkMethod(method);
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
   }
 }
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d9935cb..e4f7b7a 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -17,7 +17,6 @@
 #ifndef ART_RUNTIME_CLASS_LINKER_H_
 #define ART_RUNTIME_CLASS_LINKER_H_
 
-#include <deque>
 #include <string>
 #include <utility>
 #include <vector>
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index de46b35..97d170e 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -4836,6 +4836,9 @@
       CHECK(!Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
       records = &dummy;
     }
+    // We don't need to wait on the condition variable records->new_record_condition_, because this
+    // function only reads the class objects, which are already marked so it doesn't change their
+    // reachability.
 
     //
     // Part 1: generate string tables.
@@ -4850,7 +4853,7 @@
          count > 0 && it != end; count--, it++) {
       const gc::AllocRecord* record = it->second;
       std::string temp;
-      class_names.Add(record->GetClass()->GetDescriptor(&temp));
+      class_names.Add(record->GetClassDescriptor(&temp));
       for (size_t i = 0, depth = record->GetDepth(); i < depth; i++) {
         ArtMethod* m = record->StackElement(i).GetMethod();
         class_names.Add(m->GetDeclaringClassDescriptor());
@@ -4902,7 +4905,7 @@
       const gc::AllocRecord* record = it->second;
       size_t stack_depth = record->GetDepth();
       size_t allocated_object_class_name_index =
-          class_names.IndexOf(record->GetClass()->GetDescriptor(&temp));
+          class_names.IndexOf(record->GetClassDescriptor(&temp));
       JDWP::Append4BE(bytes, record->ByteCount());
       JDWP::Append2BE(bytes, static_cast<uint16_t>(record->GetTid()));
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 7ac264a..3a15f1a 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -786,7 +786,10 @@
 
   // Get the pointer to the start of the debugging data
   const uint8_t* GetDebugInfoStream(const CodeItem* code_item) const {
-    if (code_item->debug_info_off_ == 0) {
+    // Check that the offset is in bounds.
+    // Note that although the specification says that 0 should be used if there
+    // is no debug information, some applications incorrectly use 0xFFFFFFFF.
+    if (code_item->debug_info_off_ == 0 || code_item->debug_info_off_ >= size_) {
       return nullptr;
     } else {
       return begin_ + code_item->debug_info_off_;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 90b8fdb..eec4983 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -794,13 +794,13 @@
   }
 
   const DexFile::TryItem* try_items = DexFile::GetTryItems(*code_item, 0);
-  ptr_ = DexFile::GetCatchHandlerData(*code_item, 0);
-  uint32_t handlers_size = DecodeUnsignedLeb128(&ptr_);
-
   if (!CheckListSize(try_items, try_items_size, sizeof(DexFile::TryItem), "try_items size")) {
     return false;
   }
 
+  ptr_ = DexFile::GetCatchHandlerData(*code_item, 0);
+  uint32_t handlers_size = DecodeUnsignedLeb128(&ptr_);
+
   if (UNLIKELY((handlers_size == 0) || (handlers_size >= 65536))) {
     ErrorStringPrintf("Invalid handlers_size: %ud", handlers_size);
     return false;
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 0a5ebfa..c05c935 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -116,7 +116,7 @@
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, last_no_thread_suspension_cause, checkpoint_functions,
                         sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, checkpoint_functions, interpreter_entrypoints,
-                        sizeof(void*) * 3);
+                        sizeof(void*) * 6);
 
     // Skip across the entrypoints structures.
 
@@ -133,7 +133,8 @@
                         sizeof(void*) * kLockLevelCount);
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, nested_signal_state, flip_function, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, flip_function, method_verifier, sizeof(void*));
-    EXPECT_OFFSET_DIFF(Thread, tlsPtr_.method_verifier, Thread, wait_mutex_, sizeof(void*),
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, method_verifier, thread_local_mark_stack, sizeof(void*));
+    EXPECT_OFFSET_DIFF(Thread, tlsPtr_.thread_local_mark_stack, Thread, wait_mutex_, sizeof(void*),
                        thread_tlsptr_end);
   }
 
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index bc3ba21..de4b3f4 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -93,7 +93,7 @@
 
     // NOTE: Don't align the code (it will not be executed) but check that the Thumb2
     // adjustment will be a NOP, see ArtMethod::EntryPointToCodePointer().
-    CHECK_EQ(mapping_table_offset & 1u, 0u);
+    CHECK_ALIGNED(mapping_table_offset, 2);
     const uint8_t* code_ptr = &fake_header_code_and_maps_[gc_map_offset];
 
     method_f_ = my_klass_->FindVirtualMethod("f", "()I", sizeof(void*));
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 762f061..47f9b1b 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -320,7 +320,7 @@
     return false;
   }
 
-  ArtMethod* method_obj = 0;
+  ArtMethod* method_obj = nullptr;
   uintptr_t return_pc = 0;
   uintptr_t sp = 0;
 
@@ -331,7 +331,9 @@
   // If we don't have a potential method, we're outta here.
   VLOG(signals) << "potential method: " << method_obj;
   // TODO: Check linear alloc and image.
-  if (method_obj == 0 || !IsAligned<kObjectAlignment>(method_obj)) {
+  DCHECK_ALIGNED(ArtMethod::ObjectSize(sizeof(void*)), sizeof(void*))
+      << "ArtMethod is not pointer aligned";
+  if (method_obj == nullptr || !IsAligned<sizeof(void*)>(method_obj)) {
     VLOG(signals) << "no method";
     return false;
   }
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index ac716ea..93f32e8 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -156,6 +156,10 @@
     return Size() == 0;
   }
 
+  bool IsFull() const {
+    return Size() == growth_limit_;
+  }
+
   size_t Size() const {
     DCHECK_LE(front_index_.LoadRelaxed(), back_index_.LoadRelaxed());
     return back_index_.LoadRelaxed() - front_index_.LoadRelaxed();
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index cd3f910..009254b 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -21,16 +21,11 @@
 #include "base/stl_util.h"
 #include "bitmap-inl.h"
 #include "card_table-inl.h"
-#include "heap_bitmap.h"
 #include "gc/accounting/space_bitmap-inl.h"
-#include "gc/collector/mark_sweep.h"
-#include "gc/collector/mark_sweep-inl.h"
 #include "gc/heap.h"
-#include "gc/space/space.h"
 #include "gc/space/image_space.h"
+#include "gc/space/space.h"
 #include "mirror/object-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/object_array-inl.h"
 #include "space_bitmap-inl.h"
 #include "thread.h"
 
@@ -95,11 +90,11 @@
 
 class ModUnionUpdateObjectReferencesVisitor {
  public:
-  ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback* callback, void* arg,
+  ModUnionUpdateObjectReferencesVisitor(MarkObjectVisitor* visitor,
                                         space::ContinuousSpace* from_space,
                                         space::ContinuousSpace* immune_space,
                                         bool* contains_reference_to_other_space)
-    : callback_(callback), arg_(arg), from_space_(from_space), immune_space_(immune_space),
+    : visitor_(visitor), from_space_(from_space), immune_space_(immune_space),
       contains_reference_to_other_space_(contains_reference_to_other_space) {
   }
 
@@ -111,13 +106,12 @@
     mirror::Object* ref = obj_ptr->AsMirrorPtr();
     if (ref != nullptr && !from_space_->HasAddress(ref) && !immune_space_->HasAddress(ref)) {
       *contains_reference_to_other_space_ = true;
-      callback_(obj_ptr, arg_);
+      visitor_->MarkHeapReference(obj_ptr);
     }
   }
 
  private:
-  MarkHeapReferenceCallback* const callback_;
-  void* const arg_;
+  MarkObjectVisitor* const visitor_;
   // Space which we are scanning
   space::ContinuousSpace* const from_space_;
   space::ContinuousSpace* const immune_space_;
@@ -129,25 +123,24 @@
  public:
   // Immune space is any other space which we don't care about references to. Currently this is
   // the image space in the case of the zygote mod union table.
-  ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg,
+  ModUnionScanImageRootVisitor(MarkObjectVisitor* visitor,
                                space::ContinuousSpace* from_space,
                                space::ContinuousSpace* immune_space,
                                bool* contains_reference_to_other_space)
-      : callback_(callback), arg_(arg), from_space_(from_space), immune_space_(immune_space),
+      : visitor_(visitor), from_space_(from_space), immune_space_(immune_space),
         contains_reference_to_other_space_(contains_reference_to_other_space) {}
 
   void operator()(Object* root) const
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(root != nullptr);
-    ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_, from_space_, immune_space_,
+    ModUnionUpdateObjectReferencesVisitor ref_visitor(visitor_, from_space_, immune_space_,
                                                       contains_reference_to_other_space_);
     root->VisitReferences<kMovingClasses>(ref_visitor, VoidFunctor());
   }
 
  private:
-  MarkHeapReferenceCallback* const callback_;
-  void* const arg_;
+  MarkObjectVisitor* const visitor_;
   // Space which we are scanning
   space::ContinuousSpace* const from_space_;
   space::ContinuousSpace* const immune_space_;
@@ -305,8 +298,7 @@
   }
 }
 
-void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
-                                                          void* arg) {
+void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
   CardTable* card_table = heap_->GetCardTable();
 
   std::vector<mirror::HeapReference<Object>*> cards_references;
@@ -338,7 +330,7 @@
   size_t count = 0;
   for (const auto& ref : references_) {
     for (mirror::HeapReference<Object>* obj_ptr : ref.second) {
-      callback(obj_ptr, arg);
+      visitor->MarkHeapReference(obj_ptr);
     }
     count += ref.second.size();
   }
@@ -362,9 +354,9 @@
 
 class CardBitVisitor {
  public:
-  CardBitVisitor(MarkHeapReferenceCallback* callback, void* arg, space::ContinuousSpace* space,
+  CardBitVisitor(MarkObjectVisitor* visitor, space::ContinuousSpace* space,
                  space::ContinuousSpace* immune_space, ModUnionTable::CardBitmap* card_bitmap)
-      : callback_(callback), arg_(arg), space_(space), immune_space_(immune_space),
+      : visitor_(visitor), space_(space), immune_space_(immune_space),
         bitmap_(space->GetLiveBitmap()), card_bitmap_(card_bitmap) {
     DCHECK(immune_space_ != nullptr);
   }
@@ -374,7 +366,7 @@
     DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
         << start << " " << *space_;
     bool reference_to_other_space = false;
-    ModUnionScanImageRootVisitor scan_visitor(callback_, arg_, space_, immune_space_,
+    ModUnionScanImageRootVisitor scan_visitor(visitor_, space_, immune_space_,
                                               &reference_to_other_space);
     bitmap_->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
     if (!reference_to_other_space) {
@@ -384,8 +376,7 @@
   }
 
  private:
-  MarkHeapReferenceCallback* const callback_;
-  void* const arg_;
+  MarkObjectVisitor* const visitor_;
   space::ContinuousSpace* const space_;
   space::ContinuousSpace* const immune_space_;
   ContinuousSpaceBitmap* const bitmap_;
@@ -400,15 +391,14 @@
 }
 
 // Mark all references to the alloc space(s).
-void ModUnionTableCardCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
-                                                     void* arg) {
+void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
   auto* image_space = heap_->GetImageSpace();
   // If we don't have an image space, just pass in space_ as the immune space. Pass in the same
   // space_ instead of image_space to avoid a null check in ModUnionUpdateObjectReferencesVisitor.
-  CardBitVisitor visitor(callback, arg, space_, image_space != nullptr ? image_space : space_,
+  CardBitVisitor bit_visitor(visitor, space_, image_space != nullptr ? image_space : space_,
       card_bitmap_.get());
   card_bitmap_->VisitSetBits(
-      0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, visitor);
+      0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, bit_visitor);
 }
 
 void ModUnionTableCardCache::Dump(std::ostream& os) {
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index 2e232ca..520cc1c 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -76,7 +76,7 @@
   // 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. Also mark references to other
   // spaces which are stored in the mod-union table.
-  virtual void UpdateAndMarkReferences(MarkHeapReferenceCallback* callback, void* arg) = 0;
+  virtual void UpdateAndMarkReferences(MarkObjectVisitor* visitor) = 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
@@ -117,7 +117,7 @@
   void ClearCards() OVERRIDE;
 
   // Update table based on cleared cards and mark all references to the other spaces.
-  void UpdateAndMarkReferences(MarkHeapReferenceCallback* callback, void* arg) OVERRIDE
+  void UpdateAndMarkReferences(MarkObjectVisitor* visitor) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -157,7 +157,7 @@
   virtual void ClearCards() OVERRIDE;
 
   // Mark all references to the alloc space(s).
-  virtual void UpdateAndMarkReferences(MarkHeapReferenceCallback* callback, void* arg) OVERRIDE
+  virtual void UpdateAndMarkReferences(MarkObjectVisitor* visitor) OVERRIDE
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc
index 363b76a..aad8a25 100644
--- a/runtime/gc/accounting/mod_union_table_test.cc
+++ b/runtime/gc/accounting/mod_union_table_test.cc
@@ -93,12 +93,24 @@
 };
 
 // Collect visited objects into container.
-static void CollectVisitedCallback(mirror::HeapReference<mirror::Object>* ref, void* arg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(ref != nullptr);
-  DCHECK(arg != nullptr);
-  reinterpret_cast<std::set<mirror::Object*>*>(arg)->insert(ref->AsMirrorPtr());
-}
+class CollectVisitedVisitor : public MarkObjectVisitor {
+ public:
+  explicit CollectVisitedVisitor(std::set<mirror::Object*>* out) : out_(out) {}
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* ref) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(ref != nullptr);
+    MarkObject(ref->AsMirrorPtr());
+  }
+  virtual mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(obj != nullptr);
+    out_->insert(obj);
+    return obj;
+  }
+
+ private:
+  std::set<mirror::Object*>* const out_;
+};
 
 // A mod union table that only holds references to a specified target space.
 class ModUnionTableRefCacheToSpace : public ModUnionTableReferenceCache {
@@ -199,7 +211,8 @@
   obj2->Set(3, other_space_ref2);
   table->ClearCards();
   std::set<mirror::Object*> visited_before;
-  table->UpdateAndMarkReferences(&CollectVisitedCallback, &visited_before);
+  CollectVisitedVisitor collector_before(&visited_before);
+  table->UpdateAndMarkReferences(&collector_before);
   // Check that we visited all the references in other spaces only.
   ASSERT_GE(visited_before.size(), 2u);
   ASSERT_TRUE(visited_before.find(other_space_ref1) != visited_before.end());
@@ -230,7 +243,8 @@
   }
   // Visit again and make sure the cards got cleared back to their sane state.
   std::set<mirror::Object*> visited_after;
-  table->UpdateAndMarkReferences(&CollectVisitedCallback, &visited_after);
+  CollectVisitedVisitor collector_after(&visited_after);
+  table->UpdateAndMarkReferences(&collector_after);
   // Check that we visited a superset after.
   for (auto* obj : visited_before) {
     ASSERT_TRUE(visited_after.find(obj) != visited_after.end()) << obj;
diff --git a/runtime/gc/accounting/read_barrier_table.h b/runtime/gc/accounting/read_barrier_table.h
index 436df92..86266e2 100644
--- a/runtime/gc/accounting/read_barrier_table.h
+++ b/runtime/gc/accounting/read_barrier_table.h
@@ -51,8 +51,8 @@
   void Clear(uint8_t* start_addr, uint8_t* end_addr) {
     DCHECK(IsValidHeapAddr(start_addr)) << start_addr;
     DCHECK(IsValidHeapAddr(end_addr)) << end_addr;
-    DCHECK(IsAligned<kRegionSize>(start_addr));
-    DCHECK(IsAligned<kRegionSize>(end_addr));
+    DCHECK_ALIGNED(start_addr, kRegionSize);
+    DCHECK_ALIGNED(end_addr, kRegionSize);
     uint8_t* entry_start = EntryFromAddr(start_addr);
     uint8_t* entry_end = EntryFromAddr(end_addr);
     memset(reinterpret_cast<void*>(entry_start), 0, entry_end - entry_start);
diff --git a/runtime/gc/accounting/remembered_set.cc b/runtime/gc/accounting/remembered_set.cc
index eeb385e..23ab8df 100644
--- a/runtime/gc/accounting/remembered_set.cc
+++ b/runtime/gc/accounting/remembered_set.cc
@@ -61,11 +61,10 @@
 
 class RememberedSetReferenceVisitor {
  public:
-  RememberedSetReferenceVisitor(MarkHeapReferenceCallback* callback,
-                                DelayReferenceReferentCallback* ref_callback,
-                                space::ContinuousSpace* target_space,
-                                bool* const contains_reference_to_target_space, void* arg)
-      : callback_(callback), ref_callback_(ref_callback), target_space_(target_space), arg_(arg),
+  RememberedSetReferenceVisitor(space::ContinuousSpace* target_space,
+                                bool* const contains_reference_to_target_space,
+                                collector::GarbageCollector* collector)
+      : collector_(collector), target_space_(target_space),
         contains_reference_to_target_space_(contains_reference_to_target_space) {}
 
   void operator()(mirror::Object* obj, MemberOffset offset, bool /* is_static */) const
@@ -74,7 +73,7 @@
     mirror::HeapReference<mirror::Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
     if (target_space_->HasAddress(ref_ptr->AsMirrorPtr())) {
       *contains_reference_to_target_space_ = true;
-      callback_(ref_ptr, arg_);
+      collector_->MarkHeapReference(ref_ptr);
       DCHECK(!target_space_->HasAddress(ref_ptr->AsMirrorPtr()));
     }
   }
@@ -84,49 +83,43 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     if (target_space_->HasAddress(ref->GetReferent())) {
       *contains_reference_to_target_space_ = true;
-      ref_callback_(klass, ref, arg_);
+      collector_->DelayReferenceReferent(klass, ref);
     }
   }
 
  private:
-  MarkHeapReferenceCallback* const callback_;
-  DelayReferenceReferentCallback* const ref_callback_;
+  collector::GarbageCollector* const collector_;
   space::ContinuousSpace* const target_space_;
-  void* const arg_;
   bool* const contains_reference_to_target_space_;
 };
 
 class RememberedSetObjectVisitor {
  public:
-  RememberedSetObjectVisitor(MarkHeapReferenceCallback* callback,
-                             DelayReferenceReferentCallback* ref_callback,
-                             space::ContinuousSpace* target_space,
-                             bool* const contains_reference_to_target_space, void* arg)
-      : callback_(callback), ref_callback_(ref_callback), target_space_(target_space), arg_(arg),
+  RememberedSetObjectVisitor(space::ContinuousSpace* target_space,
+                             bool* const contains_reference_to_target_space,
+                             collector::GarbageCollector* collector)
+      : collector_(collector), target_space_(target_space),
         contains_reference_to_target_space_(contains_reference_to_target_space) {}
 
   void operator()(mirror::Object* obj) const EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    RememberedSetReferenceVisitor visitor(callback_, ref_callback_, target_space_,
-                                          contains_reference_to_target_space_, arg_);
+    RememberedSetReferenceVisitor visitor(target_space_, contains_reference_to_target_space_,
+                                          collector_);
     obj->VisitReferences<kMovingClasses>(visitor, visitor);
   }
 
  private:
-  MarkHeapReferenceCallback* const callback_;
-  DelayReferenceReferentCallback* const ref_callback_;
+  collector::GarbageCollector* const collector_;
   space::ContinuousSpace* const target_space_;
-  void* const arg_;
   bool* const contains_reference_to_target_space_;
 };
 
-void RememberedSet::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
-                                            DelayReferenceReferentCallback* ref_callback,
-                                            space::ContinuousSpace* target_space, void* arg) {
+void RememberedSet::UpdateAndMarkReferences(space::ContinuousSpace* target_space,
+                                            collector::GarbageCollector* collector) {
   CardTable* card_table = heap_->GetCardTable();
   bool contains_reference_to_target_space = false;
-  RememberedSetObjectVisitor obj_visitor(callback, ref_callback, target_space,
-                                         &contains_reference_to_target_space, arg);
+  RememberedSetObjectVisitor obj_visitor(target_space, &contains_reference_to_target_space,
+                                         collector);
   ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
   CardSet remove_card_set;
   for (uint8_t* const card_addr : dirty_cards_) {
diff --git a/runtime/gc/accounting/remembered_set.h b/runtime/gc/accounting/remembered_set.h
index c51e26d..affe863 100644
--- a/runtime/gc/accounting/remembered_set.h
+++ b/runtime/gc/accounting/remembered_set.h
@@ -29,6 +29,7 @@
 namespace gc {
 
 namespace collector {
+  class GarbageCollector;
   class MarkSweep;
 }  // namespace collector
 namespace space {
@@ -53,9 +54,8 @@
   void ClearCards();
 
   // Mark through all references to the target space.
-  void UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
-                               DelayReferenceReferentCallback* ref_callback,
-                               space::ContinuousSpace* target_space, void* arg)
+  void UpdateAndMarkReferences(space::ContinuousSpace* target_space,
+                               collector::GarbageCollector* collector)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 6546eb4..cdeaa50 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -79,7 +79,7 @@
 
 template<size_t kAlignment>
 void SpaceBitmap<kAlignment>::SetHeapLimit(uintptr_t new_end) {
-  DCHECK(IsAligned<kBitsPerIntPtrT * kAlignment>(new_end));
+  DCHECK_ALIGNED(new_end, kBitsPerIntPtrT * kAlignment);
   size_t new_size = OffsetToIndex(new_end - heap_begin_) * sizeof(intptr_t);
   if (new_size < bitmap_size_) {
     bitmap_size_ = new_size;
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index 35faff3..e0661b6 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -30,6 +30,7 @@
 namespace art {
 
 namespace mirror {
+  class Class;
   class Object;
 }  // namespace mirror
 class MemMap;
diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc
index 11921f4..3108b7c 100644
--- a/runtime/gc/allocation_record.cc
+++ b/runtime/gc/allocation_record.cc
@@ -32,6 +32,15 @@
   return method_->GetLineNumFromDexPC(dex_pc_);
 }
 
+const char* AllocRecord::GetClassDescriptor(std::string* storage) const {
+  // klass_ could contain null only if we implement class unloading.
+  if (UNLIKELY(klass_.IsNull())) {
+    return "null";
+  } else {
+    return klass_.Read()->GetDescriptor(storage);
+  }
+}
+
 void AllocRecordObjectMap::SetProperties() {
 #ifdef HAVE_ANDROID_OS
   // Check whether there's a system property overriding the max number of records.
@@ -97,25 +106,28 @@
   // Only visit the last recent_record_max_ number of allocation records in entries_ and mark the
   // klass_ fields as strong roots.
   for (auto it = entries_.rbegin(), end = entries_.rend(); count > 0 && it != end; count--, ++it) {
-    buffered_visitor.VisitRoot(it->second->GetClassGcRoot());
+    buffered_visitor.VisitRootIfNonNull(it->second->GetClassGcRoot());
   }
 }
 
-static inline void SweepClassObject(AllocRecord* record, IsMarkedCallback* callback, void* arg)
+static inline void SweepClassObject(AllocRecord* record, IsMarkedVisitor* visitor)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
   GcRoot<mirror::Class>& klass = record->GetClassGcRoot();
   // This does not need a read barrier because this is called by GC.
   mirror::Object* old_object = klass.Read<kWithoutReadBarrier>();
-  mirror::Object* new_object = UNLIKELY(old_object == nullptr) ?
-      nullptr : callback(old_object, arg);
-  if (UNLIKELY(old_object != new_object)) {
-    mirror::Class* new_klass = UNLIKELY(new_object == nullptr) ? nullptr : new_object->AsClass();
-    klass = GcRoot<mirror::Class>(new_klass);
+  if (old_object != nullptr) {
+    // The class object can become null if we implement class unloading.
+    // In that case we might still want to keep the class name string (not implemented).
+    mirror::Object* new_object = visitor->IsMarked(old_object);
+    DCHECK(new_object != nullptr);
+    if (UNLIKELY(old_object != new_object)) {
+      klass = GcRoot<mirror::Class>(new_object->AsClass());
+    }
   }
 }
 
-void AllocRecordObjectMap::SweepAllocationRecords(IsMarkedCallback* callback, void* arg) {
+void AllocRecordObjectMap::SweepAllocationRecords(IsMarkedVisitor* visitor) {
   VLOG(heap) << "Start SweepAllocationRecords()";
   size_t count_deleted = 0, count_moved = 0, count = 0;
   // Only the first (size - recent_record_max_) number of records can be deleted.
@@ -130,11 +142,11 @@
     // This does not need a read barrier because this is called by GC.
     mirror::Object* old_object = it->first.Read<kWithoutReadBarrier>();
     AllocRecord* record = it->second;
-    mirror::Object* new_object = old_object == nullptr ? nullptr : callback(old_object, arg);
+    mirror::Object* new_object = old_object == nullptr ? nullptr : visitor->IsMarked(old_object);
     if (new_object == nullptr) {
       if (count > delete_bound) {
         it->first = GcRoot<mirror::Object>(nullptr);
-        SweepClassObject(record, callback, arg);
+        SweepClassObject(record, visitor);
         ++it;
       } else {
         delete record;
@@ -146,7 +158,7 @@
         it->first = GcRoot<mirror::Object>(new_object);
         ++count_moved;
       }
-      SweepClassObject(record, callback, arg);
+      SweepClassObject(record, visitor);
       ++it;
     }
   }
@@ -163,11 +175,6 @@
   allow_new_record_ = false;
 }
 
-void AllocRecordObjectMap::EnsureNewAllocationRecordsDisallowed() {
-  CHECK(!allow_new_record_);
-}
-
-
 struct AllocRecordStackVisitor : public StackVisitor {
   AllocRecordStackVisitor(Thread* thread, AllocRecordStackTrace* trace_in, size_t max)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -259,7 +266,8 @@
   }
 
   // Wait for GC's sweeping to complete and allow new records
-  while (UNLIKELY(!records->allow_new_record_)) {
+  while (UNLIKELY((!kUseReadBarrier && !records->allow_new_record_) ||
+                  (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
     records->new_record_condition_.WaitHoldingLocks(self);
   }
 
diff --git a/runtime/gc/allocation_record.h b/runtime/gc/allocation_record.h
index f567153..933363b 100644
--- a/runtime/gc/allocation_record.h
+++ b/runtime/gc/allocation_record.h
@@ -188,7 +188,10 @@
     return klass_.Read();
   }
 
-  GcRoot<mirror::Class>& GetClassGcRoot() {
+  const char* GetClassDescriptor(std::string* storage) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  GcRoot<mirror::Class>& GetClassGcRoot() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return klass_;
   }
 
@@ -258,19 +261,22 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
 
-  void SweepAllocationRecords(IsMarkedCallback* callback, void* arg)
+  void SweepAllocationRecords(IsMarkedVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
 
+  // Allocation tracking could be enabled by user in between DisallowNewAllocationRecords() and
+  // AllowNewAllocationRecords(), in which case new allocation records can be added although they
+  // should be disallowed. However, this is GC-safe because new objects are not processed in this GC
+  // cycle. The only downside of not handling this case is that such new allocation records can be
+  // swept from the list. But missing the first few records is acceptable for using the button to
+  // enable allocation tracking.
   void DisallowNewAllocationRecords()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
   void AllowNewAllocationRecords()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
-  void EnsureNewAllocationRecordsDisallowed()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
 
   // TODO: Is there a better way to hide the entries_'s type?
   EntryList::iterator Begin()
diff --git a/runtime/gc/allocator/rosalloc-inl.h b/runtime/gc/allocator/rosalloc-inl.h
index bba92a1..25fdd7c 100644
--- a/runtime/gc/allocator/rosalloc-inl.h
+++ b/runtime/gc/allocator/rosalloc-inl.h
@@ -24,7 +24,7 @@
 namespace allocator {
 
 inline ALWAYS_INLINE bool RosAlloc::ShouldCheckZeroMemory() {
-  return kCheckZeroMemory && !running_on_valgrind_;
+  return kCheckZeroMemory && !is_running_on_memory_tool_;
 }
 
 template<bool kThreadSafe>
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 49c7fda..abaa97f 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -16,8 +16,9 @@
 
 #include "rosalloc.h"
 
+#include "base/memory_tool.h"
 #include "base/mutex-inl.h"
-#include "gc/space/valgrind_settings.h"
+#include "gc/space/memory_tool_settings.h"
 #include "mem_map.h"
 #include "mirror/class-inl.h"
 #include "mirror/object.h"
@@ -50,7 +51,7 @@
     reinterpret_cast<RosAlloc::Run*>(dedicated_full_run_storage_);
 
 RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity,
-                   PageReleaseMode page_release_mode, bool running_on_valgrind,
+                   PageReleaseMode page_release_mode, bool running_on_memory_tool,
                    size_t page_release_size_threshold)
     : base_(reinterpret_cast<uint8_t*>(base)), footprint_(capacity),
       capacity_(capacity), max_capacity_(max_capacity),
@@ -58,11 +59,11 @@
       bulk_free_lock_("rosalloc bulk free lock", kRosAllocBulkFreeLock),
       page_release_mode_(page_release_mode),
       page_release_size_threshold_(page_release_size_threshold),
-      running_on_valgrind_(running_on_valgrind) {
+      is_running_on_memory_tool_(running_on_memory_tool) {
   DCHECK_EQ(RoundUp(capacity, kPageSize), capacity);
   DCHECK_EQ(RoundUp(max_capacity, kPageSize), max_capacity);
   CHECK_LE(capacity, max_capacity);
-  CHECK(IsAligned<kPageSize>(page_release_size_threshold_));
+  CHECK_ALIGNED(page_release_size_threshold_, kPageSize);
   if (!initialized_) {
     Initialize();
   }
@@ -110,6 +111,9 @@
   for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
     delete size_bracket_locks_[i];
   }
+  if (is_running_on_memory_tool_) {
+    MEMORY_TOOL_MAKE_DEFINED(base_, capacity_);
+  }
 }
 
 void* RosAlloc::AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type) {
@@ -345,7 +349,7 @@
     fpr->magic_num_ = kMagicNumFree;
   }
   fpr->SetByteSize(this, byte_size);
-  DCHECK(IsAligned<kPageSize>(fpr->ByteSize(this)));
+  DCHECK_ALIGNED(fpr->ByteSize(this), kPageSize);
 
   DCHECK(free_page_runs_.find(fpr) == free_page_runs_.end());
   if (!free_page_runs_.empty()) {
@@ -1563,7 +1567,7 @@
         FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * kPageSize);
         DCHECK(free_page_runs_.find(fpr) != free_page_runs_.end());
         size_t fpr_size = fpr->ByteSize(this);
-        DCHECK(IsAligned<kPageSize>(fpr_size));
+        DCHECK_ALIGNED(fpr_size, kPageSize);
         void* start = fpr;
         if (kIsDebugBuild) {
           // In the debug build, the first page of a free page run
@@ -1897,8 +1901,8 @@
     MutexLock lock_mu(self, lock_);
     size_t pm_end = page_map_size_;
     size_t i = 0;
-    size_t valgrind_modifier =  running_on_valgrind_ ?
-        2 * ::art::gc::space::kDefaultValgrindRedZoneBytes :  // Redzones before and after.
+    size_t memory_tool_modifier =  is_running_on_memory_tool_ ?
+        2 * ::art::gc::space::kDefaultMemoryToolRedZoneBytes :  // Redzones before and after.
         0;
     while (i < pm_end) {
       uint8_t pm = page_map_[i];
@@ -1912,7 +1916,7 @@
           CHECK(free_page_runs_.find(fpr) != free_page_runs_.end())
               << "An empty page must belong to the free page run set";
           size_t fpr_size = fpr->ByteSize(this);
-          CHECK(IsAligned<kPageSize>(fpr_size))
+          CHECK_ALIGNED(fpr_size, kPageSize)
               << "A free page run size isn't page-aligned : " << fpr_size;
           size_t num_pages = fpr_size / kPageSize;
           CHECK_GT(num_pages, static_cast<uintptr_t>(0))
@@ -1938,15 +1942,15 @@
             idx++;
           }
           uint8_t* start = base_ + i * kPageSize;
-          if (running_on_valgrind_) {
-            start += ::art::gc::space::kDefaultValgrindRedZoneBytes;
+          if (is_running_on_memory_tool_) {
+            start += ::art::gc::space::kDefaultMemoryToolRedZoneBytes;
           }
           mirror::Object* obj = reinterpret_cast<mirror::Object*>(start);
           size_t obj_size = obj->SizeOf();
-          CHECK_GT(obj_size + valgrind_modifier, kLargeSizeThreshold)
+          CHECK_GT(obj_size + memory_tool_modifier, kLargeSizeThreshold)
               << "A rosalloc large object size must be > " << kLargeSizeThreshold;
-          CHECK_EQ(num_pages, RoundUp(obj_size + valgrind_modifier, kPageSize) / kPageSize)
-              << "A rosalloc large object size " << obj_size + valgrind_modifier
+          CHECK_EQ(num_pages, RoundUp(obj_size + memory_tool_modifier, kPageSize) / kPageSize)
+              << "A rosalloc large object size " << obj_size + memory_tool_modifier
               << " does not match the page map table " << (num_pages * kPageSize)
               << std::endl << DumpPageMap();
           i += num_pages;
@@ -2011,11 +2015,11 @@
   }
   // Call Verify() here for the lock order.
   for (auto& run : runs) {
-    run->Verify(self, this, running_on_valgrind_);
+    run->Verify(self, this, is_running_on_memory_tool_);
   }
 }
 
-void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc, bool running_on_valgrind) {
+void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc, bool running_on_memory_tool) {
   DCHECK_EQ(magic_num_, kMagicNum) << "Bad magic number : " << Dump();
   const size_t idx = size_bracket_idx_;
   CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump();
@@ -2098,8 +2102,8 @@
   }
   // Check each slot.
   size_t slots = 0;
-  size_t valgrind_modifier = running_on_valgrind ?
-      2 * ::art::gc::space::kDefaultValgrindRedZoneBytes :
+  size_t memory_tool_modifier = running_on_memory_tool ?
+      2 * ::art::gc::space::kDefaultMemoryToolRedZoneBytes :
       0U;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
     DCHECK_GE(num_slots, slots) << "Out of bounds";
@@ -2113,16 +2117,16 @@
       bool is_thread_local_freed = IsThreadLocal() && ((thread_local_free_vec >> i) & 0x1) != 0;
       if (is_allocated && !is_thread_local_freed) {
         uint8_t* slot_addr = slot_base + (slots + i) * bracket_size;
-        if (running_on_valgrind) {
-          slot_addr += ::art::gc::space::kDefaultValgrindRedZoneBytes;
+        if (running_on_memory_tool) {
+          slot_addr += ::art::gc::space::kDefaultMemoryToolRedZoneBytes;
         }
         mirror::Object* obj = reinterpret_cast<mirror::Object*>(slot_addr);
         size_t obj_size = obj->SizeOf();
-        CHECK_LE(obj_size + valgrind_modifier, kLargeSizeThreshold)
+        CHECK_LE(obj_size + memory_tool_modifier, kLargeSizeThreshold)
             << "A run slot contains a large object " << Dump();
-        CHECK_EQ(SizeToIndex(obj_size + valgrind_modifier), idx)
+        CHECK_EQ(SizeToIndex(obj_size + memory_tool_modifier), idx)
             << PrettyTypeOf(obj) << " "
-            << "obj_size=" << obj_size << "(" << obj_size + valgrind_modifier << "), idx=" << idx
+            << "obj_size=" << obj_size << "(" << obj_size + memory_tool_modifier << "), idx=" << idx
             << " A run slot contains an object with wrong size " << Dump();
       }
     }
@@ -2159,7 +2163,7 @@
           // to the next page.
           if (free_page_runs_.find(fpr) != free_page_runs_.end()) {
             size_t fpr_size = fpr->ByteSize(this);
-            DCHECK(IsAligned<kPageSize>(fpr_size));
+            DCHECK_ALIGNED(fpr_size, kPageSize);
             uint8_t* start = reinterpret_cast<uint8_t*>(fpr);
             reclaimed_bytes += ReleasePageRange(start, start + fpr_size);
             size_t pages = fpr_size / kPageSize;
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 0fcfe72..c356a39 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -253,7 +253,7 @@
     // Dump the run metadata for debugging.
     std::string Dump();
     // Verify for debugging.
-    void Verify(Thread* self, RosAlloc* rosalloc, bool running_on_valgrind)
+    void Verify(Thread* self, RosAlloc* rosalloc, bool running_on_memory_tool)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_);
 
@@ -503,7 +503,7 @@
   const size_t page_release_size_threshold_;
 
   // Whether this allocator is running under Valgrind.
-  bool running_on_valgrind_;
+  bool is_running_on_memory_tool_;
 
   // The base address of the memory region that's managed by this allocator.
   uint8_t* Begin() { return base_; }
@@ -561,7 +561,7 @@
  public:
   RosAlloc(void* base, size_t capacity, size_t max_capacity,
            PageReleaseMode page_release_mode,
-           bool running_on_valgrind,
+           bool running_on_memory_tool,
            size_t page_release_size_threshold = kDefaultPageReleaseSizeThreshold);
   ~RosAlloc();
 
diff --git a/runtime/gc/allocator_type.h b/runtime/gc/allocator_type.h
index f9a2ff6..185a9b7 100644
--- a/runtime/gc/allocator_type.h
+++ b/runtime/gc/allocator_type.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_ALLOCATOR_TYPE_H_
 #define ART_RUNTIME_GC_ALLOCATOR_TYPE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index c7d2e9f..c803655 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -17,8 +17,10 @@
 #include "concurrent_copying.h"
 
 #include "art_field-inl.h"
+#include "base/stl_util.h"
 #include "gc/accounting/heap_bitmap-inl.h"
 #include "gc/accounting/space_bitmap-inl.h"
+#include "gc/reference_processor.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space.h"
 #include "intern_table.h"
@@ -37,17 +39,22 @@
     : GarbageCollector(heap,
                        name_prefix + (name_prefix.empty() ? "" : " ") +
                        "concurrent copying + mark sweep"),
-      region_space_(nullptr), gc_barrier_(new Barrier(0)), mark_queue_(2 * MB),
+      region_space_(nullptr), gc_barrier_(new Barrier(0)),
+      gc_mark_stack_(accounting::ObjectStack::Create("concurrent copying gc mark stack",
+                                                     2 * MB, 2 * MB)),
+      mark_stack_lock_("concurrent copying mark stack lock", kMarkSweepMarkStackLock),
+      thread_running_gc_(nullptr),
       is_marking_(false), is_active_(false), is_asserting_to_space_invariant_(false),
-      heap_mark_bitmap_(nullptr), live_stack_freeze_size_(0),
+      heap_mark_bitmap_(nullptr), live_stack_freeze_size_(0), mark_stack_mode_(kMarkStackModeOff),
+      weak_ref_access_enabled_(true),
       skipped_blocks_lock_("concurrent copying bytes blocks lock", kMarkSweepMarkStackLock),
       rb_table_(heap_->GetReadBarrierTable()),
       force_evacuate_all_(false) {
   static_assert(space::RegionSpace::kRegionSize == accounting::ReadBarrierTable::kRegionSize,
                 "The region space size and the read barrier table region size must match");
   cc_heap_bitmap_.reset(new accounting::HeapBitmap(heap));
+  Thread* self = Thread::Current();
   {
-    Thread* self = Thread::Current();
     ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
     // Cache this so that we won't have to lock heap_bitmap_lock_ in
     // Mark() which could cause a nested lock on heap_bitmap_lock_
@@ -55,9 +62,27 @@
     // (class_linker_lock_ and heap_bitmap_lock_).
     heap_mark_bitmap_ = heap->GetMarkBitmap();
   }
+  {
+    MutexLock mu(self, mark_stack_lock_);
+    for (size_t i = 0; i < kMarkStackPoolSize; ++i) {
+      accounting::AtomicStack<mirror::Object>* mark_stack =
+          accounting::AtomicStack<mirror::Object>::Create(
+              "thread local mark stack", kMarkStackSize, kMarkStackSize);
+      pooled_mark_stacks_.push_back(mark_stack);
+    }
+  }
+}
+
+void ConcurrentCopying::MarkHeapReference(mirror::HeapReference<mirror::Object>* from_ref) {
+  // Used for preserving soft references, should be OK to not have a CAS here since there should be
+  // no other threads which can trigger read barriers on the same referent during reference
+  // processing.
+  from_ref->Assign(Mark(from_ref->AsMirrorPtr()));
+  DCHECK(!from_ref->IsNull());
 }
 
 ConcurrentCopying::~ConcurrentCopying() {
+  STLDeleteElements(&pooled_mark_stacks_);
 }
 
 void ConcurrentCopying::RunPhases() {
@@ -65,6 +90,7 @@
   CHECK(!is_active_);
   is_active_ = true;
   Thread* self = Thread::Current();
+  thread_running_gc_ = self;
   Locks::mutator_lock_->AssertNotHeld(self);
   {
     ReaderMutexLock mu(self, *Locks::mutator_lock_);
@@ -79,7 +105,7 @@
   if (kEnableNoFromSpaceRefsVerification || kIsDebugBuild) {
     TimingLogger::ScopedTiming split("(Paused)VerifyNoFromSpaceReferences", GetTimings());
     ScopedPause pause(this);
-    CheckEmptyMarkQueue();
+    CheckEmptyMarkStack();
     if (kVerboseMode) {
       LOG(INFO) << "Verifying no from-space refs";
     }
@@ -87,7 +113,7 @@
     if (kVerboseMode) {
       LOG(INFO) << "Done verifying no from-space refs";
     }
-    CheckEmptyMarkQueue();
+    CheckEmptyMarkStack();
   }
   {
     ReaderMutexLock mu(self, *Locks::mutator_lock_);
@@ -96,6 +122,7 @@
   FinishPhase();
   CHECK(is_active_);
   is_active_ = false;
+  thread_running_gc_ = nullptr;
 }
 
 void ConcurrentCopying::BindBitmaps() {
@@ -132,7 +159,7 @@
     LOG(INFO) << "Region-space : " << reinterpret_cast<void*>(region_space_->Begin()) << "-"
               << reinterpret_cast<void*>(region_space_->Limit());
   }
-  CHECK(mark_queue_.IsEmpty());
+  CheckEmptyMarkStack();
   immune_region_.Reset();
   bytes_moved_.StoreRelaxed(0);
   objects_moved_.StoreRelaxed(0);
@@ -209,6 +236,7 @@
       cc->from_space_num_bytes_at_first_pause_ = cc->region_space_->GetBytesAllocated();
     }
     cc->is_marking_ = true;
+    cc->mark_stack_mode_.StoreRelaxed(ConcurrentCopying::kMarkStackModeThreadLocal);
     if (UNLIKELY(Runtime::Current()->IsActiveTransaction())) {
       CHECK(Runtime::Current()->IsAotCompiler());
       TimingLogger::ScopedTiming split2("(Paused)VisitTransactionRoots", cc->GetTimings());
@@ -283,12 +311,12 @@
     } else {
       // Newly marked. Set the gray bit and push it onto the mark stack.
       CHECK(!kUseBakerReadBarrier || obj->GetReadBarrierPointer() == ReadBarrier::GrayPtr());
-      collector_->PushOntoMarkStack<true>(obj);
+      collector_->PushOntoMarkStack(obj);
     }
   }
 
  private:
-  ConcurrentCopying* collector_;
+  ConcurrentCopying* const collector_;
 };
 
 class EmptyCheckpoint : public Closure {
@@ -319,6 +347,7 @@
   if (kVerboseMode) {
     LOG(INFO) << "GC MarkingPhase";
   }
+  CHECK(weak_ref_access_enabled_);
   {
     // Mark the image root. The WB-based collectors do not need to
     // scan the image objects from roots by relying on the card table,
@@ -334,6 +363,8 @@
       }
     }
   }
+  // TODO: Other garbage collectors uses Runtime::VisitConcurrentRoots(), refactor this part
+  // to also use the same function.
   {
     TimingLogger::ScopedTiming split2("VisitConstantRoots", GetTimings());
     Runtime::Current()->VisitConstantRoots(this);
@@ -351,6 +382,7 @@
     TimingLogger::ScopedTiming split5("VisitNonThreadRoots", GetTimings());
     Runtime::Current()->VisitNonThreadRoots(this);
   }
+  Runtime::Current()->GetHeap()->VisitAllocationRecords(this);
 
   // Immune spaces.
   for (auto& space : heap_->GetContinuousSpaces()) {
@@ -367,37 +399,47 @@
   Thread* self = Thread::Current();
   {
     TimingLogger::ScopedTiming split6("ProcessMarkStack", GetTimings());
-    // Process the mark stack and issue an empty check point. If the
-    // mark stack is still empty after the check point, we're
-    // done. Otherwise, repeat.
+    // We transition through three mark stack modes (thread-local, shared, GC-exclusive). The
+    // primary reasons are the fact that we need to use a checkpoint to process thread-local mark
+    // stacks, but after we disable weak refs accesses, we can't use a checkpoint due to a deadlock
+    // issue because running threads potentially blocking at WaitHoldingLocks, and that once we
+    // reach the point where we process weak references, we can avoid using a lock when accessing
+    // the GC mark stack, which makes mark stack processing more efficient.
+
+    // Process the mark stack once in the thread local stack mode. This marks most of the live
+    // objects, aside from weak ref accesses with read barriers (Reference::GetReferent() and system
+    // weaks) that may happen concurrently while we processing the mark stack and newly mark/gray
+    // objects and push refs on the mark stack.
     ProcessMarkStack();
-    size_t count = 0;
-    while (!ProcessMarkStack()) {
-      ++count;
-      if (kVerboseMode) {
-        LOG(INFO) << "Issue an empty check point. " << count;
-      }
-      IssueEmptyCheckpoint();
-    }
-    // Need to ensure the mark stack is empty before reference
-    // processing to get rid of non-reference gray objects.
-    CheckEmptyMarkQueue();
-    // Enable the GetReference slow path and disallow access to the system weaks.
-    GetHeap()->GetReferenceProcessor()->EnableSlowPath();
-    Runtime::Current()->DisallowNewSystemWeaks();
-    QuasiAtomic::ThreadFenceForConstructor();
-    // Lock-unlock the system weak locks so that there's no thread in
-    // the middle of accessing system weaks.
-    Runtime::Current()->EnsureNewSystemWeaksDisallowed();
-    // Note: Do not issue a checkpoint from here to the
-    // SweepSystemWeaks call or else a deadlock due to
-    // WaitHoldingLocks() would occur.
+    // Switch to the shared mark stack mode. That is, revoke and process thread-local mark stacks
+    // for the last time before transitioning to the shared mark stack mode, which would process new
+    // refs that may have been concurrently pushed onto the mark stack during the ProcessMarkStack()
+    // call above. At the same time, disable weak ref accesses using a per-thread flag. It's
+    // important to do these together in a single checkpoint so that we can ensure that mutators
+    // won't newly gray objects and push new refs onto the mark stack due to weak ref accesses and
+    // mutators safely transition to the shared mark stack mode (without leaving unprocessed refs on
+    // the thread-local mark stacks), without a race. This is why we use a thread-local weak ref
+    // access flag Thread::tls32_.weak_ref_access_enabled_ instead of the global ones.
+    SwitchToSharedMarkStackMode();
+    CHECK(!self->GetWeakRefAccessEnabled());
+    // Now that weak refs accesses are disabled, once we exhaust the shared mark stack again here
+    // (which may be non-empty if there were refs found on thread-local mark stacks during the above
+    // SwitchToSharedMarkStackMode() call), we won't have new refs to process, that is, mutators
+    // (via read barriers) have no way to produce any more refs to process. Marking converges once
+    // before we process weak refs below.
+    ProcessMarkStack();
+    CheckEmptyMarkStack();
+    // Switch to the GC exclusive mark stack mode so that we can process the mark stack without a
+    // lock from this point on.
+    SwitchToGcExclusiveMarkStackMode();
+    CheckEmptyMarkStack();
     if (kVerboseMode) {
-      LOG(INFO) << "Enabled the ref proc slow path & disabled access to system weaks.";
       LOG(INFO) << "ProcessReferences";
     }
-    ProcessReferences(self, true);
-    CheckEmptyMarkQueue();
+    // Process weak references. This may produce new refs to process and have them processed via
+    // ProcessMarkStack (in the GC exclusive mark stack mode).
+    ProcessReferences(self);
+    CheckEmptyMarkStack();
     if (kVerboseMode) {
       LOG(INFO) << "SweepSystemWeaks";
     }
@@ -405,33 +447,52 @@
     if (kVerboseMode) {
       LOG(INFO) << "SweepSystemWeaks done";
     }
-    // Because hash_set::Erase() can call the hash function for
-    // arbitrary elements in the weak intern table in
-    // InternTable::Table::SweepWeaks(), the above SweepSystemWeaks()
-    // call may have marked some objects (strings) alive. So process
-    // the mark stack here once again.
+    // Process the mark stack here one last time because the above SweepSystemWeaks() call may have
+    // marked some objects (strings alive) as hash_set::Erase() can call the hash function for
+    // arbitrary elements in the weak intern table in InternTable::Table::SweepWeaks().
     ProcessMarkStack();
-    CheckEmptyMarkQueue();
-    if (kVerboseMode) {
-      LOG(INFO) << "AllowNewSystemWeaks";
-    }
-    Runtime::Current()->AllowNewSystemWeaks();
+    CheckEmptyMarkStack();
+    // Re-enable weak ref accesses.
+    ReenableWeakRefAccess(self);
+    // Issue an empty checkpoint to ensure no threads are still in the middle of a read barrier
+    // which may have a from-space ref cached in a local variable.
     IssueEmptyCheckpoint();
-    // Disable marking.
+    // Marking is done. Disable marking.
     if (kUseTableLookupReadBarrier) {
       heap_->rb_table_->ClearAll();
       DCHECK(heap_->rb_table_->IsAllCleared());
     }
-    is_mark_queue_push_disallowed_.StoreSequentiallyConsistent(1);
-    is_marking_ = false;
-    CheckEmptyMarkQueue();
+    is_mark_stack_push_disallowed_.StoreSequentiallyConsistent(1);
+    is_marking_ = false;  // This disables the read barrier/marking of weak roots.
+    mark_stack_mode_.StoreSequentiallyConsistent(kMarkStackModeOff);
+    CheckEmptyMarkStack();
   }
 
+  CHECK(weak_ref_access_enabled_);
   if (kVerboseMode) {
     LOG(INFO) << "GC end of MarkingPhase";
   }
 }
 
+void ConcurrentCopying::ReenableWeakRefAccess(Thread* self) {
+  if (kVerboseMode) {
+    LOG(INFO) << "ReenableWeakRefAccess";
+  }
+  weak_ref_access_enabled_.StoreRelaxed(true);  // This is for new threads.
+  QuasiAtomic::ThreadFenceForConstructor();
+  // Iterate all threads (don't need to or can't use a checkpoint) and re-enable weak ref access.
+  {
+    MutexLock mu(self, *Locks::thread_list_lock_);
+    std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
+    for (Thread* thread : thread_list) {
+      thread->SetWeakRefAccessEnabled(true);
+    }
+  }
+  // Unblock blocking threads.
+  GetHeap()->GetReferenceProcessor()->BroadcastForSlowPath(self);
+  Runtime::Current()->BroadcastForNewSystemWeaks();
+}
+
 void ConcurrentCopying::IssueEmptyCheckpoint() {
   Thread* self = Thread::Current();
   EmptyCheckpoint check_point(this);
@@ -452,18 +513,61 @@
   Locks::mutator_lock_->SharedLock(self);
 }
 
-mirror::Object* ConcurrentCopying::PopOffMarkStack() {
-  return mark_queue_.Dequeue();
-}
-
-template<bool kThreadSafe>
 void ConcurrentCopying::PushOntoMarkStack(mirror::Object* to_ref) {
-  CHECK_EQ(is_mark_queue_push_disallowed_.LoadRelaxed(), 0)
+  CHECK_EQ(is_mark_stack_push_disallowed_.LoadRelaxed(), 0)
       << " " << to_ref << " " << PrettyTypeOf(to_ref);
-  if (kThreadSafe) {
-    CHECK(mark_queue_.Enqueue(to_ref)) << "Mark queue overflow";
+  Thread* self = Thread::Current();  // TODO: pass self as an argument from call sites?
+  CHECK(thread_running_gc_ != nullptr);
+  MarkStackMode mark_stack_mode = mark_stack_mode_.LoadRelaxed();
+  if (mark_stack_mode == kMarkStackModeThreadLocal) {
+    if (self == thread_running_gc_) {
+      // If GC-running thread, use the GC mark stack instead of a thread-local mark stack.
+      CHECK(self->GetThreadLocalMarkStack() == nullptr);
+      CHECK(!gc_mark_stack_->IsFull());
+      gc_mark_stack_->PushBack(to_ref);
+    } else {
+      // Otherwise, use a thread-local mark stack.
+      accounting::AtomicStack<mirror::Object>* tl_mark_stack = self->GetThreadLocalMarkStack();
+      if (UNLIKELY(tl_mark_stack == nullptr || tl_mark_stack->IsFull())) {
+        MutexLock mu(self, mark_stack_lock_);
+        // Get a new thread local mark stack.
+        accounting::AtomicStack<mirror::Object>* new_tl_mark_stack;
+        if (!pooled_mark_stacks_.empty()) {
+          // Use a pooled mark stack.
+          new_tl_mark_stack = pooled_mark_stacks_.back();
+          pooled_mark_stacks_.pop_back();
+        } else {
+          // None pooled. Create a new one.
+          new_tl_mark_stack =
+              accounting::AtomicStack<mirror::Object>::Create(
+                  "thread local mark stack", 4 * KB, 4 * KB);
+        }
+        DCHECK(new_tl_mark_stack != nullptr);
+        DCHECK(new_tl_mark_stack->IsEmpty());
+        new_tl_mark_stack->PushBack(to_ref);
+        self->SetThreadLocalMarkStack(new_tl_mark_stack);
+        if (tl_mark_stack != nullptr) {
+          // Store the old full stack into a vector.
+          revoked_mark_stacks_.push_back(tl_mark_stack);
+        }
+      } else {
+        tl_mark_stack->PushBack(to_ref);
+      }
+    }
+  } else if (mark_stack_mode == kMarkStackModeShared) {
+    // Access the shared GC mark stack with a lock.
+    MutexLock mu(self, mark_stack_lock_);
+    CHECK(!gc_mark_stack_->IsFull());
+    gc_mark_stack_->PushBack(to_ref);
   } else {
-    CHECK(mark_queue_.EnqueueThreadUnsafe(to_ref)) << "Mark queue overflow";
+    CHECK_EQ(static_cast<uint32_t>(mark_stack_mode),
+             static_cast<uint32_t>(kMarkStackModeGcExclusive));
+    CHECK(self == thread_running_gc_)
+        << "Only GC-running thread should access the mark stack "
+        << "in the GC exclusive mark stack mode";
+    // Access the GC mark stack without a lock.
+    CHECK(!gc_mark_stack_->IsFull());
+    gc_mark_stack_->PushBack(to_ref);
   }
 }
 
@@ -548,7 +652,7 @@
   }
 
  private:
-  ConcurrentCopying* collector_;
+  ConcurrentCopying* const collector_;
 };
 
 class ConcurrentCopyingVerifyNoFromSpaceRefsObjectVisitor {
@@ -636,16 +740,9 @@
     }
     collector_->AssertToSpaceInvariant(nullptr, MemberOffset(0), ref);
   }
-  static void RootCallback(mirror::Object** root, void *arg, const RootInfo& /*root_info*/)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ConcurrentCopying* collector = reinterpret_cast<ConcurrentCopying*>(arg);
-    ConcurrentCopyingAssertToSpaceInvariantRefsVisitor visitor(collector);
-    DCHECK(root != nullptr);
-    visitor(*root);
-  }
 
  private:
-  ConcurrentCopying* collector_;
+  ConcurrentCopying* const collector_;
 };
 
 class ConcurrentCopyingAssertToSpaceInvariantFieldVisitor {
@@ -666,7 +763,7 @@
   }
 
  private:
-  ConcurrentCopying* collector_;
+  ConcurrentCopying* const collector_;
 };
 
 class ConcurrentCopyingAssertToSpaceInvariantObjectVisitor {
@@ -689,93 +786,310 @@
   }
 
  private:
-  ConcurrentCopying* collector_;
+  ConcurrentCopying* const collector_;
 };
 
-bool ConcurrentCopying::ProcessMarkStack() {
+class RevokeThreadLocalMarkStackCheckpoint : public Closure {
+ public:
+  explicit RevokeThreadLocalMarkStackCheckpoint(ConcurrentCopying* concurrent_copying,
+                                                bool disable_weak_ref_access)
+      : concurrent_copying_(concurrent_copying),
+        disable_weak_ref_access_(disable_weak_ref_access) {
+  }
+
+  virtual void Run(Thread* thread) OVERRIDE NO_THREAD_SAFETY_ANALYSIS {
+    // Note: self is not necessarily equal to thread since thread may be suspended.
+    Thread* self = Thread::Current();
+    CHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
+        << thread->GetState() << " thread " << thread << " self " << self;
+    // Revoke thread local mark stacks.
+    accounting::AtomicStack<mirror::Object>* tl_mark_stack = thread->GetThreadLocalMarkStack();
+    if (tl_mark_stack != nullptr) {
+      MutexLock mu(self, concurrent_copying_->mark_stack_lock_);
+      concurrent_copying_->revoked_mark_stacks_.push_back(tl_mark_stack);
+      thread->SetThreadLocalMarkStack(nullptr);
+    }
+    // Disable weak ref access.
+    if (disable_weak_ref_access_) {
+      thread->SetWeakRefAccessEnabled(false);
+    }
+    // If thread is a running mutator, then act on behalf of the garbage collector.
+    // See the code in ThreadList::RunCheckpoint.
+    if (thread->GetState() == kRunnable) {
+      concurrent_copying_->GetBarrier().Pass(self);
+    }
+  }
+
+ private:
+  ConcurrentCopying* const concurrent_copying_;
+  const bool disable_weak_ref_access_;
+};
+
+void ConcurrentCopying::RevokeThreadLocalMarkStacks(bool disable_weak_ref_access) {
+  Thread* self = Thread::Current();
+  RevokeThreadLocalMarkStackCheckpoint check_point(this, disable_weak_ref_access);
+  ThreadList* thread_list = Runtime::Current()->GetThreadList();
+  gc_barrier_->Init(self, 0);
+  size_t barrier_count = thread_list->RunCheckpoint(&check_point);
+  // If there are no threads to wait which implys that all the checkpoint functions are finished,
+  // then no need to release the mutator lock.
+  if (barrier_count == 0) {
+    return;
+  }
+  Locks::mutator_lock_->SharedUnlock(self);
+  {
+    ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+    gc_barrier_->Increment(self, barrier_count);
+  }
+  Locks::mutator_lock_->SharedLock(self);
+}
+
+void ConcurrentCopying::RevokeThreadLocalMarkStack(Thread* thread) {
+  Thread* self = Thread::Current();
+  CHECK_EQ(self, thread);
+  accounting::AtomicStack<mirror::Object>* tl_mark_stack = thread->GetThreadLocalMarkStack();
+  if (tl_mark_stack != nullptr) {
+    CHECK(is_marking_);
+    MutexLock mu(self, mark_stack_lock_);
+    revoked_mark_stacks_.push_back(tl_mark_stack);
+    thread->SetThreadLocalMarkStack(nullptr);
+  }
+}
+
+void ConcurrentCopying::ProcessMarkStack() {
   if (kVerboseMode) {
     LOG(INFO) << "ProcessMarkStack. ";
   }
-  size_t count = 0;
-  mirror::Object* to_ref;
-  while ((to_ref = PopOffMarkStack()) != nullptr) {
-    ++count;
-    DCHECK(!region_space_->IsInFromSpace(to_ref));
-    if (kUseBakerReadBarrier) {
-      DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr())
-          << " " << to_ref << " " << to_ref->GetReadBarrierPointer()
-          << " is_marked=" << IsMarked(to_ref);
+  bool empty_prev = false;
+  while (true) {
+    bool empty = ProcessMarkStackOnce();
+    if (empty_prev && empty) {
+      // Saw empty mark stack for a second time, done.
+      break;
     }
-    // Scan ref fields.
-    Scan(to_ref);
-    // Mark the gray ref as white or black.
-    if (kUseBakerReadBarrier) {
-      DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr())
-          << " " << to_ref << " " << to_ref->GetReadBarrierPointer()
-          << " is_marked=" << IsMarked(to_ref);
-    }
-    if (to_ref->GetClass<kVerifyNone, kWithoutReadBarrier>()->IsTypeOfReferenceClass() &&
-        to_ref->AsReference()->GetReferent<kWithoutReadBarrier>() != nullptr &&
-        !IsInToSpace(to_ref->AsReference()->GetReferent<kWithoutReadBarrier>())) {
-      // Leave References gray so that GetReferent() will trigger RB.
-      CHECK(to_ref->AsReference()->IsEnqueued()) << "Left unenqueued ref gray " << to_ref;
-    } else {
-#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
-      if (kUseBakerReadBarrier) {
-        if (region_space_->IsInToSpace(to_ref)) {
-          // If to-space, change from gray to white.
-          bool success = to_ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(),
-                                                             ReadBarrier::WhitePtr());
-          CHECK(success) << "Must succeed as we won the race.";
-          CHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::WhitePtr());
-        } else {
-          // If non-moving space/unevac from space, change from gray
-          // to black. We can't change gray to white because it's not
-          // safe to use CAS if two threads change values in opposite
-          // directions (A->B and B->A). So, we change it to black to
-          // indicate non-moving objects that have been marked
-          // through. Note we'd need to change from black to white
-          // later (concurrently).
-          bool success = to_ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(),
-                                                             ReadBarrier::BlackPtr());
-          CHECK(success) << "Must succeed as we won the race.";
-          CHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::BlackPtr());
-        }
-      }
-#else
-      DCHECK(!kUseBakerReadBarrier);
-#endif
-    }
-    if (ReadBarrier::kEnableToSpaceInvariantChecks || kIsDebugBuild) {
-      ConcurrentCopyingAssertToSpaceInvariantObjectVisitor visitor(this);
-      visitor(to_ref);
-    }
+    empty_prev = empty;
   }
+}
+
+bool ConcurrentCopying::ProcessMarkStackOnce() {
+  Thread* self = Thread::Current();
+  CHECK(thread_running_gc_ != nullptr);
+  CHECK(self == thread_running_gc_);
+  CHECK(self->GetThreadLocalMarkStack() == nullptr);
+  size_t count = 0;
+  MarkStackMode mark_stack_mode = mark_stack_mode_.LoadRelaxed();
+  if (mark_stack_mode == kMarkStackModeThreadLocal) {
+    // Process the thread-local mark stacks and the GC mark stack.
+    count += ProcessThreadLocalMarkStacks(false);
+    while (!gc_mark_stack_->IsEmpty()) {
+      mirror::Object* to_ref = gc_mark_stack_->PopBack();
+      ProcessMarkStackRef(to_ref);
+      ++count;
+    }
+    gc_mark_stack_->Reset();
+  } else if (mark_stack_mode == kMarkStackModeShared) {
+    // Process the shared GC mark stack with a lock.
+    {
+      MutexLock mu(self, mark_stack_lock_);
+      CHECK(revoked_mark_stacks_.empty());
+    }
+    while (true) {
+      std::vector<mirror::Object*> refs;
+      {
+        // Copy refs with lock. Note the number of refs should be small.
+        MutexLock mu(self, mark_stack_lock_);
+        if (gc_mark_stack_->IsEmpty()) {
+          break;
+        }
+        for (StackReference<mirror::Object>* p = gc_mark_stack_->Begin();
+             p != gc_mark_stack_->End(); ++p) {
+          refs.push_back(p->AsMirrorPtr());
+        }
+        gc_mark_stack_->Reset();
+      }
+      for (mirror::Object* ref : refs) {
+        ProcessMarkStackRef(ref);
+        ++count;
+      }
+    }
+  } else {
+    CHECK_EQ(static_cast<uint32_t>(mark_stack_mode),
+             static_cast<uint32_t>(kMarkStackModeGcExclusive));
+    {
+      MutexLock mu(self, mark_stack_lock_);
+      CHECK(revoked_mark_stacks_.empty());
+    }
+    // Process the GC mark stack in the exclusive mode. No need to take the lock.
+    while (!gc_mark_stack_->IsEmpty()) {
+      mirror::Object* to_ref = gc_mark_stack_->PopBack();
+      ProcessMarkStackRef(to_ref);
+      ++count;
+    }
+    gc_mark_stack_->Reset();
+  }
+
   // Return true if the stack was empty.
   return count == 0;
 }
 
-void ConcurrentCopying::CheckEmptyMarkQueue() {
-  if (!mark_queue_.IsEmpty()) {
-    while (!mark_queue_.IsEmpty()) {
-      mirror::Object* obj = mark_queue_.Dequeue();
-      if (kUseBakerReadBarrier) {
-        mirror::Object* rb_ptr = obj->GetReadBarrierPointer();
-        LOG(INFO) << "On mark queue : " << obj << " " << PrettyTypeOf(obj) << " rb_ptr=" << rb_ptr
-                  << " is_marked=" << IsMarked(obj);
+size_t ConcurrentCopying::ProcessThreadLocalMarkStacks(bool disable_weak_ref_access) {
+  // Run a checkpoint to collect all thread local mark stacks and iterate over them all.
+  RevokeThreadLocalMarkStacks(disable_weak_ref_access);
+  size_t count = 0;
+  std::vector<accounting::AtomicStack<mirror::Object>*> mark_stacks;
+  {
+    MutexLock mu(Thread::Current(), mark_stack_lock_);
+    // Make a copy of the mark stack vector.
+    mark_stacks = revoked_mark_stacks_;
+    revoked_mark_stacks_.clear();
+  }
+  for (accounting::AtomicStack<mirror::Object>* mark_stack : mark_stacks) {
+    for (StackReference<mirror::Object>* p = mark_stack->Begin(); p != mark_stack->End(); ++p) {
+      mirror::Object* to_ref = p->AsMirrorPtr();
+      ProcessMarkStackRef(to_ref);
+      ++count;
+    }
+    {
+      MutexLock mu(Thread::Current(), mark_stack_lock_);
+      if (pooled_mark_stacks_.size() >= kMarkStackPoolSize) {
+        // The pool has enough. Delete it.
+        delete mark_stack;
       } else {
-        LOG(INFO) << "On mark queue : " << obj << " " << PrettyTypeOf(obj)
-                  << " is_marked=" << IsMarked(obj);
+        // Otherwise, put it into the pool for later reuse.
+        mark_stack->Reset();
+        pooled_mark_stacks_.push_back(mark_stack);
       }
     }
-    LOG(FATAL) << "mark queue is not empty";
+  }
+  return count;
+}
+
+void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) {
+  DCHECK(!region_space_->IsInFromSpace(to_ref));
+  if (kUseBakerReadBarrier) {
+    DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr())
+        << " " << to_ref << " " << to_ref->GetReadBarrierPointer()
+        << " is_marked=" << IsMarked(to_ref);
+  }
+  // Scan ref fields.
+  Scan(to_ref);
+  // Mark the gray ref as white or black.
+  if (kUseBakerReadBarrier) {
+    DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr())
+        << " " << to_ref << " " << to_ref->GetReadBarrierPointer()
+        << " is_marked=" << IsMarked(to_ref);
+  }
+  if (to_ref->GetClass<kVerifyNone, kWithoutReadBarrier>()->IsTypeOfReferenceClass() &&
+      to_ref->AsReference()->GetReferent<kWithoutReadBarrier>() != nullptr &&
+      !IsInToSpace(to_ref->AsReference()->GetReferent<kWithoutReadBarrier>())) {
+    // Leave References gray so that GetReferent() will trigger RB.
+    CHECK(to_ref->AsReference()->IsEnqueued()) << "Left unenqueued ref gray " << to_ref;
+  } else {
+#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
+    if (kUseBakerReadBarrier) {
+      if (region_space_->IsInToSpace(to_ref)) {
+        // If to-space, change from gray to white.
+        bool success = to_ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(),
+                                                           ReadBarrier::WhitePtr());
+        CHECK(success) << "Must succeed as we won the race.";
+        CHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::WhitePtr());
+      } else {
+        // If non-moving space/unevac from space, change from gray
+        // to black. We can't change gray to white because it's not
+        // safe to use CAS if two threads change values in opposite
+        // directions (A->B and B->A). So, we change it to black to
+        // indicate non-moving objects that have been marked
+        // through. Note we'd need to change from black to white
+        // later (concurrently).
+        bool success = to_ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(),
+                                                           ReadBarrier::BlackPtr());
+        CHECK(success) << "Must succeed as we won the race.";
+        CHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::BlackPtr());
+      }
+    }
+#else
+    DCHECK(!kUseBakerReadBarrier);
+#endif
+  }
+  if (ReadBarrier::kEnableToSpaceInvariantChecks || kIsDebugBuild) {
+    ConcurrentCopyingAssertToSpaceInvariantObjectVisitor visitor(this);
+    visitor(to_ref);
+  }
+}
+
+void ConcurrentCopying::SwitchToSharedMarkStackMode() {
+  Thread* self = Thread::Current();
+  CHECK(thread_running_gc_ != nullptr);
+  CHECK_EQ(self, thread_running_gc_);
+  CHECK(self->GetThreadLocalMarkStack() == nullptr);
+  MarkStackMode before_mark_stack_mode = mark_stack_mode_.LoadRelaxed();
+  CHECK_EQ(static_cast<uint32_t>(before_mark_stack_mode),
+           static_cast<uint32_t>(kMarkStackModeThreadLocal));
+  mark_stack_mode_.StoreRelaxed(kMarkStackModeShared);
+  CHECK(weak_ref_access_enabled_.LoadRelaxed());
+  weak_ref_access_enabled_.StoreRelaxed(false);
+  QuasiAtomic::ThreadFenceForConstructor();
+  // Process the thread local mark stacks one last time after switching to the shared mark stack
+  // mode and disable weak ref accesses.
+  ProcessThreadLocalMarkStacks(true);
+  if (kVerboseMode) {
+    LOG(INFO) << "Switched to shared mark stack mode and disabled weak ref access";
+  }
+}
+
+void ConcurrentCopying::SwitchToGcExclusiveMarkStackMode() {
+  Thread* self = Thread::Current();
+  CHECK(thread_running_gc_ != nullptr);
+  CHECK_EQ(self, thread_running_gc_);
+  CHECK(self->GetThreadLocalMarkStack() == nullptr);
+  MarkStackMode before_mark_stack_mode = mark_stack_mode_.LoadRelaxed();
+  CHECK_EQ(static_cast<uint32_t>(before_mark_stack_mode),
+           static_cast<uint32_t>(kMarkStackModeShared));
+  mark_stack_mode_.StoreRelaxed(kMarkStackModeGcExclusive);
+  QuasiAtomic::ThreadFenceForConstructor();
+  if (kVerboseMode) {
+    LOG(INFO) << "Switched to GC exclusive mark stack mode";
+  }
+}
+
+void ConcurrentCopying::CheckEmptyMarkStack() {
+  Thread* self = Thread::Current();
+  CHECK(thread_running_gc_ != nullptr);
+  CHECK_EQ(self, thread_running_gc_);
+  CHECK(self->GetThreadLocalMarkStack() == nullptr);
+  MarkStackMode mark_stack_mode = mark_stack_mode_.LoadRelaxed();
+  if (mark_stack_mode == kMarkStackModeThreadLocal) {
+    // Thread-local mark stack mode.
+    RevokeThreadLocalMarkStacks(false);
+    MutexLock mu(Thread::Current(), mark_stack_lock_);
+    if (!revoked_mark_stacks_.empty()) {
+      for (accounting::AtomicStack<mirror::Object>* mark_stack : revoked_mark_stacks_) {
+        while (!mark_stack->IsEmpty()) {
+          mirror::Object* obj = mark_stack->PopBack();
+          if (kUseBakerReadBarrier) {
+            mirror::Object* rb_ptr = obj->GetReadBarrierPointer();
+            LOG(INFO) << "On mark queue : " << obj << " " << PrettyTypeOf(obj) << " rb_ptr=" << rb_ptr
+                      << " is_marked=" << IsMarked(obj);
+          } else {
+            LOG(INFO) << "On mark queue : " << obj << " " << PrettyTypeOf(obj)
+                      << " is_marked=" << IsMarked(obj);
+          }
+        }
+      }
+      LOG(FATAL) << "mark stack is not empty";
+    }
+  } else {
+    // Shared, GC-exclusive, or off.
+    MutexLock mu(Thread::Current(), mark_stack_lock_);
+    CHECK(gc_mark_stack_->IsEmpty());
+    CHECK(revoked_mark_stacks_.empty());
   }
 }
 
 void ConcurrentCopying::SweepSystemWeaks(Thread* self) {
   TimingLogger::ScopedTiming split("SweepSystemWeaks", GetTimings());
   ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  Runtime::Current()->SweepSystemWeaks(IsMarkedCallback, this);
+  Runtime::Current()->SweepSystemWeaks(this);
 }
 
 void ConcurrentCopying::Sweep(bool swap_bitmaps) {
@@ -788,7 +1102,7 @@
     heap_->MarkAllocStackAsLive(live_stack);
     live_stack->Reset();
   }
-  CHECK(mark_queue_.IsEmpty());
+  CheckEmptyMarkStack();
   TimingLogger::ScopedTiming split("Sweep", GetTimings());
   for (const auto& space : GetHeap()->GetContinuousSpaces()) {
     if (space->IsContinuousMemMapAllocSpace()) {
@@ -884,8 +1198,8 @@
     }
     IssueEmptyCheckpoint();
     // Disable the check.
-    is_mark_queue_push_disallowed_.StoreSequentiallyConsistent(0);
-    CheckEmptyMarkQueue();
+    is_mark_stack_push_disallowed_.StoreSequentiallyConsistent(0);
+    CheckEmptyMarkStack();
   }
 
   {
@@ -952,6 +1266,8 @@
     region_space_bitmap_ = nullptr;
   }
 
+  CheckEmptyMarkStack();
+
   if (kVerboseMode) {
     LOG(INFO) << "GC end of ReclaimPhase";
   }
@@ -978,7 +1294,7 @@
   }
 
  private:
-  ConcurrentCopying* collector_;
+  ConcurrentCopying* const collector_;
 };
 
 // Compute how much live objects are left in regions.
@@ -1271,7 +1587,7 @@
 // Fill the given memory block with a dummy object. Used to fill in a
 // copy of objects that was lost in race.
 void ConcurrentCopying::FillWithDummyObject(mirror::Object* dummy_obj, size_t byte_size) {
-  CHECK(IsAligned<kObjectAlignment>(byte_size));
+  CHECK_ALIGNED(byte_size, kObjectAlignment);
   memset(dummy_obj, 0, byte_size);
   mirror::Class* int_array_class = mirror::IntArray::GetArrayClass();
   CHECK(int_array_class != nullptr);
@@ -1304,7 +1620,7 @@
 // Reuse the memory blocks that were copy of objects that were lost in race.
 mirror::Object* ConcurrentCopying::AllocateInSkippedBlock(size_t alloc_size) {
   // Try to reuse the blocks that were unused due to CAS failures.
-  CHECK(IsAligned<space::RegionSpace::kAlignment>(alloc_size));
+  CHECK_ALIGNED(alloc_size, space::RegionSpace::kAlignment);
   Thread* self = Thread::Current();
   size_t min_object_size = RoundUp(sizeof(mirror::Object), space::RegionSpace::kAlignment);
   MutexLock mu(self, skipped_blocks_lock_);
@@ -1323,7 +1639,7 @@
         // Not found.
         return nullptr;
       }
-      CHECK(IsAligned<space::RegionSpace::kAlignment>(it->first - alloc_size));
+      CHECK_ALIGNED(it->first - alloc_size, space::RegionSpace::kAlignment);
       CHECK_GE(it->first - alloc_size, min_object_size)
           << "byte_size=" << byte_size << " it->first=" << it->first << " alloc_size=" << alloc_size;
     }
@@ -1334,7 +1650,7 @@
   uint8_t* addr = it->second;
   CHECK_GE(byte_size, alloc_size);
   CHECK(region_space_->IsInToSpace(reinterpret_cast<mirror::Object*>(addr)));
-  CHECK(IsAligned<space::RegionSpace::kAlignment>(byte_size));
+  CHECK_ALIGNED(byte_size, space::RegionSpace::kAlignment);
   if (kVerboseMode) {
     LOG(INFO) << "Reusing skipped bytes : " << reinterpret_cast<void*>(addr) << ", " << byte_size;
   }
@@ -1342,7 +1658,7 @@
   memset(addr, 0, byte_size);
   if (byte_size > alloc_size) {
     // Return the remainder to the map.
-    CHECK(IsAligned<space::RegionSpace::kAlignment>(byte_size - alloc_size));
+    CHECK_ALIGNED(byte_size - alloc_size, space::RegionSpace::kAlignment);
     CHECK_GE(byte_size - alloc_size, min_object_size);
     FillWithDummyObject(reinterpret_cast<mirror::Object*>(addr + alloc_size),
                         byte_size - alloc_size);
@@ -1475,7 +1791,7 @@
       }
       DCHECK(GetFwdPtr(from_ref) == to_ref);
       CHECK_NE(to_ref->GetLockWord(false).GetState(), LockWord::kForwardingAddress);
-      PushOntoMarkStack<true>(to_ref);
+      PushOntoMarkStack(to_ref);
       return to_ref;
     } else {
       // The CAS failed. It may have lost the race or may have failed
@@ -1608,7 +1924,7 @@
       if (kUseBakerReadBarrier) {
         DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr());
       }
-      PushOntoMarkStack<true>(to_ref);
+      PushOntoMarkStack(to_ref);
     }
   } else {
     // from_ref is in a non-moving space.
@@ -1635,7 +1951,7 @@
         if (kUseBakerReadBarrier) {
           DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr());
         }
-        PushOntoMarkStack<true>(to_ref);
+        PushOntoMarkStack(to_ref);
       }
     } else {
       // Use the mark bitmap.
@@ -1691,7 +2007,7 @@
             if (kUseBakerReadBarrier) {
               DCHECK(to_ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr());
             }
-            PushOntoMarkStack<true>(to_ref);
+            PushOntoMarkStack(to_ref);
           }
         }
       }
@@ -1701,9 +2017,11 @@
 }
 
 void ConcurrentCopying::FinishPhase() {
+  {
+    MutexLock mu(Thread::Current(), mark_stack_lock_);
+    CHECK_EQ(pooled_mark_stacks_.size(), kMarkStackPoolSize);
+  }
   region_space_ = nullptr;
-  CHECK(mark_queue_.IsEmpty());
-  mark_queue_.Clear();
   {
     MutexLock mu(Thread::Current(), skipped_blocks_lock_);
     skipped_blocks_map_.clear();
@@ -1712,14 +2030,9 @@
   heap_->ClearMarkedObjects();
 }
 
-mirror::Object* ConcurrentCopying::IsMarkedCallback(mirror::Object* from_ref, void* arg) {
-  return reinterpret_cast<ConcurrentCopying*>(arg)->IsMarked(from_ref);
-}
-
-bool ConcurrentCopying::IsHeapReferenceMarkedCallback(
-    mirror::HeapReference<mirror::Object>* field, void* arg) {
+bool ConcurrentCopying::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* field) {
   mirror::Object* from_ref = field->AsMirrorPtr();
-  mirror::Object* to_ref = reinterpret_cast<ConcurrentCopying*>(arg)->IsMarked(from_ref);
+  mirror::Object* to_ref = IsMarked(from_ref);
   if (to_ref == nullptr) {
     return false;
   }
@@ -1731,25 +2044,20 @@
   return true;
 }
 
-mirror::Object* ConcurrentCopying::MarkCallback(mirror::Object* from_ref, void* arg) {
-  return reinterpret_cast<ConcurrentCopying*>(arg)->Mark(from_ref);
-}
-
-void ConcurrentCopying::ProcessMarkStackCallback(void* arg) {
-  reinterpret_cast<ConcurrentCopying*>(arg)->ProcessMarkStack();
+mirror::Object* ConcurrentCopying::MarkObject(mirror::Object* from_ref) {
+  return Mark(from_ref);
 }
 
 void ConcurrentCopying::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference) {
-  heap_->GetReferenceProcessor()->DelayReferenceReferent(
-      klass, reference, &IsHeapReferenceMarkedCallback, this);
+  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, reference, this);
 }
 
-void ConcurrentCopying::ProcessReferences(Thread* self, bool concurrent) {
+void ConcurrentCopying::ProcessReferences(Thread* self) {
   TimingLogger::ScopedTiming split("ProcessReferences", GetTimings());
+  // We don't really need to lock the heap bitmap lock as we use CAS to mark in bitmaps.
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   GetHeap()->GetReferenceProcessor()->ProcessReferences(
-      concurrent, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
-      &IsHeapReferenceMarkedCallback, &MarkCallback, &ProcessMarkStackCallback, this);
+      true /*concurrent*/, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(), this);
 }
 
 void ConcurrentCopying::RevokeAllThreadLocalBuffers() {
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index b1897b8..f1317b8 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -49,89 +49,6 @@
 
 namespace collector {
 
-// Concurrent queue. Used as the mark stack. TODO: use a concurrent
-// stack for locality.
-class MarkQueue {
- public:
-  explicit MarkQueue(size_t size) : size_(size) {
-    CHECK(IsPowerOfTwo(size_));
-    buf_.reset(new Atomic<mirror::Object*>[size_]);
-    CHECK(buf_.get() != nullptr);
-    Clear();
-  }
-
-  ALWAYS_INLINE Atomic<mirror::Object*>* GetSlotAddr(size_t index) {
-    return &(buf_.get()[index & (size_ - 1)]);
-  }
-
-  // Multiple-proceducer enqueue.
-  bool Enqueue(mirror::Object* to_ref) {
-    size_t t;
-    do {
-      t = tail_.LoadRelaxed();
-      size_t h = head_.LoadSequentiallyConsistent();
-      if (t + size_ == h) {
-        // It's full.
-        return false;
-      }
-    } while (!tail_.CompareExchangeWeakSequentiallyConsistent(t, t + 1));
-    // We got a slot but its content has not been filled yet at this point.
-    GetSlotAddr(t)->StoreSequentiallyConsistent(to_ref);
-    return true;
-  }
-
-  // Thread-unsafe.
-  bool EnqueueThreadUnsafe(mirror::Object* to_ref) {
-    size_t t = tail_.LoadRelaxed();
-    size_t h = head_.LoadRelaxed();
-    if (t + size_ == h) {
-      // It's full.
-      return false;
-    }
-    GetSlotAddr(t)->StoreRelaxed(to_ref);
-    tail_.StoreRelaxed(t + 1);
-    return true;
-  }
-
-  // Single-consumer dequeue.
-  mirror::Object* Dequeue() {
-    size_t h = head_.LoadRelaxed();
-    size_t t = tail_.LoadSequentiallyConsistent();
-    if (h == t) {
-      // it's empty.
-      return nullptr;
-    }
-    Atomic<mirror::Object*>* slot = GetSlotAddr(h);
-    mirror::Object* ref = slot->LoadSequentiallyConsistent();
-    while (ref == nullptr) {
-      // Wait until the slot content becomes visible.
-      ref = slot->LoadSequentiallyConsistent();
-    }
-    slot->StoreRelaxed(nullptr);
-    head_.StoreSequentiallyConsistent(h + 1);
-    return ref;
-  }
-
-  bool IsEmpty() {
-    size_t h = head_.LoadSequentiallyConsistent();
-    size_t t = tail_.LoadSequentiallyConsistent();
-    return h == t;
-  }
-
-  void Clear() {
-    head_.StoreRelaxed(0);
-    tail_.StoreRelaxed(0);
-    memset(buf_.get(), 0, size_ * sizeof(Atomic<mirror::Object*>));
-  }
-
- private:
-  Atomic<size_t> head_;
-  Atomic<size_t> tail_;
-
-  size_t size_;
-  std::unique_ptr<Atomic<mirror::Object*>[]> buf_;
-};
-
 class ConcurrentCopying : public GarbageCollector {
  public:
   // TODO: disable thse flags for production use.
@@ -185,10 +102,12 @@
   Barrier& GetBarrier() {
     return *gc_barrier_;
   }
+  bool IsWeakRefAccessEnabled() {
+    return weak_ref_access_enabled_.LoadRelaxed();
+  }
+  void RevokeThreadLocalMarkStack(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  mirror::Object* PopOffMarkStack();
-  template<bool kThreadSafe>
   void PushOntoMarkStack(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Object* Copy(mirror::Object* from_ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void Scan(mirror::Object* to_ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -202,20 +121,25 @@
   void VerifyNoFromSpaceReferences() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   accounting::ObjectStack* GetAllocationStack();
   accounting::ObjectStack* GetLiveStack();
-  bool ProcessMarkStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference)
+  virtual void ProcessMarkStack() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool ProcessMarkStackOnce() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void ProcessMarkStackRef(mirror::Object* to_ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  size_t ProcessThreadLocalMarkStacks(bool disable_weak_ref_access)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void ProcessReferences(Thread* self, bool concurrent)
+  void RevokeThreadLocalMarkStacks(bool disable_weak_ref_access)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::Object* IsMarked(mirror::Object* from_ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static mirror::Object* MarkCallback(mirror::Object* from_ref, void* arg)
+  void SwitchToSharedMarkStackMode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SwitchToGcExclusiveMarkStackMode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual void DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static mirror::Object* IsMarkedCallback(mirror::Object* from_ref, void* arg)
+  void ProcessReferences(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual mirror::Object* MarkObject(mirror::Object* from_ref) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static bool IsHeapReferenceMarkedCallback(
-      mirror::HeapReference<mirror::Object>* field, void* arg)
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* from_ref) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void ProcessMarkStackCallback(void* arg)
+  virtual mirror::Object* IsMarked(mirror::Object* from_ref) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* field) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SweepSystemWeaks(Thread* self)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
@@ -229,7 +153,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Object* AllocateInSkippedBlock(size_t alloc_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CheckEmptyMarkQueue() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void CheckEmptyMarkStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void IssueEmptyCheckpoint() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsOnAllocStack(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Object* GetFwdPtr(mirror::Object* from_ref)
@@ -242,10 +166,19 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj, mirror::Object* ref)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void ReenableWeakRefAccess(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   space::RegionSpace* region_space_;      // The underlying region space.
   std::unique_ptr<Barrier> gc_barrier_;
-  MarkQueue mark_queue_;
+  std::unique_ptr<accounting::ObjectStack> gc_mark_stack_;
+  Mutex mark_stack_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  std::vector<accounting::ObjectStack*> revoked_mark_stacks_
+      GUARDED_BY(mark_stack_lock_);
+  static constexpr size_t kMarkStackSize = kPageSize;
+  static constexpr size_t kMarkStackPoolSize = 256;
+  std::vector<accounting::ObjectStack*> pooled_mark_stacks_
+      GUARDED_BY(mark_stack_lock_);
+  Thread* thread_running_gc_;
   bool is_marking_;                       // True while marking is ongoing.
   bool is_active_;                        // True while the collection is ongoing.
   bool is_asserting_to_space_invariant_;  // True while asserting the to-space invariant.
@@ -258,7 +191,18 @@
   size_t live_stack_freeze_size_;
   size_t from_space_num_objects_at_first_pause_;
   size_t from_space_num_bytes_at_first_pause_;
-  Atomic<int> is_mark_queue_push_disallowed_;
+  Atomic<int> is_mark_stack_push_disallowed_;
+  enum MarkStackMode {
+    kMarkStackModeOff = 0,      // Mark stack is off.
+    kMarkStackModeThreadLocal,  // All threads except for the GC-running thread push refs onto
+                                // thread-local mark stacks. The GC-running thread pushes onto and
+                                // pops off the GC mark stack without a lock.
+    kMarkStackModeShared,       // All threads share the GC mark stack with a lock.
+    kMarkStackModeGcExclusive   // The GC-running thread pushes onto and pops from the GC mark stack
+                                // without a lock. Other threads won't access the mark stack.
+  };
+  Atomic<MarkStackMode> mark_stack_mode_;
+  Atomic<bool> weak_ref_access_enabled_;
 
   // How many objects and bytes we moved. Used for accounting.
   Atomic<size_t> bytes_moved_;
@@ -284,6 +228,7 @@
   friend class ThreadFlipVisitor;
   friend class FlipCallback;
   friend class ConcurrentCopyingComputeUnevacFromSpaceLiveRatioVisitor;
+  friend class RevokeThreadLocalMarkStackCheckpoint;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ConcurrentCopying);
 };
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index 9b76d1a..cfc4f96 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -17,6 +17,9 @@
 #ifndef ART_RUNTIME_GC_COLLECTOR_GARBAGE_COLLECTOR_H_
 #define ART_RUNTIME_GC_COLLECTOR_GARBAGE_COLLECTOR_H_
 
+#include <stdint.h>
+#include <vector>
+
 #include "base/histogram.h"
 #include "base/mutex.h"
 #include "base/timing_logger.h"
@@ -24,10 +27,16 @@
 #include "gc/gc_cause.h"
 #include "gc_root.h"
 #include "gc_type.h"
-#include <stdint.h>
-#include <vector>
+#include "object_callbacks.h"
 
 namespace art {
+
+namespace mirror {
+class Class;
+class Object;
+class Reference;
+}  // namespace mirror
+
 namespace gc {
 
 class Heap;
@@ -113,7 +122,7 @@
   DISALLOW_COPY_AND_ASSIGN(Iteration);
 };
 
-class GarbageCollector : public RootVisitor {
+class GarbageCollector : public RootVisitor, public IsMarkedVisitor, public MarkObjectVisitor {
  public:
   class SCOPED_LOCKABLE ScopedPause {
    public:
@@ -172,6 +181,22 @@
   void RecordFreeLOS(const ObjectBytePair& freed);
   void DumpPerformanceInfo(std::ostream& os) LOCKS_EXCLUDED(pause_histogram_lock_);
 
+  // Helper functions for querying if objects are marked. These are used for processing references,
+  // and will be used for reading system weaks while the GC is running.
+  virtual mirror::Object* IsMarked(mirror::Object* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+  virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+  // Used by reference processor.
+  virtual void ProcessMarkStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+  // Force mark an object.
+  virtual mirror::Object* MarkObject(mirror::Object* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+  virtual void DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
  protected:
   // Run all of the GC phases.
   virtual void RunPhases() = 0;
diff --git a/runtime/gc/collector/gc_type.h b/runtime/gc/collector/gc_type.h
index f18e40f..401444a 100644
--- a/runtime/gc/collector/gc_type.h
+++ b/runtime/gc/collector/gc_type.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_COLLECTOR_GC_TYPE_H_
 #define ART_RUNTIME_GC_COLLECTOR_GC_TYPE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index 3c247cd..0623fd4 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -21,34 +21,19 @@
 #include "base/timing_logger.h"
 #include "gc/accounting/heap_bitmap-inl.h"
 #include "gc/accounting/mod_union_table.h"
-#include "gc/accounting/remembered_set.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
 #include "gc/reference_processor.h"
-#include "gc/space/bump_pointer_space.h"
 #include "gc/space/bump_pointer_space-inl.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 "mark_sweep-inl.h"
-#include "monitor.h"
 #include "mirror/class-inl.h"
-#include "mirror/class_loader.h"
-#include "mirror/dex_cache.h"
-#include "mirror/reference-inl.h"
 #include "mirror/object-inl.h"
-#include "mirror/object_array.h"
-#include "mirror/object_array-inl.h"
 #include "runtime.h"
 #include "stack.h"
 #include "thread-inl.h"
 #include "thread_list.h"
 
-using ::art::mirror::Object;
-
 namespace art {
 namespace gc {
 namespace collector {
@@ -67,7 +52,7 @@
 
 MarkCompact::MarkCompact(Heap* heap, const std::string& name_prefix)
     : GarbageCollector(heap, name_prefix + (name_prefix.empty() ? "" : " ") + "mark compact"),
-      space_(nullptr), collector_name_(name_) {
+      space_(nullptr), collector_name_(name_), updating_references_(false) {
 }
 
 void MarkCompact::RunPhases() {
@@ -107,7 +92,7 @@
   void operator()(mirror::Object* obj) const EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_,
                                                                       Locks::heap_bitmap_lock_) {
     DCHECK_ALIGNED(obj, space::BumpPointerSpace::kAlignment);
-    DCHECK(collector_->IsMarked(obj));
+    DCHECK(collector_->IsMarked(obj) != nullptr);
     collector_->ForwardObject(obj);
   }
 
@@ -141,8 +126,7 @@
 void MarkCompact::ProcessReferences(Thread* self) {
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   heap_->GetReferenceProcessor()->ProcessReferences(
-      false, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
-      &HeapReferenceMarkedCallback, &MarkObjectCallback, &ProcessMarkStackCallback, this);
+      false, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(), this);
 }
 
 class BitmapSetSlowPathVisitor {
@@ -156,29 +140,29 @@
   }
 };
 
-inline void MarkCompact::MarkObject(mirror::Object* obj) {
+inline mirror::Object* MarkCompact::MarkObject(mirror::Object* obj) {
   if (obj == nullptr) {
-    return;
+    return nullptr;
   }
   if (kUseBakerOrBrooksReadBarrier) {
     // Verify all the objects have the correct forward pointer installed.
     obj->AssertReadBarrierPointer();
   }
-  if (immune_region_.ContainsObject(obj)) {
-    return;
-  }
-  if (objects_before_forwarding_->HasAddress(obj)) {
-    if (!objects_before_forwarding_->Set(obj)) {
-      MarkStackPush(obj);  // This object was not previously marked.
-    }
-  } else {
-    DCHECK(!space_->HasAddress(obj));
-    BitmapSetSlowPathVisitor visitor;
-    if (!mark_bitmap_->Set(obj, visitor)) {
-      // This object was not previously marked.
-      MarkStackPush(obj);
+  if (!immune_region_.ContainsObject(obj)) {
+    if (objects_before_forwarding_->HasAddress(obj)) {
+      if (!objects_before_forwarding_->Set(obj)) {
+        MarkStackPush(obj);  // This object was not previously marked.
+      }
+    } else {
+      DCHECK(!space_->HasAddress(obj));
+      BitmapSetSlowPathVisitor visitor;
+      if (!mark_bitmap_->Set(obj, visitor)) {
+        // This object was not previously marked.
+        MarkStackPush(obj);
+      }
     }
   }
+  return obj;
 }
 
 void MarkCompact::MarkingPhase() {
@@ -240,7 +224,7 @@
         TimingLogger::ScopedTiming t2(
             space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
                                      "UpdateAndMarkImageModUnionTable", GetTimings());
-        table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
+        table->UpdateAndMarkReferences(this);
       }
     }
   }
@@ -272,7 +256,7 @@
 }
 
 void MarkCompact::ResizeMarkStack(size_t new_size) {
-  std::vector<StackReference<Object>> temp(mark_stack_->Begin(), mark_stack_->End());
+  std::vector<StackReference<mirror::Object>> temp(mark_stack_->Begin(), mark_stack_->End());
   CHECK_LE(mark_stack_->Size(), new_size);
   mark_stack_->Resize(new_size);
   for (auto& obj : temp) {
@@ -280,7 +264,7 @@
   }
 }
 
-inline void MarkCompact::MarkStackPush(Object* obj) {
+inline void MarkCompact::MarkStackPush(mirror::Object* obj) {
   if (UNLIKELY(mark_stack_->Size() >= mark_stack_->Capacity())) {
     ResizeMarkStack(mark_stack_->Capacity() * 2);
   }
@@ -288,23 +272,12 @@
   mark_stack_->PushBack(obj);
 }
 
-void MarkCompact::ProcessMarkStackCallback(void* arg) {
-  reinterpret_cast<MarkCompact*>(arg)->ProcessMarkStack();
-}
-
-mirror::Object* MarkCompact::MarkObjectCallback(mirror::Object* root, void* arg) {
-  reinterpret_cast<MarkCompact*>(arg)->MarkObject(root);
-  return root;
-}
-
-void MarkCompact::MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* obj_ptr,
-                                            void* arg) {
-  reinterpret_cast<MarkCompact*>(arg)->MarkObject(obj_ptr->AsMirrorPtr());
-}
-
-void MarkCompact::DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
-                                                 void* arg) {
-  reinterpret_cast<MarkCompact*>(arg)->DelayReferenceReferent(klass, ref);
+void MarkCompact::MarkHeapReference(mirror::HeapReference<mirror::Object>* obj_ptr) {
+  if (updating_references_) {
+    UpdateHeapReference(obj_ptr);
+  } else {
+    MarkObject(obj_ptr->AsMirrorPtr());
+  }
 }
 
 void MarkCompact::VisitRoots(
@@ -373,6 +346,7 @@
 
 void MarkCompact::UpdateReferences() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
+  updating_references_ = true;
   Runtime* runtime = Runtime::Current();
   // Update roots.
   UpdateRootVisitor update_root_visitor(this);
@@ -387,7 +361,7 @@
           space->IsZygoteSpace() ? "UpdateZygoteModUnionTableReferences" :
                                    "UpdateImageModUnionTableReferences",
                                    GetTimings());
-      table->UpdateAndMarkReferences(&UpdateHeapReferenceCallback, this);
+      table->UpdateAndMarkReferences(this);
     } else {
       // No mod union table, so we need to scan the space using bitmap visit.
       // Scan the space using bitmap visit.
@@ -403,14 +377,15 @@
   CHECK(!kMovingClasses)
       << "Didn't update large object classes since they are assumed to not move.";
   // Update the system weaks, these should already have been swept.
-  runtime->SweepSystemWeaks(&MarkedForwardingAddressCallback, this);
+  runtime->SweepSystemWeaks(this);
   // Update the objects in the bump pointer space last, these objects don't have a bitmap.
   UpdateObjectReferencesVisitor visitor(this);
   objects_before_forwarding_->VisitMarkedRange(reinterpret_cast<uintptr_t>(space_->Begin()),
                                                reinterpret_cast<uintptr_t>(space_->End()),
                                                visitor);
   // Update the reference processor cleared list.
-  heap_->GetReferenceProcessor()->UpdateRoots(&MarkedForwardingAddressCallback, this);
+  heap_->GetReferenceProcessor()->UpdateRoots(this);
+  updating_references_ = false;
 }
 
 void MarkCompact::Compact() {
@@ -436,10 +411,6 @@
   Runtime::Current()->VisitRoots(this);
 }
 
-mirror::Object* MarkCompact::MarkedForwardingAddressCallback(mirror::Object* obj, void* arg) {
-  return reinterpret_cast<MarkCompact*>(arg)->GetMarkedForwardAddress(obj);
-}
-
 inline void MarkCompact::UpdateHeapReference(mirror::HeapReference<mirror::Object>* reference) {
   mirror::Object* obj = reference->AsMirrorPtr();
   if (obj != nullptr) {
@@ -451,17 +422,12 @@
   }
 }
 
-void MarkCompact::UpdateHeapReferenceCallback(mirror::HeapReference<mirror::Object>* reference,
-                                              void* arg) {
-  reinterpret_cast<MarkCompact*>(arg)->UpdateHeapReference(reference);
-}
-
 class UpdateReferenceVisitor {
  public:
   explicit UpdateReferenceVisitor(MarkCompact* collector) : collector_(collector) {
   }
 
-  void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
+  void operator()(mirror::Object* obj, MemberOffset offset, bool /*is_static*/) const
       ALWAYS_INLINE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
     collector_->UpdateHeapReference(obj->GetFieldObjectReferenceAddr<kVerifyNone>(offset));
   }
@@ -481,7 +447,7 @@
   obj->VisitReferences<kMovingClasses>(visitor, visitor);
 }
 
-inline mirror::Object* MarkCompact::GetMarkedForwardAddress(mirror::Object* obj) const {
+inline mirror::Object* MarkCompact::GetMarkedForwardAddress(mirror::Object* obj) {
   DCHECK(obj != nullptr);
   if (objects_before_forwarding_->HasAddress(obj)) {
     DCHECK(objects_before_forwarding_->Test(obj));
@@ -491,33 +457,30 @@
     return ret;
   }
   DCHECK(!space_->HasAddress(obj));
-  DCHECK(IsMarked(obj));
   return obj;
 }
 
-inline bool MarkCompact::IsMarked(const Object* object) const {
+mirror::Object* MarkCompact::IsMarked(mirror::Object* object) {
   if (immune_region_.ContainsObject(object)) {
-    return true;
+    return object;
+  }
+  if (updating_references_) {
+    return GetMarkedForwardAddress(object);
   }
   if (objects_before_forwarding_->HasAddress(object)) {
-    return objects_before_forwarding_->Test(object);
+    return objects_before_forwarding_->Test(object) ? object : nullptr;
   }
-  return mark_bitmap_->Test(object);
+  return mark_bitmap_->Test(object) ? object : nullptr;
 }
 
-mirror::Object* MarkCompact::IsMarkedCallback(mirror::Object* object, void* arg) {
-  return reinterpret_cast<MarkCompact*>(arg)->IsMarked(object) ? object : nullptr;
-}
-
-bool MarkCompact::HeapReferenceMarkedCallback(mirror::HeapReference<mirror::Object>* ref_ptr,
-                                              void* arg) {
+bool MarkCompact::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref_ptr) {
   // Side effect free since we call this before ever moving objects.
-  return reinterpret_cast<MarkCompact*>(arg)->IsMarked(ref_ptr->AsMirrorPtr());
+  return IsMarked(ref_ptr->AsMirrorPtr()) != nullptr;
 }
 
 void MarkCompact::SweepSystemWeaks() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
-  Runtime::Current()->SweepSystemWeaks(IsMarkedCallback, this);
+  Runtime::Current()->SweepSystemWeaks(this);
 }
 
 bool MarkCompact::ShouldSweepSpace(space::ContinuousSpace* space) const {
@@ -592,8 +555,7 @@
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
 // marked, put it on the appropriate list in the heap for later processing.
 void MarkCompact::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference) {
-  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, reference,
-                                                         &HeapReferenceMarkedCallback, this);
+  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, reference, this);
 }
 
 class MarkCompactMarkObjectVisitor {
@@ -601,7 +563,7 @@
   explicit MarkCompactMarkObjectVisitor(MarkCompact* collector) : collector_(collector) {
   }
 
-  void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const ALWAYS_INLINE
+  void operator()(mirror::Object* obj, MemberOffset offset, bool /*is_static*/) const ALWAYS_INLINE
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
     // Object was already verified when we scanned it.
     collector_->MarkObject(obj->GetFieldObject<mirror::Object, kVerifyNone>(offset));
@@ -618,7 +580,7 @@
 };
 
 // Visit all of the references of an object and update.
-void MarkCompact::ScanObject(Object* obj) {
+void MarkCompact::ScanObject(mirror::Object* obj) {
   MarkCompactMarkObjectVisitor visitor(this);
   obj->VisitReferences<kMovingClasses>(visitor, visitor);
 }
@@ -627,7 +589,7 @@
 void MarkCompact::ProcessMarkStack() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   while (!mark_stack_->IsEmpty()) {
-    Object* obj = mark_stack_->PopBack();
+    mirror::Object* obj = mark_stack_->PopBack();
     DCHECK(obj != nullptr);
     ScanObject(obj);
   }
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index f59a2cd..89d66b5 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -121,23 +121,6 @@
                           const RootInfo& info)
       OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
 
-  static mirror::Object* MarkObjectCallback(mirror::Object* root, void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
-  static void MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* obj_ptr, void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
-  static bool HeapReferenceMarkedCallback(mirror::HeapReference<mirror::Object>* ref_ptr,
-                                          void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
-  static void ProcessMarkStackCallback(void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
-
-  static void DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
-                                             void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
   // Schedules an unmarked object for reference processing.
   void DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
@@ -145,11 +128,7 @@
  protected:
   // Returns null if the object is not marked, otherwise returns the forwarding address (same as
   // object for non movable things).
-  mirror::Object* GetMarkedForwardAddress(mirror::Object* object) const
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  static mirror::Object* MarkedForwardingAddressCallback(mirror::Object* object, void* arg)
+  mirror::Object* GetMarkedForwardAddress(mirror::Object* object)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -184,30 +163,27 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
   // Update the references of objects by using the forwarding addresses.
   void UpdateReferences() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
-  static void UpdateRootCallback(mirror::Object** root, void* arg, const RootInfo& /*root_info*/)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
   // Move objects and restore lock words.
   void MoveObjects() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Move a single object to its forward address.
   void MoveObject(mirror::Object* obj, size_t len) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Mark a single object.
-  void MarkObject(mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
-                                                                Locks::mutator_lock_);
-  bool IsMarked(const mirror::Object* obj) const
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-  static mirror::Object* IsMarkedCallback(mirror::Object* object, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  virtual mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* obj_ptr) OVERRIDE
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+  virtual mirror::Object* IsMarked(mirror::Object* obj) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+  virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* obj) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ForwardObject(mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_,
                                                                    Locks::mutator_lock_);
   // Update a single heap reference.
   void UpdateHeapReference(mirror::HeapReference<mirror::Object>* reference)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void UpdateHeapReferenceCallback(mirror::HeapReference<mirror::Object>* reference,
-                                          void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Update all of the references of a single object.
   void UpdateObjectReferences(mirror::Object* obj)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
@@ -242,6 +218,9 @@
   // Which lock words we need to restore as we are moving objects.
   std::deque<LockWord> lock_words_to_restore_;
 
+  // State whether or not we are updating references.
+  bool updating_references_;
+
  private:
   friend class BitmapSetSlowPathVisitor;
   friend class CalculateObjectForwardingAddressVisitor;
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 1c9c412..4035143 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -37,7 +37,6 @@
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
 #include "gc/reference_processor.h"
-#include "gc/space/image_space.h"
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
 #include "mark_sweep-inl.h"
@@ -47,8 +46,6 @@
 #include "thread-inl.h"
 #include "thread_list.h"
 
-using ::art::mirror::Object;
-
 namespace art {
 namespace gc {
 namespace collector {
@@ -175,8 +172,7 @@
 void MarkSweep::ProcessReferences(Thread* self) {
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   GetHeap()->GetReferenceProcessor()->ProcessReferences(
-      true, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
-      &HeapReferenceMarkedCallback, &MarkObjectCallback, &ProcessMarkStackCallback, this);
+      true, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(), this);
 }
 
 void MarkSweep::PausePhase() {
@@ -273,7 +269,7 @@
       TimingLogger::ScopedTiming t(name, GetTimings());
       accounting::ModUnionTable* mod_union_table = heap_->FindModUnionTableFromSpace(space);
       CHECK(mod_union_table != nullptr);
-      mod_union_table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
+      mod_union_table->UpdateAndMarkReferences(this);
     }
   }
 }
@@ -333,7 +329,7 @@
     // Someone else acquired the lock and expanded the mark stack before us.
     return;
   }
-  std::vector<StackReference<Object>> temp(mark_stack_->Begin(), mark_stack_->End());
+  std::vector<StackReference<mirror::Object>> temp(mark_stack_->Begin(), mark_stack_->End());
   CHECK_LE(mark_stack_->Size(), new_size);
   mark_stack_->Resize(new_size);
   for (auto& obj : temp) {
@@ -341,7 +337,12 @@
   }
 }
 
-inline void MarkSweep::MarkObjectNonNullParallel(Object* obj) {
+mirror::Object* MarkSweep::MarkObject(mirror::Object* obj) {
+  MarkObject(obj, nullptr, MemberOffset(0));
+  return obj;
+}
+
+inline void MarkSweep::MarkObjectNonNullParallel(mirror::Object* obj) {
   DCHECK(obj != nullptr);
   if (MarkObjectParallel(obj)) {
     MutexLock mu(Thread::Current(), mark_stack_lock_);
@@ -353,28 +354,18 @@
   }
 }
 
-mirror::Object* MarkSweep::MarkObjectCallback(mirror::Object* obj, void* arg) {
-  MarkSweep* mark_sweep = reinterpret_cast<MarkSweep*>(arg);
-  mark_sweep->MarkObject(obj);
-  return obj;
-}
-
-void MarkSweep::MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* ref, void* arg) {
-  reinterpret_cast<MarkSweep*>(arg)->MarkObject(ref->AsMirrorPtr());
-}
-
-bool MarkSweep::HeapReferenceMarkedCallback(mirror::HeapReference<mirror::Object>* ref, void* arg) {
-  return reinterpret_cast<MarkSweep*>(arg)->IsMarked(ref->AsMirrorPtr());
+bool MarkSweep::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref) {
+  return IsMarked(ref->AsMirrorPtr());
 }
 
 class MarkSweepMarkObjectSlowPath {
  public:
-  explicit MarkSweepMarkObjectSlowPath(MarkSweep* mark_sweep, Object* holder = nullptr,
+  explicit MarkSweepMarkObjectSlowPath(MarkSweep* mark_sweep, mirror::Object* holder = nullptr,
                                        MemberOffset offset = MemberOffset(0))
       : mark_sweep_(mark_sweep), holder_(holder), offset_(offset) {
   }
 
-  void operator()(const Object* obj) const ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS {
+  void operator()(const mirror::Object* obj) const ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS {
     if (kProfileLargeObjects) {
       // TODO: Differentiate between marking and testing somehow.
       ++mark_sweep_->large_object_test_;
@@ -450,7 +441,8 @@
   MemberOffset offset_;
 };
 
-inline void MarkSweep::MarkObjectNonNull(Object* obj, Object* holder, MemberOffset offset) {
+inline void MarkSweep::MarkObjectNonNull(mirror::Object* obj, mirror::Object* holder,
+                                         MemberOffset offset) {
   DCHECK(obj != nullptr);
   if (kUseBakerOrBrooksReadBarrier) {
     // Verify all the objects have the correct pointer installed.
@@ -481,7 +473,7 @@
   }
 }
 
-inline void MarkSweep::PushOnMarkStack(Object* obj) {
+inline void MarkSweep::PushOnMarkStack(mirror::Object* obj) {
   if (UNLIKELY(mark_stack_->Size() >= mark_stack_->Capacity())) {
     // Lock is not needed but is here anyways to please annotalysis.
     MutexLock mu(Thread::Current(), mark_stack_lock_);
@@ -491,14 +483,14 @@
   mark_stack_->PushBack(obj);
 }
 
-inline bool MarkSweep::MarkObjectParallel(const Object* obj) {
+inline bool MarkSweep::MarkObjectParallel(mirror::Object* obj) {
   DCHECK(obj != nullptr);
   if (kUseBakerOrBrooksReadBarrier) {
     // Verify all the objects have the correct pointer installed.
     obj->AssertReadBarrierPointer();
   }
   if (immune_region_.ContainsObject(obj)) {
-    DCHECK(IsMarked(obj));
+    DCHECK(IsMarked(obj) != nullptr);
     return false;
   }
   // Try to take advantage of locality of references within a space, failing this find the space
@@ -511,8 +503,13 @@
   return !mark_bitmap_->AtomicTestAndSet(obj, visitor);
 }
 
+void MarkSweep::MarkHeapReference(mirror::HeapReference<mirror::Object>* ref) {
+  MarkObject(ref->AsMirrorPtr(), nullptr, MemberOffset(0));
+}
+
 // Used to mark objects when processing the mark stack. If an object is null, it is not marked.
-inline void MarkSweep::MarkObject(Object* obj, Object* holder, MemberOffset offset) {
+inline void MarkSweep::MarkObject(mirror::Object* obj, mirror::Object* holder,
+                                  MemberOffset offset) {
   if (obj != nullptr) {
     MarkObjectNonNull(obj, holder, offset);
   } else if (kCountMarkedObjects) {
@@ -526,7 +523,7 @@
 
   void VisitRoot(mirror::Object* root, const RootInfo& info) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
-    CHECK(collector_->IsMarked(root)) << info.ToString();
+    CHECK(collector_->IsMarked(root) != nullptr) << info.ToString();
   }
 
  private:
@@ -599,7 +596,8 @@
   explicit ScanObjectVisitor(MarkSweep* const mark_sweep) ALWAYS_INLINE
       : mark_sweep_(mark_sweep) {}
 
-  void operator()(Object* obj) const ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+  void operator()(mirror::Object* obj) const ALWAYS_INLINE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     if (kCheckLocks) {
       Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
@@ -631,7 +629,7 @@
 class MarkStackTask : public Task {
  public:
   MarkStackTask(ThreadPool* thread_pool, MarkSweep* mark_sweep, size_t mark_stack_size,
-                StackReference<Object>* mark_stack)
+                StackReference<mirror::Object>* mark_stack)
       : mark_sweep_(mark_sweep),
         thread_pool_(thread_pool),
         mark_stack_pos_(mark_stack_size) {
@@ -655,7 +653,7 @@
                                        MarkSweep* mark_sweep) ALWAYS_INLINE
             : chunk_task_(chunk_task), mark_sweep_(mark_sweep) {}
 
-    void operator()(Object* obj, MemberOffset offset, bool /* static */) const ALWAYS_INLINE
+    void operator()(mirror::Object* obj, MemberOffset offset, bool /* static */) const ALWAYS_INLINE
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
       mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
       if (ref != nullptr && mark_sweep_->MarkObjectParallel(ref)) {
@@ -681,7 +679,7 @@
         : chunk_task_(chunk_task) {}
 
     // No thread safety analysis since multiple threads will use this visitor.
-    void operator()(Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+    void operator()(mirror::Object* obj) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
       MarkSweep* const mark_sweep = chunk_task_->mark_sweep_;
       MarkObjectParallelVisitor mark_visitor(chunk_task_, mark_sweep);
@@ -704,11 +702,12 @@
   MarkSweep* const mark_sweep_;
   ThreadPool* const thread_pool_;
   // Thread local mark stack for this task.
-  StackReference<Object> mark_stack_[kMaxSize];
+  StackReference<mirror::Object> mark_stack_[kMaxSize];
   // Mark stack position.
   size_t mark_stack_pos_;
 
-  ALWAYS_INLINE void MarkStackPush(Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ALWAYS_INLINE void MarkStackPush(mirror::Object* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (UNLIKELY(mark_stack_pos_ == kMaxSize)) {
       // Mark stack overflow, give 1/2 the stack to the thread pool as a new work task.
       mark_stack_pos_ /= 2;
@@ -732,12 +731,12 @@
     ScanObjectParallelVisitor visitor(this);
     // TODO: Tune this.
     static const size_t kFifoSize = 4;
-    BoundedFifoPowerOfTwo<Object*, kFifoSize> prefetch_fifo;
+    BoundedFifoPowerOfTwo<mirror::Object*, kFifoSize> prefetch_fifo;
     for (;;) {
-      Object* obj = nullptr;
+      mirror::Object* obj = nullptr;
       if (kUseMarkStackPrefetch) {
         while (mark_stack_pos_ != 0 && prefetch_fifo.size() < kFifoSize) {
-          Object* const mark_stack_obj = mark_stack_[--mark_stack_pos_].AsMirrorPtr();
+          mirror::Object* const mark_stack_obj = mark_stack_[--mark_stack_pos_].AsMirrorPtr();
           DCHECK(mark_stack_obj != nullptr);
           __builtin_prefetch(mark_stack_obj);
           prefetch_fifo.push_back(mark_stack_obj);
@@ -764,7 +763,7 @@
   CardScanTask(ThreadPool* thread_pool, MarkSweep* mark_sweep,
                accounting::ContinuousSpaceBitmap* bitmap,
                uint8_t* begin, uint8_t* end, uint8_t minimum_age, size_t mark_stack_size,
-               StackReference<Object>* mark_stack_obj, bool clear_card)
+               StackReference<mirror::Object>* mark_stack_obj, bool clear_card)
       : MarkStackTask<false>(thread_pool, mark_sweep, mark_stack_size, mark_stack_obj),
         bitmap_(bitmap),
         begin_(begin),
@@ -815,8 +814,8 @@
     TimingLogger::ScopedTiming t(paused ? "(Paused)ScanGrayObjects" : __FUNCTION__,
         GetTimings());
     // Try to take some of the mark stack since we can pass this off to the worker tasks.
-    StackReference<Object>* mark_stack_begin = mark_stack_->Begin();
-    StackReference<Object>* mark_stack_end = mark_stack_->End();
+    StackReference<mirror::Object>* mark_stack_begin = mark_stack_->Begin();
+    StackReference<mirror::Object>* mark_stack_end = mark_stack_->End();
     const size_t mark_stack_size = mark_stack_end - mark_stack_begin;
     // Estimated number of work tasks we will create.
     const size_t mark_stack_tasks = GetHeap()->GetContinuousSpaces().size() * thread_count;
@@ -832,8 +831,8 @@
       // Align up the end address. For example, the image space's end
       // may not be card-size-aligned.
       card_end = AlignUp(card_end, accounting::CardTable::kCardSize);
-      DCHECK(IsAligned<accounting::CardTable::kCardSize>(card_begin));
-      DCHECK(IsAligned<accounting::CardTable::kCardSize>(card_end));
+      DCHECK_ALIGNED(card_begin, accounting::CardTable::kCardSize);
+      DCHECK_ALIGNED(card_end, accounting::CardTable::kCardSize);
       // Calculate how many bytes of heap we will scan,
       const size_t address_range = card_end - card_begin;
       // Calculate how much address range each task gets.
@@ -988,13 +987,6 @@
   ProcessMarkStack(false);
 }
 
-mirror::Object* MarkSweep::IsMarkedCallback(mirror::Object* object, void* arg) {
-  if (reinterpret_cast<MarkSweep*>(arg)->IsMarked(object)) {
-    return object;
-  }
-  return nullptr;
-}
-
 void MarkSweep::RecursiveMarkDirtyObjects(bool paused, uint8_t minimum_age) {
   ScanGrayObjects(paused, minimum_age);
   ProcessMarkStack(paused);
@@ -1015,16 +1007,23 @@
 void MarkSweep::SweepSystemWeaks(Thread* self) {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
-  Runtime::Current()->SweepSystemWeaks(IsMarkedCallback, this);
+  Runtime::Current()->SweepSystemWeaks(this);
 }
 
-mirror::Object* MarkSweep::VerifySystemWeakIsLiveCallback(Object* obj, void* arg) {
-  reinterpret_cast<MarkSweep*>(arg)->VerifyIsLive(obj);
-  // We don't actually want to sweep the object, so lets return "marked"
-  return obj;
-}
+class VerifySystemWeakVisitor : public IsMarkedVisitor {
+ public:
+  explicit VerifySystemWeakVisitor(MarkSweep* mark_sweep) : mark_sweep_(mark_sweep) {}
 
-void MarkSweep::VerifyIsLive(const Object* obj) {
+  virtual mirror::Object* IsMarked(mirror::Object* obj) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
+    mark_sweep_->VerifyIsLive(obj);
+    return obj;
+  }
+
+  MarkSweep* const mark_sweep_;
+};
+
+void MarkSweep::VerifyIsLive(const mirror::Object* obj) {
   if (!heap_->GetLiveBitmap()->Test(obj)) {
     // TODO: Consider live stack? Has this code bitrotted?
     CHECK(!heap_->allocation_stack_->Contains(obj))
@@ -1035,7 +1034,8 @@
 void MarkSweep::VerifySystemWeaks() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
   // Verify system weaks, uses a special object visitor which returns the input object.
-  Runtime::Current()->SweepSystemWeaks(VerifySystemWeakIsLiveCallback, this);
+  VerifySystemWeakVisitor visitor(this);
+  Runtime::Current()->SweepSystemWeaks(&visitor);
 }
 
 class CheckpointMarkThreadRoots : public Closure, public RootVisitor {
@@ -1122,7 +1122,7 @@
   ObjectBytePair freed;
   ObjectBytePair freed_los;
   // How many objects are left in the array, modified after each space is swept.
-  StackReference<Object>* objects = allocations->Begin();
+  StackReference<mirror::Object>* objects = allocations->Begin();
   size_t count = allocations->Size();
   // Change the order to ensure that the non-moving space last swept as an optimization.
   std::vector<space::ContinuousSpace*> sweep_spaces;
@@ -1150,9 +1150,9 @@
     if (swap_bitmaps) {
       std::swap(live_bitmap, mark_bitmap);
     }
-    StackReference<Object>* out = objects;
+    StackReference<mirror::Object>* out = objects;
     for (size_t i = 0; i < count; ++i) {
-      Object* const obj = objects[i].AsMirrorPtr();
+      mirror::Object* const obj = objects[i].AsMirrorPtr();
       if (kUseThreadLocalAllocationStack && obj == nullptr) {
         continue;
       }
@@ -1191,7 +1191,7 @@
       std::swap(large_live_objects, large_mark_objects);
     }
     for (size_t i = 0; i < count; ++i) {
-      Object* const obj = objects[i].AsMirrorPtr();
+      mirror::Object* const obj = objects[i].AsMirrorPtr();
       // Handle large objects.
       if (kUseThreadLocalAllocationStack && obj == nullptr) {
         continue;
@@ -1250,16 +1250,15 @@
   if (kCountJavaLangRefs) {
     ++reference_count_;
   }
-  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, &HeapReferenceMarkedCallback,
-                                                         this);
+  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, ref, this);
 }
 
-class MarkObjectVisitor {
+class MarkVisitor {
  public:
-  explicit MarkObjectVisitor(MarkSweep* const mark_sweep) ALWAYS_INLINE : mark_sweep_(mark_sweep) {
+  explicit MarkVisitor(MarkSweep* const mark_sweep) ALWAYS_INLINE : mark_sweep_(mark_sweep) {
   }
 
-  void operator()(Object* obj, MemberOffset offset, bool /* is_static */) const
+  void operator()(mirror::Object* obj, MemberOffset offset, bool /* is_static */) const
       ALWAYS_INLINE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
     if (kCheckLocks) {
@@ -1275,16 +1274,12 @@
 
 // Scans an object reference.  Determines the type of the reference
 // and dispatches to a specialized scanning routine.
-void MarkSweep::ScanObject(Object* obj) {
-  MarkObjectVisitor mark_visitor(this);
+void MarkSweep::ScanObject(mirror::Object* obj) {
+  MarkVisitor mark_visitor(this);
   DelayReferenceReferentVisitor ref_visitor(this);
   ScanObjectVisit(obj, mark_visitor, ref_visitor);
 }
 
-void MarkSweep::ProcessMarkStackCallback(void* arg) {
-  reinterpret_cast<MarkSweep*>(arg)->ProcessMarkStack(false);
-}
-
 void MarkSweep::ProcessMarkStackParallel(size_t thread_count) {
   Thread* self = Thread::Current();
   ThreadPool* thread_pool = GetHeap()->GetThreadPool();
@@ -1317,12 +1312,12 @@
   } else {
     // TODO: Tune this.
     static const size_t kFifoSize = 4;
-    BoundedFifoPowerOfTwo<Object*, kFifoSize> prefetch_fifo;
+    BoundedFifoPowerOfTwo<mirror::Object*, kFifoSize> prefetch_fifo;
     for (;;) {
-      Object* obj = nullptr;
+      mirror::Object* obj = nullptr;
       if (kUseMarkStackPrefetch) {
         while (!mark_stack_->IsEmpty() && prefetch_fifo.size() < kFifoSize) {
-          Object* mark_stack_obj = mark_stack_->PopBack();
+          mirror::Object* mark_stack_obj = mark_stack_->PopBack();
           DCHECK(mark_stack_obj != nullptr);
           __builtin_prefetch(mark_stack_obj);
           prefetch_fifo.push_back(mark_stack_obj);
@@ -1344,14 +1339,14 @@
   }
 }
 
-inline bool MarkSweep::IsMarked(const Object* object) const {
+inline mirror::Object* MarkSweep::IsMarked(mirror::Object* object) {
   if (immune_region_.ContainsObject(object)) {
-    return true;
+    return object;
   }
   if (current_space_bitmap_->HasAddress(object)) {
-    return current_space_bitmap_->Test(object);
+    return current_space_bitmap_->Test(object) ? object : nullptr;
   }
-  return mark_bitmap_->Test(object);
+  return mark_bitmap_->Test(object) ? object : nullptr;
 }
 
 void MarkSweep::FinishPhase() {
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index d29d87a..7692b06 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -170,18 +170,9 @@
 
   // Verify that an object is live, either in a live bitmap or in the allocation stack.
   void VerifyIsLive(const mirror::Object* obj)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
 
-  static mirror::Object* MarkObjectCallback(mirror::Object* obj, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  static void MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* ref, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  static bool HeapReferenceMarkedCallback(mirror::HeapReference<mirror::Object>* ref, void* arg)
+  virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* ref) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -194,13 +185,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static void ProcessMarkStackCallback(void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   // Marks an object.
-  void MarkObject(mirror::Object* obj, mirror::Object* holder = nullptr,
-                  MemberOffset offset = MemberOffset(0))
+  virtual mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  void MarkObject(mirror::Object* obj, mirror::Object* holder, MemberOffset offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* ref) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -213,16 +205,10 @@
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
  protected:
-  // Returns true if the object has its bit set in the mark bitmap.
-  bool IsMarked(const mirror::Object* object) const
+  // Returns object if the object is marked in the heap bitmap, otherwise null.
+  virtual mirror::Object* IsMarked(mirror::Object* object) OVERRIDE
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static mirror::Object* IsMarkedCallback(mirror::Object* object, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  static void VerifyImageRootVisitor(mirror::Object* root, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
   void MarkObjectNonNull(mirror::Object* obj, mirror::Object* holder = nullptr,
                          MemberOffset offset = MemberOffset(0))
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -233,7 +219,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Returns true if we need to add obj to a mark stack.
-  bool MarkObjectParallel(const mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS;
+  bool MarkObjectParallel(mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS;
 
   // Verify the roots of the heap and print out information related to any invalid roots.
   // Called in MarkObject, so may we may not hold the mutator lock.
@@ -258,6 +244,11 @@
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  virtual void ProcessMarkStack() OVERRIDE EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    ProcessMarkStack(false);
+  }
+
   // Recursively blackens objects on the mark stack.
   void ProcessMarkStack(bool paused)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
diff --git a/runtime/gc/collector/semi_space-inl.h b/runtime/gc/collector/semi_space-inl.h
index 7b19dc9..a7de44f 100644
--- a/runtime/gc/collector/semi_space-inl.h
+++ b/runtime/gc/collector/semi_space-inl.h
@@ -34,7 +34,7 @@
   void operator()(const mirror::Object* obj) const {
     CHECK(!semi_space_->to_space_->HasAddress(obj)) << "Marking " << obj << " in to_space_";
     // Marking a large object, make sure its aligned as a sanity check.
-    CHECK(IsAligned<kPageSize>(obj));
+    CHECK_ALIGNED(obj, kPageSize);
   }
 
  private:
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 82d02e7..2a9f47a 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -157,8 +157,7 @@
 void SemiSpace::ProcessReferences(Thread* self) {
   WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   GetHeap()->GetReferenceProcessor()->ProcessReferences(
-      false, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(),
-      &HeapReferenceMarkedCallback, &MarkObjectCallback, &ProcessMarkStackCallback, this);
+      false, GetTimings(), GetCurrentIteration()->GetClearSoftReferences(), this);
 }
 
 void SemiSpace::MarkingPhase() {
@@ -336,7 +335,7 @@
           space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
                                    "UpdateAndMarkImageModUnionTable",
                                    GetTimings());
-      table->UpdateAndMarkReferences(MarkHeapReferenceCallback, this);
+      table->UpdateAndMarkReferences(this);
       DCHECK(GetHeap()->FindRememberedSetFromSpace(space) == nullptr);
     } else if (collect_from_space_only_ && space->GetLiveBitmap() != nullptr) {
       // If the space has no mod union table (the non-moving space and main spaces when the bump
@@ -351,8 +350,7 @@
       CHECK_EQ(rem_set != nullptr, kUseRememberedSet);
       if (rem_set != nullptr) {
         TimingLogger::ScopedTiming t2("UpdateAndMarkRememberedSet", GetTimings());
-        rem_set->UpdateAndMarkReferences(MarkHeapReferenceCallback, DelayReferenceReferentCallback,
-                                         from_space_, this);
+        rem_set->UpdateAndMarkReferences(from_space_, this);
         if (kIsDebugBuild) {
           // Verify that there are no from-space references that
           // remain in the space, that is, the remembered set (and the
@@ -583,24 +581,14 @@
   return forward_address;
 }
 
-void SemiSpace::ProcessMarkStackCallback(void* arg) {
-  reinterpret_cast<SemiSpace*>(arg)->ProcessMarkStack();
-}
-
-mirror::Object* SemiSpace::MarkObjectCallback(mirror::Object* root, void* arg) {
+mirror::Object* SemiSpace::MarkObject(mirror::Object* root) {
   auto ref = StackReference<mirror::Object>::FromMirrorPtr(root);
-  reinterpret_cast<SemiSpace*>(arg)->MarkObject(&ref);
+  MarkObject(&ref);
   return ref.AsMirrorPtr();
 }
 
-void SemiSpace::MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* obj_ptr,
-                                          void* arg) {
-  reinterpret_cast<SemiSpace*>(arg)->MarkObject(obj_ptr);
-}
-
-void SemiSpace::DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
-                                               void* arg) {
-  reinterpret_cast<SemiSpace*>(arg)->DelayReferenceReferent(klass, ref);
+void SemiSpace::MarkHeapReference(mirror::HeapReference<mirror::Object>* obj_ptr) {
+  MarkObject(obj_ptr);
 }
 
 void SemiSpace::VisitRoots(mirror::Object*** roots, size_t count,
@@ -628,29 +616,9 @@
   Runtime::Current()->VisitRoots(this);
 }
 
-bool SemiSpace::HeapReferenceMarkedCallback(mirror::HeapReference<mirror::Object>* object,
-                                            void* arg) {
-  mirror::Object* obj = object->AsMirrorPtr();
-  mirror::Object* new_obj =
-      reinterpret_cast<SemiSpace*>(arg)->GetMarkedForwardAddress(obj);
-  if (new_obj == nullptr) {
-    return false;
-  }
-  if (new_obj != obj) {
-    // Write barrier is not necessary since it still points to the same object, just at a different
-    // address.
-    object->Assign(new_obj);
-  }
-  return true;
-}
-
-mirror::Object* SemiSpace::MarkedForwardingAddressCallback(mirror::Object* object, void* arg) {
-  return reinterpret_cast<SemiSpace*>(arg)->GetMarkedForwardAddress(object);
-}
-
 void SemiSpace::SweepSystemWeaks() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
-  Runtime::Current()->SweepSystemWeaks(MarkedForwardingAddressCallback, this);
+  Runtime::Current()->SweepSystemWeaks(this);
 }
 
 bool SemiSpace::ShouldSweepSpace(space::ContinuousSpace* space) const {
@@ -688,8 +656,7 @@
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
 // marked, put it on the appropriate list in the heap for later processing.
 void SemiSpace::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* reference) {
-  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, reference,
-                                                         &HeapReferenceMarkedCallback, this);
+  heap_->GetReferenceProcessor()->DelayReferenceReferent(klass, reference, this);
 }
 
 class SemiSpaceMarkObjectVisitor {
@@ -746,8 +713,7 @@
   }
 }
 
-inline Object* SemiSpace::GetMarkedForwardAddress(mirror::Object* obj) const
-    SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+mirror::Object* SemiSpace::IsMarked(mirror::Object* obj) {
   // All immune objects are assumed marked.
   if (from_space_->HasAddress(obj)) {
     // Returns either the forwarding address or null.
@@ -759,6 +725,20 @@
   return mark_bitmap_->Test(obj) ? obj : nullptr;
 }
 
+bool SemiSpace::IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* object) {
+  mirror::Object* obj = object->AsMirrorPtr();
+  mirror::Object* new_obj = IsMarked(obj);
+  if (new_obj == nullptr) {
+    return false;
+  }
+  if (new_obj != obj) {
+    // Write barrier is not necessary since it still points to the same object, just at a different
+    // address.
+    object->Assign(new_obj);
+  }
+  return true;
+}
+
 void SemiSpace::SetToSpace(space::ContinuousMemMapAllocSpace* to_space) {
   DCHECK(to_space != nullptr);
   to_space_ = to_space;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 3c25f53..6b7ea0d 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -103,6 +103,12 @@
   void MarkObject(mirror::ObjectReference<kPoisonReferences, mirror::Object>* obj_ptr)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
+  virtual mirror::Object* MarkObject(mirror::Object* root) OVERRIDE
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* obj_ptr) OVERRIDE
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+
   void ScanObject(mirror::Object* obj)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
@@ -140,19 +146,6 @@
                           const RootInfo& info) OVERRIDE
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
 
-  static mirror::Object* MarkObjectCallback(mirror::Object* root, void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
-  static void MarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>* obj_ptr, void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
-  static void ProcessMarkStackCallback(void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
-
-  static void DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
-                                             void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
-
   virtual mirror::Object* MarkNonForwardedObject(mirror::Object* obj)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
@@ -163,15 +156,11 @@
  protected:
   // Returns null if the object is not marked, otherwise returns the forwarding address (same as
   // object for non movable things).
-  mirror::Object* GetMarkedForwardAddress(mirror::Object* object) const
+  virtual mirror::Object* IsMarked(mirror::Object* object) OVERRIDE
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static bool HeapReferenceMarkedCallback(mirror::HeapReference<mirror::Object>* object, void* arg)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  static mirror::Object* MarkedForwardingAddressCallback(mirror::Object* object, void* arg)
+  virtual bool IsMarkedHeapReference(mirror::HeapReference<mirror::Object>* object) OVERRIDE
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index 9275e6d..95ba380 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_COLLECTOR_TYPE_H_
 #define ART_RUNTIME_GC_COLLECTOR_TYPE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 1f2643a..0536f32d 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_GC_CAUSE_H_
 #define ART_RUNTIME_GC_GC_CAUSE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 2e66160..cb750eb 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -92,7 +92,7 @@
   } else if (!kInstrumented && allocator == kAllocatorTypeRosAlloc &&
              (obj = rosalloc_space_->AllocThreadLocal(self, byte_count, &bytes_allocated)) &&
              LIKELY(obj != nullptr)) {
-    DCHECK(!running_on_valgrind_);
+    DCHECK(!is_running_on_memory_tool_);
     obj->SetClass(klass);
     if (kUseBakerOrBrooksReadBarrier) {
       if (kUseBrooksReadBarrier) {
@@ -244,8 +244,8 @@
       break;
     }
     case kAllocatorTypeRosAlloc: {
-      if (kInstrumented && UNLIKELY(running_on_valgrind_)) {
-        // If running on valgrind, we should be using the instrumented path.
+      if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
+        // If running on valgrind or asan, we should be using the instrumented path.
         size_t max_bytes_tl_bulk_allocated = rosalloc_space_->MaxBytesBulkAllocatedFor(alloc_size);
         if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type,
                                                       max_bytes_tl_bulk_allocated))) {
@@ -254,7 +254,7 @@
         ret = rosalloc_space_->Alloc(self, alloc_size, bytes_allocated, usable_size,
                                      bytes_tl_bulk_allocated);
       } else {
-        DCHECK(!running_on_valgrind_);
+        DCHECK(!is_running_on_memory_tool_);
         size_t max_bytes_tl_bulk_allocated =
             rosalloc_space_->MaxBytesBulkAllocatedForNonvirtual(alloc_size);
         if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(allocator_type,
@@ -270,12 +270,12 @@
       break;
     }
     case kAllocatorTypeDlMalloc: {
-      if (kInstrumented && UNLIKELY(running_on_valgrind_)) {
+      if (kInstrumented && UNLIKELY(is_running_on_memory_tool_)) {
         // If running on valgrind, we should be using the instrumented path.
         ret = dlmalloc_space_->Alloc(self, alloc_size, bytes_allocated, usable_size,
                                      bytes_tl_bulk_allocated);
       } else {
-        DCHECK(!running_on_valgrind_);
+        DCHECK(!is_running_on_memory_tool_);
         ret = dlmalloc_space_->AllocNonvirtual(self, alloc_size, bytes_allocated, usable_size,
                                                bytes_tl_bulk_allocated);
       }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 1b45ea1..2b94cf1 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -37,13 +37,12 @@
 #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.h"
 #include "gc/accounting/mod_union_table-inl.h"
 #include "gc/accounting/remembered_set.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/collector/concurrent_copying.h"
 #include "gc/collector/mark_compact.h"
-#include "gc/collector/mark_sweep-inl.h"
+#include "gc/collector/mark_sweep.h"
 #include "gc/collector/partial_mark_sweep.h"
 #include "gc/collector/semi_space.h"
 #include "gc/collector/sticky_mark_sweep.h"
@@ -62,7 +61,6 @@
 #include "image.h"
 #include "intern_table.h"
 #include "mirror/class-inl.h"
-#include "mirror/object.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/reference-inl.h"
@@ -194,7 +192,7 @@
       total_allocation_time_(0),
       verify_object_mode_(kVerifyObjectModeDisabled),
       disable_moving_gc_count_(0),
-      running_on_valgrind_(Runtime::Current()->RunningOnValgrind()),
+      is_running_on_memory_tool_(Runtime::Current()->IsRunningOnMemoryTool()),
       use_tlab_(use_tlab),
       main_space_backup_(nullptr),
       min_interval_homogeneous_space_compaction_by_oom_(
@@ -467,6 +465,7 @@
   gc_complete_cond_.reset(new ConditionVariable("GC complete condition variable",
                                                 *gc_complete_lock_));
   task_processor_.reset(new TaskProcessor());
+  reference_processor_.reset(new ReferenceProcessor());
   pending_task_lock_ = new Mutex("Pending task lock");
   if (ignore_max_footprint_) {
     SetIdealFootprint(std::numeric_limits<size_t>::max());
@@ -519,7 +518,7 @@
   if (gc_stress_mode_) {
     backtrace_lock_ = new Mutex("GC complete lock");
   }
-  if (running_on_valgrind_ || gc_stress_mode_) {
+  if (is_running_on_memory_tool_ || gc_stress_mode_) {
     instrumentation->InstrumentQuickAllocEntryPoints();
   }
   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
@@ -1432,10 +1431,10 @@
   if (UNLIKELY(static_cast<size_t>(num_bytes_allocated_.LoadRelaxed()) < 10 * KB)) {
     return;
   }
-  CHECK(IsAligned<kObjectAlignment>(obj)) << "Object isn't aligned: " << obj;
+  CHECK_ALIGNED(obj, kObjectAlignment) << "Object isn't aligned";
   mirror::Class* c = obj->GetFieldObject<mirror::Class, kVerifyNone>(mirror::Object::ClassOffset());
   CHECK(c != nullptr) << "Null class in object " << obj;
-  CHECK(IsAligned<kObjectAlignment>(c)) << "Class " << c << " not aligned in object " << obj;
+  CHECK_ALIGNED(c, kObjectAlignment) << "Class " << c << " not aligned in object " << obj;
   CHECK(VerifyClassClass(c));
 
   if (verify_object_mode_ > kVerifyObjectModeFast) {
@@ -1705,11 +1704,12 @@
     mirror::Class* instance_class = obj->GetClass();
     CHECK(instance_class != nullptr);
     for (size_t i = 0; i < instance_counter->classes_.size(); ++i) {
+      mirror::Class* klass = instance_counter->classes_[i];
       if (instance_counter->use_is_assignable_from_) {
-        if (instance_counter->classes_[i]->IsAssignableFrom(instance_class)) {
+        if (klass != nullptr && klass->IsAssignableFrom(instance_class)) {
           ++instance_counter->counts_[i];
         }
-      } else if (instance_class == instance_counter->classes_[i]) {
+      } else if (instance_class == klass) {
         ++instance_counter->counts_[i];
       }
     }
@@ -1865,7 +1865,7 @@
              static_cast<double>(space_size_before_compaction);
   tl->ResumeAll();
   // Finish GC.
-  reference_processor_.EnqueueClearedReferences(self);
+  reference_processor_->EnqueueClearedReferences(self);
   GrowForUtilization(semi_space_collector_);
   LogGC(kGcCauseHomogeneousSpaceCompact, collector);
   FinishGC(self, collector::kGcTypeFull);
@@ -1998,7 +1998,7 @@
   ChangeCollector(collector_type);
   tl->ResumeAll();
   // Can't call into java code with all threads suspended.
-  reference_processor_.EnqueueClearedReferences(self);
+  reference_processor_->EnqueueClearedReferences(self);
   uint64_t duration = NanoTime() - start_time;
   GrowForUtilization(semi_space_collector_);
   DCHECK(collector != nullptr);
@@ -2077,9 +2077,12 @@
 // Special compacting collector which uses sub-optimal bin packing to reduce zygote space size.
 class ZygoteCompactingCollector FINAL : public collector::SemiSpace {
  public:
-  explicit ZygoteCompactingCollector(gc::Heap* heap) : SemiSpace(heap, false, "zygote collector"),
-      bin_live_bitmap_(nullptr), bin_mark_bitmap_(nullptr) {
-  }
+  explicit ZygoteCompactingCollector(gc::Heap* heap,
+                                     bool is_running_on_memory_tool)
+      : SemiSpace(heap, false, "zygote collector"),
+        bin_live_bitmap_(nullptr),
+        bin_mark_bitmap_(nullptr),
+        is_running_on_memory_tool_(is_running_on_memory_tool) {}
 
   void BuildBins(space::ContinuousSpace* space) {
     bin_live_bitmap_ = space->GetLiveBitmap();
@@ -2105,6 +2108,7 @@
   accounting::ContinuousSpaceBitmap* bin_live_bitmap_;
   // Mark bitmap of the space which contains the bins.
   accounting::ContinuousSpaceBitmap* bin_mark_bitmap_;
+  const bool is_running_on_memory_tool_;
 
   static void Callback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -2119,6 +2123,9 @@
   }
 
   void AddBin(size_t size, uintptr_t position) {
+    if (is_running_on_memory_tool_) {
+      MEMORY_TOOL_MAKE_DEFINED(reinterpret_cast<void*>(position), size);
+    }
     if (size != 0) {
       bins_.insert(std::make_pair(size, position));
     }
@@ -2212,7 +2219,7 @@
     // Temporarily disable rosalloc verification because the zygote
     // compaction will mess up the rosalloc internal metadata.
     ScopedDisableRosAllocVerification disable_rosalloc_verif(this);
-    ZygoteCompactingCollector zygote_collector(this);
+    ZygoteCompactingCollector zygote_collector(this, is_running_on_memory_tool_);
     zygote_collector.BuildBins(non_moving_space_);
     // Create a new bump pointer space which we will compact into.
     space::BumpPointerSpace target_space("zygote bump space", non_moving_space_->End(),
@@ -2472,7 +2479,7 @@
   total_bytes_freed_ever_ += GetCurrentGcIteration()->GetFreedBytes();
   RequestTrim(self);
   // Enqueue cleared references.
-  reference_processor_.EnqueueClearedReferences(self);
+  reference_processor_->EnqueueClearedReferences(self);
   // Grow the heap so that we know when to perform the next GC.
   GrowForUtilization(collector, bytes_allocated_before_gc);
   LogGC(gc_cause, collector);
@@ -3048,8 +3055,13 @@
   }
 }
 
-static void IdentityMarkHeapReferenceCallback(mirror::HeapReference<mirror::Object>*, void*) {
-}
+struct IdentityMarkHeapReferenceVisitor : public MarkObjectVisitor {
+  virtual mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE {
+    return obj;
+  }
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>*) OVERRIDE {
+  }
+};
 
 void Heap::PreGcVerificationPaused(collector::GarbageCollector* gc) {
   Thread* const self = Thread::Current();
@@ -3078,7 +3090,8 @@
     ReaderMutexLock reader_lock(self, *Locks::heap_bitmap_lock_);
     for (const auto& table_pair : mod_union_tables_) {
       accounting::ModUnionTable* mod_union_table = table_pair.second;
-      mod_union_table->UpdateAndMarkReferences(IdentityMarkHeapReferenceCallback, nullptr);
+      IdentityMarkHeapReferenceVisitor visitor;
+      mod_union_table->UpdateAndMarkReferences(&visitor);
       mod_union_table->Verify();
     }
   }
@@ -3707,11 +3720,11 @@
   }
 }
 
-void Heap::SweepAllocationRecords(IsMarkedCallback* visitor, void* arg) const {
+void Heap::SweepAllocationRecords(IsMarkedVisitor* visitor) const {
   if (IsAllocTrackingEnabled()) {
     MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
     if (IsAllocTrackingEnabled()) {
-      GetAllocationRecords()->SweepAllocationRecords(visitor, arg);
+      GetAllocationRecords()->SweepAllocationRecords(visitor);
     }
   }
 }
@@ -3734,17 +3747,6 @@
   }
 }
 
-void Heap::EnsureNewAllocationRecordsDisallowed() const {
-  if (IsAllocTrackingEnabled()) {
-    // Lock and unlock once to ensure that no threads are still in the
-    // middle of adding new allocation records.
-    MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
-    if (IsAllocTrackingEnabled()) {
-      GetAllocationRecords()->EnsureNewAllocationRecordsDisallowed();
-    }
-  }
-}
-
 // Based on debug malloc logic from libc/bionic/debug_stacktrace.cpp.
 class StackCrawlState {
  public:
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 1c75bd0..ee3d510 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -26,22 +26,17 @@
 #include "arch/instruction_set.h"
 #include "atomic.h"
 #include "base/time_utils.h"
-#include "base/timing_logger.h"
 #include "gc/accounting/atomic_stack.h"
 #include "gc/accounting/card_table.h"
 #include "gc/accounting/read_barrier_table.h"
 #include "gc/gc_cause.h"
-#include "gc/collector/garbage_collector.h"
 #include "gc/collector/gc_type.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "globals.h"
-#include "jni.h"
 #include "object_callbacks.h"
 #include "offsets.h"
-#include "reference_processor.h"
 #include "safe_map.h"
-#include "thread_pool.h"
 #include "verify_object.h"
 
 namespace art {
@@ -50,6 +45,7 @@
 class Mutex;
 class StackVisitor;
 class Thread;
+class ThreadPool;
 class TimingLogger;
 
 namespace mirror {
@@ -631,7 +627,7 @@
   bool HasImageSpace() const;
 
   ReferenceProcessor* GetReferenceProcessor() {
-    return &reference_processor_;
+    return reference_processor_.get();
   }
   TaskProcessor* GetTaskProcessor() {
     return task_processor_.get();
@@ -709,7 +705,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
 
-  void SweepAllocationRecords(IsMarkedCallback* visitor, void* arg) const
+  void SweepAllocationRecords(IsMarkedVisitor* visitor) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
 
@@ -721,10 +717,6 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
 
-  void EnsureNewAllocationRecordsDisallowed() const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
-
  private:
   class ConcurrentGCTask;
   class CollectorTransitionTask;
@@ -1019,7 +1011,7 @@
   std::unique_ptr<ConditionVariable> gc_complete_cond_ GUARDED_BY(gc_complete_lock_);
 
   // Reference processor;
-  ReferenceProcessor reference_processor_;
+  std::unique_ptr<ReferenceProcessor> reference_processor_;
 
   // Task processor, proxies heap trim requests to the daemon threads.
   std::unique_ptr<TaskProcessor> task_processor_;
@@ -1181,7 +1173,7 @@
   collector::MarkCompact* mark_compact_collector_;
   collector::ConcurrentCopying* concurrent_copying_collector_;
 
-  const bool running_on_valgrind_;
+  const bool is_running_on_memory_tool_;
   const bool use_tlab_;
 
   // Pointer to the space which becomes the new main space when we do homogeneous space compaction.
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index 4d51d38..39ba743 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -17,6 +17,7 @@
 #include "reference_processor.h"
 
 #include "base/time_utils.h"
+#include "collector/garbage_collector.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/reference-inl.h"
@@ -34,7 +35,7 @@
 static constexpr bool kAsyncReferenceQueueAdd = false;
 
 ReferenceProcessor::ReferenceProcessor()
-    : process_references_args_(nullptr, nullptr, nullptr),
+    : collector_(nullptr),
       preserving_references_(false),
       condition_("reference processor condition", *Locks::reference_processor_lock_) ,
       soft_reference_queue_(Locks::reference_queue_soft_references_lock_),
@@ -53,15 +54,27 @@
   condition_.Broadcast(self);
 }
 
+void ReferenceProcessor::BroadcastForSlowPath(Thread* self) {
+  CHECK(kUseReadBarrier);
+  MutexLock mu(self, *Locks::reference_processor_lock_);
+  condition_.Broadcast(self);
+}
+
 mirror::Object* ReferenceProcessor::GetReferent(Thread* self, mirror::Reference* reference) {
-  mirror::Object* const referent = reference->GetReferent();
-  // If the referent is null then it is already cleared, we can just return null since there is no
-  // scenario where it becomes non-null during the reference processing phase.
-  if (UNLIKELY(!SlowPathEnabled()) || referent == nullptr) {
-    return referent;
+  if (!kUseReadBarrier || self->GetWeakRefAccessEnabled()) {
+    // Under read barrier / concurrent copying collector, it's not safe to call GetReferent() when
+    // weak ref access is disabled as the call includes a read barrier which may push a ref onto the
+    // mark stack and interfere with termination of marking.
+    mirror::Object* const referent = reference->GetReferent();
+    // If the referent is null then it is already cleared, we can just return null since there is no
+    // scenario where it becomes non-null during the reference processing phase.
+    if (UNLIKELY(!SlowPathEnabled()) || referent == nullptr) {
+      return referent;
+    }
   }
   MutexLock mu(self, *Locks::reference_processor_lock_);
-  while (SlowPathEnabled()) {
+  while ((!kUseReadBarrier && SlowPathEnabled()) ||
+         (kUseReadBarrier && !self->GetWeakRefAccessEnabled())) {
     mirror::HeapReference<mirror::Object>* const referent_addr =
         reference->GetReferentReferenceAddr();
     // If the referent became cleared, return it. Don't need barrier since thread roots can't get
@@ -71,16 +84,14 @@
     }
     // Try to see if the referent is already marked by using the is_marked_callback. We can return
     // it to the mutator as long as the GC is not preserving references.
-    IsHeapReferenceMarkedCallback* const is_marked_callback =
-        process_references_args_.is_marked_callback_;
-    if (LIKELY(is_marked_callback != nullptr)) {
+    if (LIKELY(collector_ != nullptr)) {
       // If it's null it means not marked, but it could become marked if the referent is reachable
       // by finalizer referents. So we can not return in this case and must block. Otherwise, we
       // can return it to the mutator as long as the GC is not preserving references, in which
       // case only black nodes can be safely returned. If the GC is preserving references, the
       // mutator could take a white field from a grey or white node and move it somewhere else
       // in the heap causing corruption since this field would get swept.
-      if (is_marked_callback(referent_addr, process_references_args_.arg_)) {
+      if (collector_->IsMarkedHeapReference(referent_addr)) {
         if (!preserving_references_ ||
            (LIKELY(!reference->IsFinalizerReferenceInstance()) && !reference->IsEnqueued())) {
           return referent_addr->AsMirrorPtr();
@@ -92,16 +103,6 @@
   return reference->GetReferent();
 }
 
-bool ReferenceProcessor::PreserveSoftReferenceCallback(mirror::HeapReference<mirror::Object>* obj,
-                                                       void* arg) {
-  auto* const args = reinterpret_cast<ProcessReferencesArgs*>(arg);
-  // TODO: Add smarter logic for preserving soft references.
-  mirror::Object* new_obj = args->mark_callback_(obj->AsMirrorPtr(), args->arg_);
-  DCHECK(new_obj != nullptr);
-  obj->Assign(new_obj);
-  return true;
-}
-
 void ReferenceProcessor::StartPreservingReferences(Thread* self) {
   MutexLock mu(self, *Locks::reference_processor_lock_);
   preserving_references_ = true;
@@ -117,18 +118,18 @@
 // Process reference class instances and schedule finalizations.
 void ReferenceProcessor::ProcessReferences(bool concurrent, TimingLogger* timings,
                                            bool clear_soft_references,
-                                           IsHeapReferenceMarkedCallback* is_marked_callback,
-                                           MarkObjectCallback* mark_object_callback,
-                                           ProcessMarkStackCallback* process_mark_stack_callback,
-                                           void* arg) {
+                                           collector::GarbageCollector* collector) {
   TimingLogger::ScopedTiming t(concurrent ? __FUNCTION__ : "(Paused)ProcessReferences", timings);
   Thread* self = Thread::Current();
   {
     MutexLock mu(self, *Locks::reference_processor_lock_);
-    process_references_args_.is_marked_callback_ = is_marked_callback;
-    process_references_args_.mark_callback_ = mark_object_callback;
-    process_references_args_.arg_ = arg;
-    CHECK_EQ(SlowPathEnabled(), concurrent) << "Slow path must be enabled iff concurrent";
+    collector_ = collector;
+    if (!kUseReadBarrier) {
+      CHECK_EQ(SlowPathEnabled(), concurrent) << "Slow path must be enabled iff concurrent";
+    } else {
+      // Weak ref access is enabled at Zygote compaction by SemiSpace (concurrent == false).
+      CHECK_EQ(!self->GetWeakRefAccessEnabled(), concurrent);
+    }
   }
   // Unless required to clear soft references with white references, preserve some white referents.
   if (!clear_soft_references) {
@@ -137,16 +138,17 @@
     if (concurrent) {
       StartPreservingReferences(self);
     }
-    soft_reference_queue_.ForwardSoftReferences(&PreserveSoftReferenceCallback,
-                                                &process_references_args_);
-    process_mark_stack_callback(arg);
+    // TODO: Add smarter logic for preserving soft references. The behavior should be a conditional
+    // mark if the SoftReference is supposed to be preserved.
+    soft_reference_queue_.ForwardSoftReferences(collector);
+    collector->ProcessMarkStack();
     if (concurrent) {
       StopPreservingReferences(self);
     }
   }
   // Clear all remaining soft and weak references with white referents.
-  soft_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
-  weak_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
+  soft_reference_queue_.ClearWhiteReferences(&cleared_references_, collector);
+  weak_reference_queue_.ClearWhiteReferences(&cleared_references_, collector);
   {
     TimingLogger::ScopedTiming t2(concurrent ? "EnqueueFinalizerReferences" :
         "(Paused)EnqueueFinalizerReferences", timings);
@@ -154,18 +156,17 @@
       StartPreservingReferences(self);
     }
     // Preserve all white objects with finalize methods and schedule them for finalization.
-    finalizer_reference_queue_.EnqueueFinalizerReferences(&cleared_references_, is_marked_callback,
-                                                          mark_object_callback, arg);
-    process_mark_stack_callback(arg);
+    finalizer_reference_queue_.EnqueueFinalizerReferences(&cleared_references_, collector);
+    collector->ProcessMarkStack();
     if (concurrent) {
       StopPreservingReferences(self);
     }
   }
   // Clear all finalizer referent reachable soft and weak references with white referents.
-  soft_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
-  weak_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
+  soft_reference_queue_.ClearWhiteReferences(&cleared_references_, collector);
+  weak_reference_queue_.ClearWhiteReferences(&cleared_references_, collector);
   // Clear all phantom references with white referents.
-  phantom_reference_queue_.ClearWhiteReferences(&cleared_references_, is_marked_callback, arg);
+  phantom_reference_queue_.ClearWhiteReferences(&cleared_references_, collector);
   // At this point all reference queues other than the cleared references should be empty.
   DCHECK(soft_reference_queue_.IsEmpty());
   DCHECK(weak_reference_queue_.IsEmpty());
@@ -177,8 +178,8 @@
     // could result in a stale is_marked_callback_ being called before the reference processing
     // starts since there is a small window of time where slow_path_enabled_ is enabled but the
     // callback isn't yet set.
-    process_references_args_.is_marked_callback_ = nullptr;
-    if (concurrent) {
+    collector_ = nullptr;
+    if (!kUseReadBarrier && concurrent) {
       // Done processing, disable the slow path and broadcast to the waiters.
       DisableSlowPath(self);
     }
@@ -188,13 +189,12 @@
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
 // marked, put it on the appropriate list in the heap for later processing.
 void ReferenceProcessor::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
-                                                IsHeapReferenceMarkedCallback* is_marked_callback,
-                                                void* arg) {
+                                                collector::GarbageCollector* collector) {
   // klass can be the class of the old object if the visitor already updated the class of ref.
   DCHECK(klass != nullptr);
   DCHECK(klass->IsTypeOfReferenceClass());
   mirror::HeapReference<mirror::Object>* referent = ref->GetReferentReferenceAddr();
-  if (referent->AsMirrorPtr() != nullptr && !is_marked_callback(referent, arg)) {
+  if (referent->AsMirrorPtr() != nullptr && !collector->IsMarkedHeapReference(referent)) {
     Thread* self = Thread::Current();
     // TODO: Remove these locks, and use atomic stacks for storing references?
     // We need to check that the references haven't already been enqueued since we can end up
@@ -214,8 +214,8 @@
   }
 }
 
-void ReferenceProcessor::UpdateRoots(IsMarkedCallback* callback, void* arg) {
-  cleared_references_.UpdateRoots(callback, arg);
+void ReferenceProcessor::UpdateRoots(IsMarkedVisitor* visitor) {
+  cleared_references_.UpdateRoots(visitor);
 }
 
 class ClearedReferenceTask : public HeapTask {
@@ -264,7 +264,8 @@
   Thread* self = Thread::Current();
   MutexLock mu(self, *Locks::reference_processor_lock_);
   // Wait untul we are done processing reference.
-  while (SlowPathEnabled()) {
+  while ((!kUseReadBarrier && SlowPathEnabled()) ||
+         (kUseReadBarrier && !self->GetWeakRefAccessEnabled())) {
     condition_.WaitHoldingLocks(self);
   }
   // At this point, since the sentinel of the reference is live, it is guaranteed to not be
diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h
index a44319b..95877d1 100644
--- a/runtime/gc/reference_processor.h
+++ b/runtime/gc/reference_processor.h
@@ -28,6 +28,7 @@
 class TimingLogger;
 
 namespace mirror {
+class Class;
 class FinalizerReference;
 class Object;
 class Reference;
@@ -35,18 +36,18 @@
 
 namespace gc {
 
+namespace collector {
+class GarbageCollector;
+}  // namespace collector
+
 class Heap;
 
 // Used to process java.lang.References concurrently or paused.
 class ReferenceProcessor {
  public:
   explicit ReferenceProcessor();
-  static bool PreserveSoftReferenceCallback(mirror::HeapReference<mirror::Object>* obj, void* arg)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ProcessReferences(bool concurrent, TimingLogger* timings, bool clear_soft_references,
-                         IsHeapReferenceMarkedCallback* is_marked_callback,
-                         MarkObjectCallback* mark_object_callback,
-                         ProcessMarkStackCallback* process_mark_stack_callback, void* arg)
+                         gc::collector::GarbageCollector* collector)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       LOCKS_EXCLUDED(Locks::reference_processor_lock_);
@@ -54,14 +55,15 @@
   // Only allow setting this with mutators suspended so that we can avoid using a lock in the
   // GetReferent fast path as an optimization.
   void EnableSlowPath() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void BroadcastForSlowPath(Thread* self);
   // Decode the referent, may block if references are being processed.
   mirror::Object* GetReferent(Thread* self, mirror::Reference* reference)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::reference_processor_lock_);
   void EnqueueClearedReferences(Thread* self) LOCKS_EXCLUDED(Locks::mutator_lock_);
   void DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
-                              IsHeapReferenceMarkedCallback* is_marked_callback, void* arg)
+                              collector::GarbageCollector* collector)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void UpdateRoots(IsMarkedCallback* callback, void* arg)
+  void UpdateRoots(IsMarkedVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
   // Make a circular list with reference if it is not enqueued. Uses the finalizer queue lock.
   bool MakeCircularListIfUnenqueued(mirror::FinalizerReference* reference)
@@ -70,21 +72,6 @@
                      Locks::reference_queue_finalizer_references_lock_);
 
  private:
-  class ProcessReferencesArgs {
-   public:
-    ProcessReferencesArgs(IsHeapReferenceMarkedCallback* is_marked_callback,
-                          MarkObjectCallback* mark_callback, void* arg)
-        : is_marked_callback_(is_marked_callback), mark_callback_(mark_callback), arg_(arg) {
-    }
-
-    // The is marked callback is null when the args aren't set up.
-    IsHeapReferenceMarkedCallback* is_marked_callback_;
-    MarkObjectCallback* mark_callback_;
-    void* arg_;
-
-   private:
-    DISALLOW_IMPLICIT_CONSTRUCTORS(ProcessReferencesArgs);
-  };
   bool SlowPathEnabled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Called by ProcessReferences.
   void DisableSlowPath(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(Locks::reference_processor_lock_)
@@ -94,8 +81,9 @@
   // referents.
   void StartPreservingReferences(Thread* self) LOCKS_EXCLUDED(Locks::reference_processor_lock_);
   void StopPreservingReferences(Thread* self) LOCKS_EXCLUDED(Locks::reference_processor_lock_);
-  // Process args, used by the GetReferent to return referents which are already marked.
-  ProcessReferencesArgs process_references_args_ GUARDED_BY(Locks::reference_processor_lock_);
+  // Collector which is clearing references, used by the GetReferent to return referents which are
+  // already marked.
+  collector::GarbageCollector* collector_ GUARDED_BY(Locks::reference_processor_lock_);
   // Boolean for whether or not we are preserving references (either soft references or finalizers).
   // If this is true, then we cannot return a referent (see comment in GetReferent).
   bool preserving_references_ GUARDED_BY(Locks::reference_processor_lock_);
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index 4ba3983..f505428 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -137,12 +137,12 @@
 }
 
 void ReferenceQueue::ClearWhiteReferences(ReferenceQueue* cleared_references,
-                                          IsHeapReferenceMarkedCallback* preserve_callback,
-                                          void* arg) {
+                                          collector::GarbageCollector* collector) {
   while (!IsEmpty()) {
     mirror::Reference* ref = DequeuePendingReference();
     mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
-    if (referent_addr->AsMirrorPtr() != nullptr && !preserve_callback(referent_addr, arg)) {
+    if (referent_addr->AsMirrorPtr() != nullptr &&
+        !collector->IsMarkedHeapReference(referent_addr)) {
       // Referent is white, clear it.
       if (Runtime::Current()->IsActiveTransaction()) {
         ref->ClearReferent<true>();
@@ -157,14 +157,13 @@
 }
 
 void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
-                                                IsHeapReferenceMarkedCallback* is_marked_callback,
-                                                MarkObjectCallback* mark_object_callback,
-                                                void* arg) {
+                                                collector::GarbageCollector* collector) {
   while (!IsEmpty()) {
     mirror::FinalizerReference* ref = DequeuePendingReference()->AsFinalizerReference();
     mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
-    if (referent_addr->AsMirrorPtr() != nullptr && !is_marked_callback(referent_addr, arg)) {
-      mirror::Object* forward_address = mark_object_callback(referent_addr->AsMirrorPtr(), arg);
+    if (referent_addr->AsMirrorPtr() != nullptr &&
+        !collector->IsMarkedHeapReference(referent_addr)) {
+      mirror::Object* forward_address = collector->MarkObject(referent_addr->AsMirrorPtr());
       // If the referent is non-null the reference must queuable.
       DCHECK(ref->IsEnqueuable());
       // Move the updated referent to the zombie field.
@@ -180,8 +179,7 @@
   }
 }
 
-void ReferenceQueue::ForwardSoftReferences(IsHeapReferenceMarkedCallback* preserve_callback,
-                                           void* arg) {
+void ReferenceQueue::ForwardSoftReferences(MarkObjectVisitor* visitor) {
   if (UNLIKELY(IsEmpty())) {
     return;
   }
@@ -190,15 +188,15 @@
   do {
     mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
     if (referent_addr->AsMirrorPtr() != nullptr) {
-      UNUSED(preserve_callback(referent_addr, arg));
+      visitor->MarkHeapReference(referent_addr);
     }
     ref = ref->GetPendingNext();
   } while (LIKELY(ref != head));
 }
 
-void ReferenceQueue::UpdateRoots(IsMarkedCallback* callback, void* arg) {
+void ReferenceQueue::UpdateRoots(IsMarkedVisitor* visitor) {
   if (list_ != nullptr) {
-    list_ = down_cast<mirror::Reference*>(callback(list_, arg));
+    list_ = down_cast<mirror::Reference*>(visitor->IsMarked(list_));
   }
 }
 
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index c45be85..7d9ddf6 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -36,6 +36,10 @@
 
 namespace gc {
 
+namespace collector {
+class GarbageCollector;
+}  // namespace collector
+
 class Heap;
 
 // Used to temporarily store java.lang.ref.Reference(s) during GC and prior to queueing on the
@@ -65,20 +69,19 @@
   // Enqueues finalizer references with white referents.  White referents are blackened, moved to
   // the zombie field, and the referent field is cleared.
   void EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
-                                  IsHeapReferenceMarkedCallback* is_marked_callback,
-                                  MarkObjectCallback* mark_object_callback, void* arg)
+                                  collector::GarbageCollector* collector)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Walks the reference list marking any references subject to the reference clearing policy.
   // References with a black referent are removed from the list.  References with white referents
   // biased toward saving are blackened and also removed from the list.
-  void ForwardSoftReferences(IsHeapReferenceMarkedCallback* preserve_callback, void* arg)
+  void ForwardSoftReferences(MarkObjectVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Unlink the reference list clearing references objects with white referents. Cleared references
   // registered to a reference queue are scheduled for appending by the heap worker thread.
   void ClearWhiteReferences(ReferenceQueue* cleared_references,
-                            IsHeapReferenceMarkedCallback* is_marked_callback, void* arg)
+                            collector::GarbageCollector* collector)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void Dump(std::ostream& os) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -95,7 +98,7 @@
   }
 
   // Visits list_, currently only used for the mark compact GC.
-  void UpdateRoots(IsMarkedCallback* callback, void* arg)
+  void UpdateRoots(IsMarkedVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
diff --git a/runtime/gc/space/bump_pointer_space-inl.h b/runtime/gc/space/bump_pointer_space-inl.h
index d9ad9a3..338a41e 100644
--- a/runtime/gc/space/bump_pointer_space-inl.h
+++ b/runtime/gc/space/bump_pointer_space-inl.h
@@ -63,7 +63,7 @@
 }
 
 inline mirror::Object* BumpPointerSpace::AllocNonvirtualWithoutAccounting(size_t num_bytes) {
-  DCHECK(IsAligned<kAlignment>(num_bytes));
+  DCHECK_ALIGNED(num_bytes, kAlignment);
   uint8_t* old_end;
   uint8_t* new_end;
   do {
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 5237c7b..e1c5b64 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -20,13 +20,13 @@
 #include "gc/accounting/card_table.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
+#include "memory_tool_malloc_space-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "runtime.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "utils.h"
-#include "valgrind_malloc_space-inl.h"
 
 namespace art {
 namespace gc {
@@ -62,8 +62,8 @@
 
   // Everything is set so record in immutable structure and leave
   uint8_t* begin = mem_map->Begin();
-  if (Runtime::Current()->RunningOnValgrind()) {
-    return new ValgrindMallocSpace<DlMallocSpace, kDefaultValgrindRedZoneBytes, true, false>(
+  if (Runtime::Current()->IsRunningOnMemoryTool()) {
+    return new MemoryToolMallocSpace<DlMallocSpace, kDefaultMemoryToolRedZoneBytes, true, false>(
         mem_map, initial_size, name, mspace, begin, end, begin + capacity, growth_limit,
         can_move_objects, starting_size);
   } else {
@@ -152,8 +152,8 @@
                                            void* allocator, uint8_t* begin, uint8_t* end,
                                            uint8_t* limit, size_t growth_limit,
                                            bool can_move_objects) {
-  if (Runtime::Current()->RunningOnValgrind()) {
-    return new ValgrindMallocSpace<DlMallocSpace, kDefaultValgrindRedZoneBytes, true, false>(
+  if (Runtime::Current()->IsRunningOnMemoryTool()) {
+    return new MemoryToolMallocSpace<DlMallocSpace, kDefaultMemoryToolRedZoneBytes, true, false>(
         mem_map, initial_size_, name, allocator, begin, end, limit, growth_limit,
         can_move_objects, starting_size_);
   } else {
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index 1f80f1f..ab527a4 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -30,7 +30,7 @@
 namespace space {
 
 // An alloc space is a space where objects may be allocated and garbage collected. Not final as may
-// be overridden by a ValgrindMallocSpace.
+// be overridden by a MemoryToolMallocSpace.
 class DlMallocSpace : public MallocSpace {
  public:
   // Create a DlMallocSpace from an existing mem_map.
@@ -46,27 +46,27 @@
   static DlMallocSpace* Create(const std::string& name, size_t initial_size, size_t growth_limit,
                                size_t capacity, uint8_t* requested_begin, bool can_move_objects);
 
-  // Virtual to allow ValgrindMallocSpace to intercept.
+  // Virtual to allow MemoryToolMallocSpace to intercept.
   virtual mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated,
                                           size_t* usable_size,
                                           size_t* bytes_tl_bulk_allocated)
       OVERRIDE LOCKS_EXCLUDED(lock_);
-  // Virtual to allow ValgrindMallocSpace to intercept.
+  // Virtual to allow MemoryToolMallocSpace to intercept.
   virtual mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
                                 size_t* usable_size, size_t* bytes_tl_bulk_allocated)
       OVERRIDE LOCKS_EXCLUDED(lock_) {
     return AllocNonvirtual(self, num_bytes, bytes_allocated, usable_size,
                            bytes_tl_bulk_allocated);
   }
-  // Virtual to allow ValgrindMallocSpace to intercept.
+  // Virtual to allow MemoryToolMallocSpace to intercept.
   virtual size_t AllocationSize(mirror::Object* obj, size_t* usable_size) OVERRIDE {
     return AllocationSizeNonvirtual(obj, usable_size);
   }
-  // Virtual to allow ValgrindMallocSpace to intercept.
+  // Virtual to allow MemoryToolMallocSpace to intercept.
   virtual size_t Free(Thread* self, mirror::Object* ptr) OVERRIDE
       LOCKS_EXCLUDED(lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  // Virtual to allow ValgrindMallocSpace to intercept.
+  // Virtual to allow MemoryToolMallocSpace to intercept.
   virtual size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) OVERRIDE
       LOCKS_EXCLUDED(lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 52192e2..2798b21 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -16,7 +16,9 @@
 
 #include "large_object_space.h"
 
+#include <valgrind.h>
 #include <memory>
+#include <memcheck/memcheck.h>
 
 #include "gc/accounting/heap_bitmap-inl.h"
 #include "gc/accounting/space_bitmap-inl.h"
@@ -32,12 +34,12 @@
 namespace gc {
 namespace space {
 
-class ValgrindLargeObjectMapSpace FINAL : public LargeObjectMapSpace {
+class MemoryToolLargeObjectMapSpace FINAL : public LargeObjectMapSpace {
  public:
-  explicit ValgrindLargeObjectMapSpace(const std::string& name) : LargeObjectMapSpace(name) {
+  explicit MemoryToolLargeObjectMapSpace(const std::string& name) : LargeObjectMapSpace(name) {
   }
 
-  ~ValgrindLargeObjectMapSpace() OVERRIDE {
+  ~MemoryToolLargeObjectMapSpace() OVERRIDE {
     // Keep valgrind happy if there is any large objects such as dex cache arrays which aren't
     // freed since they are held live by the class linker.
     MutexLock mu(Thread::Current(), lock_);
@@ -50,13 +52,14 @@
                         size_t* usable_size, size_t* bytes_tl_bulk_allocated)
       OVERRIDE {
     mirror::Object* obj =
-        LargeObjectMapSpace::Alloc(self, num_bytes + kValgrindRedZoneBytes * 2, bytes_allocated,
+        LargeObjectMapSpace::Alloc(self, num_bytes + kMemoryToolRedZoneBytes * 2, bytes_allocated,
                                    usable_size, bytes_tl_bulk_allocated);
     mirror::Object* object_without_rdz = reinterpret_cast<mirror::Object*>(
-        reinterpret_cast<uintptr_t>(obj) + kValgrindRedZoneBytes);
-    VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<void*>(obj), kValgrindRedZoneBytes);
-    VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<uint8_t*>(object_without_rdz) + num_bytes,
-                               kValgrindRedZoneBytes);
+        reinterpret_cast<uintptr_t>(obj) + kMemoryToolRedZoneBytes);
+    MEMORY_TOOL_MAKE_NOACCESS(reinterpret_cast<void*>(obj), kMemoryToolRedZoneBytes);
+    MEMORY_TOOL_MAKE_NOACCESS(
+        reinterpret_cast<uint8_t*>(object_without_rdz) + num_bytes,
+        kMemoryToolRedZoneBytes);
     if (usable_size != nullptr) {
       *usable_size = num_bytes;  // Since we have redzones, shrink the usable size.
     }
@@ -73,7 +76,7 @@
 
   size_t Free(Thread* self, mirror::Object* obj) OVERRIDE {
     mirror::Object* object_with_rdz = ObjectWithRedzone(obj);
-    VALGRIND_MAKE_MEM_UNDEFINED(object_with_rdz, AllocationSize(obj, nullptr));
+    MEMORY_TOOL_MAKE_UNDEFINED(object_with_rdz, AllocationSize(obj, nullptr));
     return LargeObjectMapSpace::Free(self, object_with_rdz);
   }
 
@@ -84,15 +87,15 @@
  private:
   static const mirror::Object* ObjectWithRedzone(const mirror::Object* obj) {
     return reinterpret_cast<const mirror::Object*>(
-        reinterpret_cast<uintptr_t>(obj) - kValgrindRedZoneBytes);
+        reinterpret_cast<uintptr_t>(obj) - kMemoryToolRedZoneBytes);
   }
 
   static mirror::Object* ObjectWithRedzone(mirror::Object* obj) {
     return reinterpret_cast<mirror::Object*>(
-        reinterpret_cast<uintptr_t>(obj) - kValgrindRedZoneBytes);
+        reinterpret_cast<uintptr_t>(obj) - kMemoryToolRedZoneBytes);
   }
 
-  static constexpr size_t kValgrindRedZoneBytes = kPageSize;
+  static constexpr size_t kMemoryToolRedZoneBytes = kPageSize;
 };
 
 void LargeObjectSpace::SwapBitmaps() {
@@ -119,8 +122,8 @@
       lock_("large object map space lock", kAllocSpaceLock) {}
 
 LargeObjectMapSpace* LargeObjectMapSpace::Create(const std::string& name) {
-  if (Runtime::Current()->RunningOnValgrind()) {
-    return new ValgrindLargeObjectMapSpace(name);
+  if (Runtime::Current()->IsRunningOnMemoryTool()) {
+    return new MemoryToolLargeObjectMapSpace(name);
   } else {
     return new LargeObjectMapSpace(name);
   }
@@ -437,7 +440,7 @@
       AllocationInfo* next_next_info = next_info->GetNextInfo();
       // Next next info can't be free since we always coalesce.
       DCHECK(!next_next_info->IsFree());
-      DCHECK(IsAligned<kAlignment>(next_next_info->ByteSize()));
+      DCHECK_ALIGNED(next_next_info->ByteSize(), kAlignment);
       new_free_info = next_next_info;
       new_free_size += next_next_info->GetPrevFreeBytes();
       RemoveFreePrev(next_next_info);
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index b014217..3a0d814 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -46,8 +46,8 @@
   if (create_bitmaps) {
     size_t bitmap_index = bitmap_index_++;
     static const uintptr_t kGcCardSize = static_cast<uintptr_t>(accounting::CardTable::kCardSize);
-    CHECK(IsAligned<kGcCardSize>(reinterpret_cast<uintptr_t>(mem_map->Begin())));
-    CHECK(IsAligned<kGcCardSize>(reinterpret_cast<uintptr_t>(mem_map->End())));
+    CHECK_ALIGNED(reinterpret_cast<uintptr_t>(mem_map->Begin()), kGcCardSize);
+    CHECK_ALIGNED(reinterpret_cast<uintptr_t>(mem_map->End()), kGcCardSize);
     live_bitmap_.reset(accounting::ContinuousSpaceBitmap::Create(
         StringPrintf("allocspace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
         Begin(), NonGrowthLimitCapacity()));
@@ -164,10 +164,10 @@
   // alloc spaces.
   RevokeAllThreadLocalBuffers();
   SetEnd(reinterpret_cast<uint8_t*>(RoundUp(reinterpret_cast<uintptr_t>(End()), kPageSize)));
-  DCHECK(IsAligned<accounting::CardTable::kCardSize>(begin_));
-  DCHECK(IsAligned<accounting::CardTable::kCardSize>(End()));
-  DCHECK(IsAligned<kPageSize>(begin_));
-  DCHECK(IsAligned<kPageSize>(End()));
+  DCHECK_ALIGNED(begin_, accounting::CardTable::kCardSize);
+  DCHECK_ALIGNED(End(), accounting::CardTable::kCardSize);
+  DCHECK_ALIGNED(begin_, kPageSize);
+  DCHECK_ALIGNED(End(), kPageSize);
   size_t size = RoundUp(Size(), kPageSize);
   // Trimming the heap should be done by the caller since we may have invalidated the accounting
   // stored in between objects.
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 5f3a1db..6c689cd 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -20,8 +20,7 @@
 #include "space.h"
 
 #include <ostream>
-#include <valgrind.h>
-#include <memcheck/memcheck.h>
+#include "base/memory_tool.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/valgrind_malloc_space-inl.h b/runtime/gc/space/memory_tool_malloc_space-inl.h
similarity index 72%
rename from runtime/gc/space/valgrind_malloc_space-inl.h
rename to runtime/gc/space/memory_tool_malloc_space-inl.h
index bc329e1..ea8b8aa 100644
--- a/runtime/gc/space/valgrind_malloc_space-inl.h
+++ b/runtime/gc/space/memory_tool_malloc_space-inl.h
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_GC_SPACE_VALGRIND_MALLOC_SPACE_INL_H_
-#define ART_RUNTIME_GC_SPACE_VALGRIND_MALLOC_SPACE_INL_H_
+#ifndef ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
+#define ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
 
-#include "valgrind_malloc_space.h"
-
-#include <memcheck/memcheck.h>
-
-#include "valgrind_settings.h"
+#include "base/memory_tool.h"
+#include "memory_tool_malloc_space.h"
+#include "memory_tool_settings.h"
 
 namespace art {
 namespace gc {
 namespace space {
 
-namespace valgrind_details {
+namespace memory_tool_details {
 
-template <size_t kValgrindRedZoneBytes, bool kUseObjSizeForUsable>
+template <size_t kMemoryToolRedZoneBytes, bool kUseObjSizeForUsable>
 inline mirror::Object* AdjustForValgrind(void* obj_with_rdz, size_t num_bytes,
                                          size_t bytes_allocated, size_t usable_size,
                                          size_t bytes_tl_bulk_allocated,
@@ -48,26 +46,26 @@
     if (kUseObjSizeForUsable) {
       *usable_size_out = num_bytes;
     } else {
-      *usable_size_out = usable_size - 2 * kValgrindRedZoneBytes;
+      *usable_size_out = usable_size - 2 * kMemoryToolRedZoneBytes;
     }
   }
 
   // Left redzone.
-  VALGRIND_MAKE_MEM_NOACCESS(obj_with_rdz, kValgrindRedZoneBytes);
+  MEMORY_TOOL_MAKE_NOACCESS(obj_with_rdz, kMemoryToolRedZoneBytes);
 
   // Make requested memory readable.
   // (If the allocator assumes memory is zeroed out, we might get UNDEFINED warnings, so make
   //  everything DEFINED initially.)
   mirror::Object* result = reinterpret_cast<mirror::Object*>(
-      reinterpret_cast<uint8_t*>(obj_with_rdz) + kValgrindRedZoneBytes);
-  VALGRIND_MAKE_MEM_DEFINED(result, num_bytes);
+      reinterpret_cast<uint8_t*>(obj_with_rdz) + kMemoryToolRedZoneBytes);
+  MEMORY_TOOL_MAKE_DEFINED(result, num_bytes);
 
   // Right redzone. Assumes that if bytes_allocated > usable_size, then the difference is
   // management data at the upper end, and for simplicity we will not protect that.
   // At the moment, this fits RosAlloc (no management data in a slot, usable_size == alloc_size)
   // and DlMalloc (allocation_size = (usable_size == num_bytes) + 4, 4 is management)
-  VALGRIND_MAKE_MEM_NOACCESS(reinterpret_cast<uint8_t*>(result) + num_bytes,
-                             usable_size - (num_bytes + kValgrindRedZoneBytes));
+  MEMORY_TOOL_MAKE_NOACCESS(reinterpret_cast<uint8_t*>(result) + num_bytes,
+                    usable_size - (num_bytes + kMemoryToolRedZoneBytes));
 
   return result;
 }
@@ -76,15 +74,15 @@
   return obj->SizeOf<kVerifyNone>();
 }
 
-}  // namespace valgrind_details
+}  // namespace memory_tool_details
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 mirror::Object*
-ValgrindMallocSpace<S,
-                    kValgrindRedZoneBytes,
+MemoryToolMallocSpace<S,
+                    kMemoryToolRedZoneBytes,
                     kAdjustForRedzoneInAllocSize,
                     kUseObjSizeForUsable>::AllocWithGrowth(
     Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
@@ -92,14 +90,14 @@
   size_t bytes_allocated;
   size_t usable_size;
   size_t bytes_tl_bulk_allocated;
-  void* obj_with_rdz = S::AllocWithGrowth(self, num_bytes + 2 * kValgrindRedZoneBytes,
+  void* obj_with_rdz = S::AllocWithGrowth(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
                                           &bytes_allocated, &usable_size,
                                           &bytes_tl_bulk_allocated);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
 
-  return valgrind_details::AdjustForValgrind<kValgrindRedZoneBytes, kUseObjSizeForUsable>(
+  return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
       obj_with_rdz, num_bytes,
       bytes_allocated, usable_size,
       bytes_tl_bulk_allocated,
@@ -109,11 +107,11 @@
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-mirror::Object* ValgrindMallocSpace<S,
-                                    kValgrindRedZoneBytes,
+mirror::Object* MemoryToolMallocSpace<S,
+                                    kMemoryToolRedZoneBytes,
                                     kAdjustForRedzoneInAllocSize,
                                     kUseObjSizeForUsable>::Alloc(
     Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
@@ -121,13 +119,13 @@
   size_t bytes_allocated;
   size_t usable_size;
   size_t bytes_tl_bulk_allocated;
-  void* obj_with_rdz = S::Alloc(self, num_bytes + 2 * kValgrindRedZoneBytes,
+  void* obj_with_rdz = S::Alloc(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
                                 &bytes_allocated, &usable_size, &bytes_tl_bulk_allocated);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
 
-  return valgrind_details::AdjustForValgrind<kValgrindRedZoneBytes,
+  return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes,
                                              kUseObjSizeForUsable>(obj_with_rdz, num_bytes,
                                                                    bytes_allocated, usable_size,
                                                                    bytes_tl_bulk_allocated,
@@ -137,11 +135,11 @@
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-mirror::Object* ValgrindMallocSpace<S,
-                                    kValgrindRedZoneBytes,
+mirror::Object* MemoryToolMallocSpace<S,
+                                    kMemoryToolRedZoneBytes,
                                     kAdjustForRedzoneInAllocSize,
                                     kUseObjSizeForUsable>::AllocThreadUnsafe(
     Thread* self, size_t num_bytes, size_t* bytes_allocated_out, size_t* usable_size_out,
@@ -149,14 +147,14 @@
   size_t bytes_allocated;
   size_t usable_size;
   size_t bytes_tl_bulk_allocated;
-  void* obj_with_rdz = S::AllocThreadUnsafe(self, num_bytes + 2 * kValgrindRedZoneBytes,
+  void* obj_with_rdz = S::AllocThreadUnsafe(self, num_bytes + 2 * kMemoryToolRedZoneBytes,
                                             &bytes_allocated, &usable_size,
                                             &bytes_tl_bulk_allocated);
   if (obj_with_rdz == nullptr) {
     return nullptr;
   }
 
-  return valgrind_details::AdjustForValgrind<kValgrindRedZoneBytes, kUseObjSizeForUsable>(
+  return memory_tool_details::AdjustForValgrind<kMemoryToolRedZoneBytes, kUseObjSizeForUsable>(
       obj_with_rdz, num_bytes,
       bytes_allocated, usable_size,
       bytes_tl_bulk_allocated,
@@ -166,38 +164,39 @@
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-size_t ValgrindMallocSpace<S,
-                           kValgrindRedZoneBytes,
+size_t MemoryToolMallocSpace<S,
+                           kMemoryToolRedZoneBytes,
                            kAdjustForRedzoneInAllocSize,
                            kUseObjSizeForUsable>::AllocationSize(
     mirror::Object* obj, size_t* usable_size) {
   size_t result = S::AllocationSize(reinterpret_cast<mirror::Object*>(
-      reinterpret_cast<uint8_t*>(obj) - (kAdjustForRedzoneInAllocSize ? kValgrindRedZoneBytes : 0)),
+      reinterpret_cast<uint8_t*>(obj) - (kAdjustForRedzoneInAllocSize ? kMemoryToolRedZoneBytes : 0)),
       usable_size);
   if (usable_size != nullptr) {
     if (kUseObjSizeForUsable) {
-      *usable_size = valgrind_details::GetObjSizeNoThreadSafety(obj);
+      *usable_size = memory_tool_details::GetObjSizeNoThreadSafety(obj);
     } else {
-      *usable_size = *usable_size - 2 * kValgrindRedZoneBytes;
+      *usable_size = *usable_size - 2 * kMemoryToolRedZoneBytes;
     }
   }
   return result;
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-size_t ValgrindMallocSpace<S,
-                           kValgrindRedZoneBytes,
+size_t MemoryToolMallocSpace<S,
+                           kMemoryToolRedZoneBytes,
                            kAdjustForRedzoneInAllocSize,
                            kUseObjSizeForUsable>::Free(
     Thread* self, mirror::Object* ptr) {
   void* obj_after_rdz = reinterpret_cast<void*>(ptr);
-  uint8_t* obj_with_rdz = reinterpret_cast<uint8_t*>(obj_after_rdz) - kValgrindRedZoneBytes;
+  uint8_t* obj_with_rdz = reinterpret_cast<uint8_t*>(obj_after_rdz) - kMemoryToolRedZoneBytes;
+
   // Make redzones undefined.
   size_t usable_size;
   size_t allocation_size = AllocationSize(ptr, &usable_size);
@@ -206,20 +205,20 @@
   // Use the obj-size-for-usable flag to determine whether usable_size is the more important one,
   // e.g., whether there's data in the allocation_size (and usable_size can't be trusted).
   if (kUseObjSizeForUsable) {
-    VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, allocation_size);
+    MEMORY_TOOL_MAKE_UNDEFINED(obj_with_rdz, allocation_size);
   } else {
-    VALGRIND_MAKE_MEM_UNDEFINED(obj_with_rdz, usable_size + 2 * kValgrindRedZoneBytes);
+    MEMORY_TOOL_MAKE_UNDEFINED(obj_with_rdz, usable_size + 2 * kMemoryToolRedZoneBytes);
   }
 
   return S::Free(self, reinterpret_cast<mirror::Object*>(obj_with_rdz));
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-size_t ValgrindMallocSpace<S,
-                           kValgrindRedZoneBytes,
+size_t MemoryToolMallocSpace<S,
+                           kMemoryToolRedZoneBytes,
                            kAdjustForRedzoneInAllocSize,
                            kUseObjSizeForUsable>::FreeList(
     Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
@@ -232,32 +231,33 @@
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
 template <typename... Params>
-ValgrindMallocSpace<S,
-                    kValgrindRedZoneBytes,
+MemoryToolMallocSpace<S,
+                    kMemoryToolRedZoneBytes,
                     kAdjustForRedzoneInAllocSize,
-                    kUseObjSizeForUsable>::ValgrindMallocSpace(
+                    kUseObjSizeForUsable>::MemoryToolMallocSpace(
     MemMap* mem_map, size_t initial_size, Params... params) : S(mem_map, initial_size, params...) {
-  VALGRIND_MAKE_MEM_UNDEFINED(mem_map->Begin() + initial_size,
-                              mem_map->Size() - initial_size);
+  MEMORY_TOOL_MAKE_DEFINED(mem_map->Begin(), initial_size);
+  MEMORY_TOOL_MAKE_UNDEFINED(mem_map->Begin() + initial_size,
+                     mem_map->Size() - initial_size);
 }
 
 template <typename S,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-size_t ValgrindMallocSpace<S,
-                           kValgrindRedZoneBytes,
+size_t MemoryToolMallocSpace<S,
+                           kMemoryToolRedZoneBytes,
                            kAdjustForRedzoneInAllocSize,
                            kUseObjSizeForUsable>::MaxBytesBulkAllocatedFor(size_t num_bytes) {
-  return S::MaxBytesBulkAllocatedFor(num_bytes + 2 * kValgrindRedZoneBytes);
+  return S::MaxBytesBulkAllocatedFor(num_bytes + 2 * kMemoryToolRedZoneBytes);
 }
 
 }  // namespace space
 }  // namespace gc
 }  // namespace art
 
-#endif  // ART_RUNTIME_GC_SPACE_VALGRIND_MALLOC_SPACE_INL_H_
+#endif  // ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_INL_H_
diff --git a/runtime/gc/space/valgrind_malloc_space.h b/runtime/gc/space/memory_tool_malloc_space.h
similarity index 78%
rename from runtime/gc/space/valgrind_malloc_space.h
rename to runtime/gc/space/memory_tool_malloc_space.h
index a6b010a..64c6f35 100644
--- a/runtime/gc/space/valgrind_malloc_space.h
+++ b/runtime/gc/space/memory_tool_malloc_space.h
@@ -14,24 +14,22 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_GC_SPACE_VALGRIND_MALLOC_SPACE_H_
-#define ART_RUNTIME_GC_SPACE_VALGRIND_MALLOC_SPACE_H_
+#ifndef ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_H_
+#define ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_H_
 
 #include "malloc_space.h"
 
-#include <valgrind.h>
-
 namespace art {
 namespace gc {
 namespace space {
 
-// A specialization of DlMallocSpace/RosAllocSpace that places valgrind red zones around
-// allocations.
+// A specialization of DlMallocSpace/RosAllocSpace that places memory tool red
+// zones around allocations.
 template <typename BaseMallocSpaceType,
-          size_t kValgrindRedZoneBytes,
+          size_t kMemoryToolRedZoneBytes,
           bool kAdjustForRedzoneInAllocSize,
           bool kUseObjSizeForUsable>
-class ValgrindMallocSpace FINAL : public BaseMallocSpaceType {
+class MemoryToolMallocSpace FINAL : public BaseMallocSpaceType {
  public:
   mirror::Object* AllocWithGrowth(Thread* self, size_t num_bytes, size_t* bytes_allocated,
                                   size_t* usable_size, size_t* bytes_tl_bulk_allocated)
@@ -57,15 +55,15 @@
   size_t MaxBytesBulkAllocatedFor(size_t num_bytes) OVERRIDE;
 
   template <typename... Params>
-  explicit ValgrindMallocSpace(MemMap* mem_map, size_t initial_size, Params... params);
-  virtual ~ValgrindMallocSpace() {}
+  explicit MemoryToolMallocSpace(MemMap* mem_map, size_t initial_size, Params... params);
+  virtual ~MemoryToolMallocSpace() {}
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ValgrindMallocSpace);
+  DISALLOW_COPY_AND_ASSIGN(MemoryToolMallocSpace);
 };
 
 }  // namespace space
 }  // namespace gc
 }  // namespace art
 
-#endif  // ART_RUNTIME_GC_SPACE_VALGRIND_MALLOC_SPACE_H_
+#endif  // ART_RUNTIME_GC_SPACE_MEMORY_TOOL_MALLOC_SPACE_H_
diff --git a/runtime/gc/space/valgrind_settings.h b/runtime/gc/space/memory_tool_settings.h
similarity index 80%
rename from runtime/gc/space/valgrind_settings.h
rename to runtime/gc/space/memory_tool_settings.h
index 73da0fd..e9333c8 100644
--- a/runtime/gc/space/valgrind_settings.h
+++ b/runtime/gc/space/memory_tool_settings.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_GC_SPACE_VALGRIND_SETTINGS_H_
-#define ART_RUNTIME_GC_SPACE_VALGRIND_SETTINGS_H_
+#ifndef ART_RUNTIME_GC_SPACE_MEMORY_TOOL_SETTINGS_H_
+#define ART_RUNTIME_GC_SPACE_MEMORY_TOOL_SETTINGS_H_
 
 namespace art {
 namespace gc {
@@ -23,10 +23,10 @@
 
 // Default 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.
-static constexpr size_t kDefaultValgrindRedZoneBytes = 8;
+static constexpr size_t kDefaultMemoryToolRedZoneBytes = 8;
 
 }  // namespace space
 }  // namespace gc
 }  // namespace art
 
-#endif  // ART_RUNTIME_GC_SPACE_VALGRIND_SETTINGS_H_
+#endif  // ART_RUNTIME_GC_SPACE_MEMORY_TOOL_SETTINGS_H_
diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h
index 1cdf69d..db005f7 100644
--- a/runtime/gc/space/region_space-inl.h
+++ b/runtime/gc/space/region_space-inl.h
@@ -43,7 +43,7 @@
 inline mirror::Object* RegionSpace::AllocNonvirtual(size_t num_bytes, size_t* bytes_allocated,
                                                     size_t* usable_size,
                                                     size_t* bytes_tl_bulk_allocated) {
-  DCHECK(IsAligned<kAlignment>(num_bytes));
+  DCHECK_ALIGNED(num_bytes, kAlignment);
   mirror::Object* obj;
   if (LIKELY(num_bytes <= kRegionSize)) {
     // Non-large object.
@@ -115,7 +115,7 @@
                                                   size_t* usable_size,
                                                   size_t* bytes_tl_bulk_allocated) {
   DCHECK(IsAllocated() && IsInToSpace());
-  DCHECK(IsAligned<kAlignment>(num_bytes));
+  DCHECK_ALIGNED(num_bytes, kAlignment);
   Atomic<uint8_t*>* atomic_top = reinterpret_cast<Atomic<uint8_t*>*>(&top_);
   uint8_t* old_top;
   uint8_t* new_top;
@@ -266,7 +266,7 @@
 mirror::Object* RegionSpace::AllocLarge(size_t num_bytes, size_t* bytes_allocated,
                                         size_t* usable_size,
                                         size_t* bytes_tl_bulk_allocated) {
-  DCHECK(IsAligned<kAlignment>(num_bytes));
+  DCHECK_ALIGNED(num_bytes, kAlignment);
   DCHECK_GT(num_bytes, kRegionSize);
   size_t num_regs = RoundUp(num_bytes, kRegionSize) / kRegionSize;
   DCHECK_GT(num_regs, 0U);
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index 814ab6c..9a2d0c6 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -287,7 +287,7 @@
 
 void RegionSpace::FreeLarge(mirror::Object* large_obj, size_t bytes_allocated) {
   DCHECK(Contains(large_obj));
-  DCHECK(IsAligned<kRegionSize>(large_obj));
+  DCHECK_ALIGNED(large_obj, kRegionSize);
   MutexLock mu(Thread::Current(), region_lock_);
   uint8_t* begin_addr = reinterpret_cast<uint8_t*>(large_obj);
   uint8_t* end_addr = AlignUp(reinterpret_cast<uint8_t*>(large_obj) + bytes_allocated, kRegionSize);
@@ -366,7 +366,7 @@
   uint8_t* tlab_start = thread->GetTlabStart();
   DCHECK_EQ(thread->HasTlab(), tlab_start != nullptr);
   if (tlab_start != nullptr) {
-    DCHECK(IsAligned<kRegionSize>(tlab_start));
+    DCHECK_ALIGNED(tlab_start, kRegionSize);
     Region* r = RefToRegionLocked(reinterpret_cast<mirror::Object*>(tlab_start));
     DCHECK(r->IsAllocated());
     DCHECK_EQ(thread->GetThreadLocalBytesAllocated(), kRegionSize);
diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h
index 25d4445..8bff2b4 100644
--- a/runtime/gc/space/rosalloc_space-inl.h
+++ b/runtime/gc/space/rosalloc_space-inl.h
@@ -17,8 +17,9 @@
 #ifndef ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 #define ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 
+#include "base/memory_tool.h"
 #include "gc/allocator/rosalloc-inl.h"
-#include "gc/space/valgrind_settings.h"
+#include "gc/space/memory_tool_settings.h"
 #include "rosalloc_space.h"
 #include "thread.h"
 
@@ -26,26 +27,26 @@
 namespace gc {
 namespace space {
 
-template<bool kMaybeRunningOnValgrind>
+template<bool kMaybeIsRunningOnMemoryTool>
 inline size_t RosAllocSpace::AllocationSizeNonvirtual(mirror::Object* obj, size_t* usable_size) {
   // obj is a valid object. Use its class in the header to get the size.
   // Don't use verification since the object may be dead if we are sweeping.
   size_t size = obj->SizeOf<kVerifyNone>();
-  bool running_on_valgrind = false;
-  if (kMaybeRunningOnValgrind) {
-    running_on_valgrind = RUNNING_ON_VALGRIND != 0;
-    if (running_on_valgrind) {
-      size += 2 * kDefaultValgrindRedZoneBytes;
+  bool add_redzones = false;
+  if (kMaybeIsRunningOnMemoryTool) {
+    add_redzones = RUNNING_ON_MEMORY_TOOL ? kMemoryToolAddsRedzones : 0;
+    if (add_redzones) {
+      size += 2 * kDefaultMemoryToolRedZoneBytes;
     }
   } else {
-    DCHECK_EQ(RUNNING_ON_VALGRIND, 0U);
+    DCHECK_EQ(RUNNING_ON_MEMORY_TOOL, 0U);
   }
   size_t size_by_size = rosalloc_->UsableSize(size);
   if (kIsDebugBuild) {
-    // On valgrind, the red zone has an impact...
+    // On memory tool, the red zone has an impact...
     const uint8_t* obj_ptr = reinterpret_cast<const uint8_t*>(obj);
     size_t size_by_ptr = rosalloc_->UsableSize(
-        obj_ptr - (running_on_valgrind ? kDefaultValgrindRedZoneBytes : 0));
+        obj_ptr - (add_redzones ? kDefaultMemoryToolRedZoneBytes : 0));
     if (size_by_size != size_by_ptr) {
       LOG(INFO) << "Found a bad sized obj of size " << size
                 << " at " << std::hex << reinterpret_cast<intptr_t>(obj_ptr) << std::dec
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index bc4414d..1a193c3 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -30,7 +30,7 @@
 #include "thread.h"
 #include "thread_list.h"
 #include "utils.h"
-#include "valgrind_malloc_space-inl.h"
+#include "memory_tool_malloc_space-inl.h"
 
 namespace art {
 namespace gc {
@@ -43,7 +43,7 @@
 static constexpr bool kVerifyFreedBytes = false;
 
 // TODO: Fix
-// template class ValgrindMallocSpace<RosAllocSpace, allocator::RosAlloc*>;
+// template class MemoryToolMallocSpace<RosAllocSpace, allocator::RosAlloc*>;
 
 RosAllocSpace::RosAllocSpace(MemMap* mem_map, size_t initial_size, const std::string& name,
                              art::gc::allocator::RosAlloc* rosalloc, uint8_t* begin, uint8_t* end,
@@ -61,10 +61,10 @@
                                                bool low_memory_mode, bool can_move_objects) {
   DCHECK(mem_map != nullptr);
 
-  bool running_on_valgrind = Runtime::Current()->RunningOnValgrind();
+  bool running_on_memory_tool = Runtime::Current()->IsRunningOnMemoryTool();
 
   allocator::RosAlloc* rosalloc = CreateRosAlloc(mem_map->Begin(), starting_size, initial_size,
-                                                 capacity, low_memory_mode, running_on_valgrind);
+                                                 capacity, low_memory_mode, running_on_memory_tool);
   if (rosalloc == nullptr) {
     LOG(ERROR) << "Failed to initialize rosalloc for alloc space (" << name << ")";
     return nullptr;
@@ -78,10 +78,10 @@
 
   // Everything is set so record in immutable structure and leave
   uint8_t* begin = mem_map->Begin();
-  // TODO: Fix RosAllocSpace to support valgrind. There is currently some issues with
+  // TODO: Fix RosAllocSpace to support Valgrind/ASan. There is currently some issues with
   // AllocationSize caused by redzones. b/12944686
-  if (running_on_valgrind) {
-    return new ValgrindMallocSpace<RosAllocSpace, kDefaultValgrindRedZoneBytes, false, true>(
+  if (running_on_memory_tool) {
+    return new MemoryToolMallocSpace<RosAllocSpace, kDefaultMemoryToolRedZoneBytes, false, true>(
         mem_map, initial_size, name, rosalloc, begin, end, begin + capacity, growth_limit,
         can_move_objects, starting_size, low_memory_mode);
   } else {
@@ -134,7 +134,7 @@
 allocator::RosAlloc* RosAllocSpace::CreateRosAlloc(void* begin, size_t morecore_start,
                                                    size_t initial_size,
                                                    size_t maximum_size, bool low_memory_mode,
-                                                   bool running_on_valgrind) {
+                                                   bool running_on_memory_tool) {
   // clear errno to allow PLOG on error
   errno = 0;
   // create rosalloc using our backing storage starting at begin and
@@ -145,7 +145,7 @@
       low_memory_mode ?
           art::gc::allocator::RosAlloc::kPageReleaseModeAll :
           art::gc::allocator::RosAlloc::kPageReleaseModeSizeAndEnd,
-      running_on_valgrind);
+      running_on_memory_tool);
   if (rosalloc != nullptr) {
     rosalloc->SetFootprintLimit(initial_size);
   } else {
@@ -180,8 +180,8 @@
                                            void* allocator, uint8_t* begin, uint8_t* end,
                                            uint8_t* limit, size_t growth_limit,
                                            bool can_move_objects) {
-  if (Runtime::Current()->RunningOnValgrind()) {
-    return new ValgrindMallocSpace<RosAllocSpace, kDefaultValgrindRedZoneBytes, false, true>(
+  if (Runtime::Current()->IsRunningOnMemoryTool()) {
+    return new MemoryToolMallocSpace<RosAllocSpace, kDefaultMemoryToolRedZoneBytes, false, true>(
         mem_map, initial_size_, name, reinterpret_cast<allocator::RosAlloc*>(allocator), begin, end,
         limit, growth_limit, can_move_objects, starting_size_, low_memory_mode_);
   } else {
@@ -370,7 +370,7 @@
   delete rosalloc_;
   rosalloc_ = CreateRosAlloc(mem_map_->Begin(), starting_size_, initial_size_,
                              NonGrowthLimitCapacity(), low_memory_mode_,
-                             Runtime::Current()->RunningOnValgrind());
+                             Runtime::Current()->IsRunningOnMemoryTool());
   SetFootprintLimit(footprint_limit);
 }
 
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index 36268f7..9dc6f31 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -31,7 +31,7 @@
 namespace space {
 
 // An alloc space implemented using a runs-of-slots memory allocator. Not final as may be
-// overridden by a ValgrindMallocSpace.
+// overridden by a MemoryToolMallocSpace.
 class RosAllocSpace : public MallocSpace {
  public:
   // Create a RosAllocSpace with the requested sizes. The requested
@@ -95,7 +95,7 @@
   ALWAYS_INLINE size_t MaxBytesBulkAllocatedForNonvirtual(size_t num_bytes);
 
   // TODO: NO_THREAD_SAFETY_ANALYSIS because SizeOf() requires that mutator_lock is held.
-  template<bool kMaybeRunningOnValgrind>
+  template<bool kMaybeIsRunningOnMemoryTool>
   size_t AllocationSizeNonvirtual(mirror::Object* obj, size_t* usable_size)
       NO_THREAD_SAFETY_ANALYSIS;
 
@@ -158,11 +158,11 @@
   void* CreateAllocator(void* base, size_t morecore_start, size_t initial_size,
                         size_t maximum_size, bool low_memory_mode) OVERRIDE {
     return CreateRosAlloc(base, morecore_start, initial_size, maximum_size, low_memory_mode,
-                          RUNNING_ON_VALGRIND != 0);
+                          RUNNING_ON_MEMORY_TOOL != 0);
   }
   static allocator::RosAlloc* CreateRosAlloc(void* base, size_t morecore_start, size_t initial_size,
                                              size_t maximum_size, bool low_memory_mode,
-                                             bool running_on_valgrind);
+                                             bool running_on_memory_tool);
 
   void InspectAllRosAlloc(void (*callback)(void *start, void *end, size_t num_bytes, void* callback_arg),
                           void* arg, bool do_null_callback_at_end)
diff --git a/runtime/indenter.h b/runtime/indenter.h
index 38b398d..78b18f6 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -19,10 +19,13 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include <ostream>
 #include <streambuf>
 
-const char kIndentChar =' ';
-const size_t kIndentBy1Count = 2;
+namespace art {
+
+constexpr char kIndentChar =' ';
+constexpr size_t kIndentBy1Count = 2;
 
 class Indenter : public std::streambuf {
  public:
@@ -99,9 +102,60 @@
   const char text_[8];
 
   // Number of times text is output.
-  const size_t count_;
+  size_t count_;
+
+  friend class VariableIndentationOutputStream;
 
   DISALLOW_COPY_AND_ASSIGN(Indenter);
 };
 
+class VariableIndentationOutputStream {
+ public:
+  explicit VariableIndentationOutputStream(std::ostream* os, char text = kIndentChar)
+      : indenter_(os->rdbuf(), text, 0u),
+        indented_os_(&indenter_) {
+  }
+
+  std::ostream& Stream() {
+    return indented_os_;
+  }
+
+  void IncreaseIndentation(size_t adjustment) {
+    indenter_.count_ += adjustment;
+  }
+
+  void DecreaseIndentation(size_t adjustment) {
+    DCHECK_GE(indenter_.count_, adjustment);
+    indenter_.count_ -= adjustment;
+  }
+
+ private:
+  Indenter indenter_;
+  std::ostream indented_os_;
+
+  DISALLOW_COPY_AND_ASSIGN(VariableIndentationOutputStream);
+};
+
+class ScopedIndentation {
+ public:
+  explicit ScopedIndentation(VariableIndentationOutputStream* vios,
+                             size_t adjustment = kIndentBy1Count)
+      : vios_(vios),
+        adjustment_(adjustment) {
+    vios_->IncreaseIndentation(adjustment_);
+  }
+
+  ~ScopedIndentation() {
+    vios_->DecreaseIndentation(adjustment_);
+  }
+
+ private:
+  VariableIndentationOutputStream* const vios_;
+  const size_t adjustment_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIndentation);
+};
+
+}  // namespace art
+
 #endif  // ART_RUNTIME_INDENTER_H_
diff --git a/runtime/indenter_test.cc b/runtime/indenter_test.cc
index 1919e3d..1a26d7b 100644
--- a/runtime/indenter_test.cc
+++ b/runtime/indenter_test.cc
@@ -17,6 +17,8 @@
 #include "gtest/gtest.h"
 #include "indenter.h"
 
+namespace art {
+
 TEST(IndenterTest, MultiLineTest) {
   std::ostringstream output;
   Indenter indent_filter(output.rdbuf(), '\t', 2);
@@ -33,3 +35,5 @@
   input << "\n";
   EXPECT_EQ(output.str(), "\t\thello\n\t\thello again\n");
 }
+
+}  // namespace art
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d37ddcb..abe9dc2 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -99,19 +99,6 @@
     }
   }
   method->SetEntryPointFromQuickCompiledCode(quick_code);
-  if (!method->IsResolutionMethod()) {
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (class_linker->IsQuickToInterpreterBridge(quick_code) ||
-        (class_linker->IsQuickResolutionStub(quick_code) &&
-         Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
-         !method->IsNative() && !method->IsProxyMethod())) {
-      DCHECK(!method->IsNative()) << PrettyMethod(method);
-      DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
-      method->SetEntryPointFromInterpreter(art::artInterpreterToInterpreterBridge);
-    } else {
-      method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
-    }
-  }
 }
 
 void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 2a96278..6ea047f 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -19,6 +19,7 @@
 #include <memory>
 
 #include "gc_root-inl.h"
+#include "gc/collector/garbage_collector.h"
 #include "gc/space/image_space.h"
 #include "mirror/dex_cache.h"
 #include "mirror/object_array-inl.h"
@@ -231,13 +232,21 @@
   CHECK(!allow_new_interns_);
 }
 
+void InternTable::BroadcastForNewInterns() {
+  CHECK(kUseReadBarrier);
+  Thread* self = Thread::Current();
+  MutexLock mu(self, *Locks::intern_table_lock_);
+  new_intern_condition_.Broadcast(self);
+}
+
 mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) {
   if (s == nullptr) {
     return nullptr;
   }
   Thread* self = Thread::Current();
   MutexLock mu(self, *Locks::intern_table_lock_);
-  while (UNLIKELY(!allow_new_interns_)) {
+  while (UNLIKELY((!kUseReadBarrier && !allow_new_interns_) ||
+                  (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
     new_intern_condition_.WaitHoldingLocks(self);
   }
   // Check the strong table for a match.
@@ -288,9 +297,9 @@
   return LookupWeak(s) == s;
 }
 
-void InternTable::SweepInternTableWeaks(IsMarkedCallback* callback, void* arg) {
+void InternTable::SweepInternTableWeaks(IsMarkedVisitor* visitor) {
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
-  weak_interns_.SweepWeaks(callback, arg);
+  weak_interns_.SweepWeaks(visitor);
 }
 
 void InternTable::AddImageInternTable(gc::space::ImageSpace* image_space) {
@@ -393,16 +402,16 @@
   }
 }
 
-void InternTable::Table::SweepWeaks(IsMarkedCallback* callback, void* arg) {
-  SweepWeaks(&pre_zygote_table_, callback, arg);
-  SweepWeaks(&post_zygote_table_, callback, arg);
+void InternTable::Table::SweepWeaks(IsMarkedVisitor* visitor) {
+  SweepWeaks(&pre_zygote_table_, visitor);
+  SweepWeaks(&post_zygote_table_, visitor);
 }
 
-void InternTable::Table::SweepWeaks(UnorderedSet* set, IsMarkedCallback* callback, void* arg) {
+void InternTable::Table::SweepWeaks(UnorderedSet* set, IsMarkedVisitor* visitor) {
   for (auto it = set->begin(), end = set->end(); it != end;) {
     // This does not need a read barrier because this is called by GC.
     mirror::Object* object = it->Read<kWithoutReadBarrier>();
-    mirror::Object* new_object = callback(object, arg);
+    mirror::Object* new_object = visitor->IsMarked(object);
     if (new_object == nullptr) {
       it = set->Erase(it);
     } else {
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 97ce73c..67a8b34 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -68,7 +68,7 @@
   // Interns a potentially new string in the 'weak' table. (See above.)
   mirror::String* InternWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SweepInternTableWeaks(IsMarkedCallback* callback, void* arg)
+  void SweepInternTableWeaks(IsMarkedVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool ContainsWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -88,6 +88,7 @@
   void DisallowNewInterns() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AllowNewInterns() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void EnsureNewInternsDisallowed() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void BroadcastForNewInterns() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Adds all of the resolved image strings from the image space into the intern table. The
   // advantage of doing this is preventing expensive DexFile::FindStringId calls.
@@ -142,7 +143,7 @@
     void VisitRoots(RootVisitor* visitor)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
-    void SweepWeaks(IsMarkedCallback* callback, void* arg)
+    void SweepWeaks(IsMarkedVisitor* visitor)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
     void SwapPostZygoteWithPreZygote() EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
@@ -162,7 +163,7 @@
     typedef HashSet<GcRoot<mirror::String>, GcRootEmptyFn, StringHashEquals, StringHashEquals,
         TrackingAllocator<GcRoot<mirror::String>, kAllocatorTagInternTable>> UnorderedSet;
 
-    void SweepWeaks(UnorderedSet* set, IsMarkedCallback* callback, void* arg)
+    void SweepWeaks(UnorderedSet* set, IsMarkedVisitor* visitor)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
         EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
 
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 194d0af..c987180 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -60,9 +60,9 @@
   EXPECT_EQ(2U, t.Size());
 }
 
-class TestPredicate {
+class TestPredicate : public IsMarkedVisitor {
  public:
-  bool IsMarked(const mirror::Object* s) const {
+  mirror::Object* IsMarked(mirror::Object* s) OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     bool erased = false;
     for (auto it = expected_.begin(), end = expected_.end(); it != end; ++it) {
       if (*it == s) {
@@ -72,7 +72,7 @@
       }
     }
     EXPECT_TRUE(erased);
-    return false;
+    return nullptr;
   }
 
   void Expect(const mirror::String* s) {
@@ -87,13 +87,6 @@
   mutable std::vector<const mirror::String*> expected_;
 };
 
-mirror::Object* IsMarkedSweepingCallback(mirror::Object* object, void* arg) {
-  if (reinterpret_cast<TestPredicate*>(arg)->IsMarked(object)) {
-    return object;
-  }
-  return nullptr;
-}
-
 TEST_F(InternTableTest, SweepInternTableWeaks) {
   ScopedObjectAccess soa(Thread::Current());
   InternTable t;
@@ -115,7 +108,7 @@
   p.Expect(s1.Get());
   {
     ReaderMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_);
-    t.SweepInternTableWeaks(IsMarkedSweepingCallback, &p);
+    t.SweepInternTableWeaks(&p);
   }
 
   EXPECT_EQ(2U, t.Size());
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index fa103b1..0980ea1 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -19,6 +19,7 @@
 #include <cmath>
 
 #include "debugger.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "mirror/array-inl.h"
 #include "unstarted_runtime.h"
 #include "verifier/method_verifier.h"
@@ -490,6 +491,23 @@
                                 uint32_t arg[Instruction::kMaxVarArgRegs],
                                 uint32_t vregC) ALWAYS_INLINE;
 
+SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+static inline bool NeedsInterpreter(Thread* self, ShadowFrame* new_shadow_frame) ALWAYS_INLINE;
+
+static inline bool NeedsInterpreter(Thread* self, ShadowFrame* new_shadow_frame) {
+  ArtMethod* target = new_shadow_frame->GetMethod();
+  if (UNLIKELY(target->IsNative() || target->IsProxyMethod())) {
+    return false;
+  }
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  return runtime->GetInstrumentation()->IsForcedInterpretOnly() ||
+        // Doing this check avoids doing compiled/interpreter transitions.
+        class_linker->IsQuickToInterpreterBridge(target->GetEntryPointFromQuickCompiledCode()) ||
+        // Force the use of interpreter when it is required by the debugger.
+        Dbg::IsForcedInterpreterNeededForCalling(self, target);
+}
+
 template<bool is_range, bool do_assignability_check>
 static inline bool DoCallCommon(ArtMethod* called_method,
                                 Thread* self,
@@ -660,28 +678,11 @@
 
   // Do the call now.
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    if (kIsDebugBuild && new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter() == nullptr) {
-      LOG(FATAL) << "Attempt to invoke non-executable method: "
-          << PrettyMethod(new_shadow_frame->GetMethod());
-      UNREACHABLE();
-    }
-    if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
-        !new_shadow_frame->GetMethod()->IsNative() &&
-        !new_shadow_frame->GetMethod()->IsProxyMethod() &&
-        new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter()
-            == artInterpreterToCompiledCodeBridge) {
-      LOG(FATAL) << "Attempt to call compiled code when -Xint: "
-          << PrettyMethod(new_shadow_frame->GetMethod());
-      UNREACHABLE();
-    }
-    // Force the use of interpreter when it is required by the debugger.
-    EntryPointFromInterpreter* entry;
-    if (UNLIKELY(Dbg::IsForcedInterpreterNeededForCalling(self, new_shadow_frame->GetMethod()))) {
-      entry = &art::artInterpreterToInterpreterBridge;
+    if (NeedsInterpreter(self, new_shadow_frame)) {
+      artInterpreterToInterpreterBridge(self, code_item, new_shadow_frame, result);
     } else {
-      entry = new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter();
+      artInterpreterToCompiledCodeBridge(self, code_item, new_shadow_frame, result);
     }
-    entry(self, code_item, new_shadow_frame, result);
   } else {
     UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result, first_dest_reg);
   }
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index a12a58d..776b6a3 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -446,10 +446,10 @@
     return 3;
   }
   const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-  DCHECK(IsAligned<4>(keys));
+  DCHECK_ALIGNED(keys, 4);
   int32_t first_key = keys[0];
   const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
-  DCHECK(IsAligned<4>(targets));
+  DCHECK_ALIGNED(targets, 4);
   int32_t index = test_val - first_key;
   if (index >= 0 && index < size) {
     return targets[index];
@@ -474,9 +474,9 @@
     return 3;
   }
   const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
-  DCHECK(IsAligned<4>(keys));
+  DCHECK_ALIGNED(keys, 4);
   const int32_t* entries = keys + size;
-  DCHECK(IsAligned<4>(entries));
+  DCHECK_ALIGNED(entries, 4);
   int lo = 0;
   int hi = size - 1;
   while (lo <= hi) {
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index f1deacf..36e3aa3 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -473,7 +473,8 @@
     return nullptr;
   }
   MutexLock mu(self, weak_globals_lock_);
-  while (UNLIKELY(!allow_new_weak_globals_)) {
+  while (UNLIKELY((!kUseReadBarrier && !allow_new_weak_globals_) ||
+                  (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
     weak_globals_add_condition_.WaitHoldingLocks(self);
   }
   IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj);
@@ -559,6 +560,13 @@
   CHECK(!allow_new_weak_globals_);
 }
 
+void JavaVMExt::BroadcastForNewWeakGlobals() {
+  CHECK(kUseReadBarrier);
+  Thread* self = Thread::Current();
+  MutexLock mu(self, weak_globals_lock_);
+  weak_globals_add_condition_.Broadcast(self);
+}
+
 mirror::Object* JavaVMExt::DecodeGlobal(Thread* self, IndirectRef ref) {
   return globals_.SynchronizedGet(self, &globals_lock_, ref);
 }
@@ -570,7 +578,8 @@
 
 mirror::Object* JavaVMExt::DecodeWeakGlobal(Thread* self, IndirectRef ref) {
   MutexLock mu(self, weak_globals_lock_);
-  while (UNLIKELY(!allow_new_weak_globals_)) {
+  while (UNLIKELY((!kUseReadBarrier && !allow_new_weak_globals_) ||
+                  (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
     weak_globals_add_condition_.WaitHoldingLocks(self);
   }
   return weak_globals_.Get(ref);
@@ -757,7 +766,7 @@
   return native_method;
 }
 
-void JavaVMExt::SweepJniWeakGlobals(IsMarkedCallback* callback, void* arg) {
+void JavaVMExt::SweepJniWeakGlobals(IsMarkedVisitor* visitor) {
   MutexLock mu(Thread::Current(), weak_globals_lock_);
   Runtime* const runtime = Runtime::Current();
   for (auto* entry : weak_globals_) {
@@ -765,7 +774,7 @@
     if (!entry->IsNull()) {
       // Since this is called by the GC, we don't need a read barrier.
       mirror::Object* obj = entry->Read<kWithoutReadBarrier>();
-      mirror::Object* new_obj = callback(obj, arg);
+      mirror::Object* new_obj = visitor->IsMarked(obj);
       if (new_obj == nullptr) {
         new_obj = runtime->GetClearedJniWeakGlobal();
       }
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index 4fdf45a..97fbbc5 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -108,6 +108,7 @@
   void DisallowNewWeakGlobals() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AllowNewWeakGlobals() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void EnsureNewWeakGlobalsDisallowed() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void BroadcastForNewWeakGlobals() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   jobject AddGlobalRef(Thread* self, mirror::Object* obj)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -119,7 +120,7 @@
 
   void DeleteWeakGlobalRef(Thread* self, jweak obj);
 
-  void SweepJniWeakGlobals(IsMarkedCallback* callback, void* arg)
+  void SweepJniWeakGlobals(IsMarkedVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::Object* DecodeGlobal(Thread* self, IndirectRef ref)
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index bc9545b..fda97db 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -132,11 +132,7 @@
     VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to breakpoint";
     return false;
   }
-  const bool result = jit_compile_method_(jit_compiler_handle_, method, self);
-  if (result) {
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
-  }
-  return result;
+  return jit_compile_method_(jit_compiler_handle_, method, self);
 }
 
 void Jit::CreateThreadPool() {
diff --git a/runtime/lock_word.h b/runtime/lock_word.h
index a290575..245f8b8 100644
--- a/runtime/lock_word.h
+++ b/runtime/lock_word.h
@@ -118,7 +118,7 @@
   }
 
   static LockWord FromForwardingAddress(size_t target) {
-    DCHECK(IsAligned < 1 << kStateSize>(target));
+    DCHECK_ALIGNED(target, (1 << kStateSize));
     return LockWord((target >> kStateSize) | (kStateForwardingAddress << kStateShift));
   }
 
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 7e640c6..8df8f96 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -16,6 +16,7 @@
 
 #include "mem_map.h"
 
+#include "base/memory_tool.h"
 #include <backtrace/BacktraceMap.h>
 #include <inttypes.h>
 
@@ -481,6 +482,12 @@
   uint8_t* page_aligned_expected =
       (expected_ptr == nullptr) ? nullptr : (expected_ptr - page_offset);
 
+  size_t redzone_size = 0;
+  if (RUNNING_ON_MEMORY_TOOL && kMemoryToolAddsRedzones && expected_ptr == nullptr) {
+    redzone_size = kPageSize;
+    page_aligned_byte_count += redzone_size;
+  }
+
   uint8_t* actual = reinterpret_cast<uint8_t*>(mmap(page_aligned_expected,
                                               page_aligned_byte_count,
                                               prot,
@@ -503,15 +510,35 @@
   if (!CheckMapRequest(expected_ptr, actual, page_aligned_byte_count, error_msg)) {
     return nullptr;
   }
+  if (redzone_size != 0) {
+    const uint8_t *real_start = actual + page_offset;
+    const uint8_t *real_end = actual + page_offset + byte_count;
+    const uint8_t *mapping_end = actual + page_aligned_byte_count;
+
+    MEMORY_TOOL_MAKE_NOACCESS(actual, real_start - actual);
+    MEMORY_TOOL_MAKE_NOACCESS(real_end, mapping_end - real_end);
+    page_aligned_byte_count -= redzone_size;
+  }
+
   return new MemMap(filename, actual + page_offset, byte_count, actual, page_aligned_byte_count,
-                    prot, reuse);
+                    prot, reuse, redzone_size);
 }
 
 MemMap::~MemMap() {
   if (base_begin_ == nullptr && base_size_ == 0) {
     return;
   }
+
+  // Unlike Valgrind, AddressSanitizer requires that all manually poisoned memory is unpoisoned
+  // before it is returned to the system.
+  if (redzone_size_ != 0) {
+    MEMORY_TOOL_MAKE_UNDEFINED(
+        reinterpret_cast<char*>(base_begin_) + base_size_ - redzone_size_,
+        redzone_size_);
+  }
+
   if (!reuse_) {
+    MEMORY_TOOL_MAKE_UNDEFINED(base_begin_, base_size_);
     int result = munmap(base_begin_, base_size_);
     if (result == -1) {
       PLOG(FATAL) << "munmap failed";
@@ -534,9 +561,9 @@
 }
 
 MemMap::MemMap(const std::string& name, uint8_t* begin, size_t size, void* base_begin,
-               size_t base_size, int prot, bool reuse)
+               size_t base_size, int prot, bool reuse, size_t redzone_size)
     : name_(name), begin_(begin), size_(size), base_begin_(base_begin), base_size_(base_size),
-      prot_(prot), reuse_(reuse) {
+      prot_(prot), reuse_(reuse), redzone_size_(redzone_size) {
   if (size_ == 0) {
     CHECK(begin_ == nullptr);
     CHECK(base_begin_ == nullptr);
@@ -558,10 +585,10 @@
   DCHECK_GE(new_end, Begin());
   DCHECK_LE(new_end, End());
   DCHECK_LE(begin_ + size_, reinterpret_cast<uint8_t*>(base_begin_) + base_size_);
-  DCHECK(IsAligned<kPageSize>(begin_));
-  DCHECK(IsAligned<kPageSize>(base_begin_));
-  DCHECK(IsAligned<kPageSize>(reinterpret_cast<uint8_t*>(base_begin_) + base_size_));
-  DCHECK(IsAligned<kPageSize>(new_end));
+  DCHECK_ALIGNED(begin_, kPageSize);
+  DCHECK_ALIGNED(base_begin_, kPageSize);
+  DCHECK_ALIGNED(reinterpret_cast<uint8_t*>(base_begin_) + base_size_, kPageSize);
+  DCHECK_ALIGNED(new_end, kPageSize);
   uint8_t* old_end = begin_ + size_;
   uint8_t* old_base_end = reinterpret_cast<uint8_t*>(base_begin_) + base_size_;
   uint8_t* new_base_end = new_end;
@@ -576,7 +603,7 @@
   uint8_t* tail_base_begin = new_base_end;
   size_t tail_base_size = old_base_end - new_base_end;
   DCHECK_EQ(tail_base_begin + tail_base_size, old_base_end);
-  DCHECK(IsAligned<kPageSize>(tail_base_size));
+  DCHECK_ALIGNED(tail_base_size, kPageSize);
 
 #ifdef USE_ASHMEM
   // android_os_Debug.cpp read_mapinfo assumes all ashmem regions associated with the VM are
@@ -595,6 +622,8 @@
   int flags = MAP_PRIVATE | MAP_ANONYMOUS;
 #endif
 
+
+  MEMORY_TOOL_MAKE_UNDEFINED(tail_base_begin, tail_base_size);
   // Unmap/map the tail region.
   int result = munmap(tail_base_begin, tail_base_size);
   if (result == -1) {
@@ -697,7 +726,7 @@
     size_t num_gaps = 0;
     size_t num = 1u;
     size_t size = map->BaseSize();
-    CHECK(IsAligned<kPageSize>(size));
+    CHECK_ALIGNED(size, kPageSize);
     void* end = map->BaseEnd();
     while (it != maps_end &&
         it->second->GetProtect() == map->GetProtect() &&
@@ -711,12 +740,12 @@
         }
         size_t gap =
             reinterpret_cast<uintptr_t>(it->second->BaseBegin()) - reinterpret_cast<uintptr_t>(end);
-        CHECK(IsAligned<kPageSize>(gap));
+        CHECK_ALIGNED(gap, kPageSize);
         os << "~0x" << std::hex << (gap / kPageSize) << "P";
         num = 0u;
         size = 0u;
       }
-      CHECK(IsAligned<kPageSize>(it->second->BaseSize()));
+      CHECK_ALIGNED(it->second->BaseSize(), kPageSize);
       ++num;
       size += it->second->BaseSize();
       end = it->second->BaseEnd();
@@ -778,6 +807,10 @@
   CHECK_ALIGNED(new_size, kPageSize);
   CHECK_EQ(base_size_, size_) << "Unsupported";
   CHECK_LE(new_size, base_size_);
+  MEMORY_TOOL_MAKE_UNDEFINED(
+      reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) +
+                              new_size),
+      base_size_ - new_size);
   CHECK_EQ(munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) + new_size),
                   base_size_ - new_size), 0) << new_size << " " << base_size_;
   base_size_ = new_size;
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 14387ee..01e29c9 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -153,7 +153,7 @@
 
  private:
   MemMap(const std::string& name, uint8_t* begin, size_t size, void* base_begin, size_t base_size,
-         int prot, bool reuse) LOCKS_EXCLUDED(Locks::mem_maps_lock_);
+         int prot, bool reuse, size_t redzone_size = 0) LOCKS_EXCLUDED(Locks::mem_maps_lock_);
 
   static void DumpMapsLocked(std::ostream& os, bool terse)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mem_maps_lock_);
@@ -175,6 +175,8 @@
   // unmapping.
   const bool reuse_;
 
+  const size_t redzone_size_;
+
 #if USE_ART_LOW_4G_ALLOCATOR
   static uintptr_t next_mem_pos_;   // Next memory location to check for low_4g extent.
 #endif
diff --git a/runtime/mem_map_test.cc b/runtime/mem_map_test.cc
index f635b5d..13bf5b7 100644
--- a/runtime/mem_map_test.cc
+++ b/runtime/mem_map_test.cc
@@ -18,7 +18,7 @@
 
 #include <memory>
 
-#include <valgrind.h>
+#include "base/memory_tool.h"
 
 #include "gtest/gtest.h"
 
@@ -216,7 +216,7 @@
 TEST_F(MemMapTest, MapAnonymousExactAddr32bitHighAddr) {
   CommonInit();
   // This test may not work under valgrind.
-  if (RUNNING_ON_VALGRIND == 0) {
+  if (RUNNING_ON_MEMORY_TOOL == 0) {
     uintptr_t start_addr = ART_BASE_ADDRESS + 0x1000000;
     std::string error_msg;
     std::unique_ptr<MemMap> map(MemMap::MapAnonymous("MapAnonymousExactAddr32bitHighAddr",
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 7f89b1d..fc27315 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -832,11 +832,22 @@
       f->VisitRoots(visitor);
     }
   }
-  for (auto& m : GetDirectMethods(pointer_size)) {
-    m.VisitRoots(visitor);
+  // We may see GetDirectMethodsPtr() == null with NumDirectMethods() != 0 if the root marking
+  // thread reads a null DirectMethodsBegin() but a non null DirectMethodsBegin() due to a race
+  // SetDirectMethodsPtr from class linking. Same for virtual methods.
+  // In this case, it is safe to avoid marking the roots since we must be either the CC or CMS. If
+  // we are CMS then the roots are already marked through other sources, otherwise the roots are
+  // already marked due to the to-space invariant.
+  // Unchecked versions since we may visit roots of classes that aren't yet loaded.
+  if (GetDirectMethodsPtrUnchecked() != nullptr) {
+    for (auto& m : GetDirectMethods(pointer_size)) {
+      m.VisitRoots(visitor);
+    }
   }
-  for (auto& m : GetVirtualMethods(pointer_size)) {
-    m.VisitRoots(visitor);
+  if (GetVirtualMethodsPtrUnchecked() != nullptr) {
+    for (auto& m : GetVirtualMethods(pointer_size)) {
+      m.VisitRoots(visitor);
+    }
   }
 }
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index f0b7bfd..5bd6583 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -471,7 +471,8 @@
 ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature,
                                             size_t pointer_size) {
   for (auto& method : GetVirtualMethods(pointer_size)) {
-    if (name == method.GetName() && method.GetSignature() == signature) {
+    ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
+    if (name == np_method->GetName() && np_method->GetSignature() == signature) {
       return &method;
     }
   }
@@ -481,7 +482,8 @@
 ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature,
                                             size_t pointer_size) {
   for (auto& method : GetVirtualMethods(pointer_size)) {
-    if (name == method.GetName() && signature == method.GetSignature()) {
+    ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
+    if (name == np_method->GetName() && signature == np_method->GetSignature()) {
       return &method;
     }
   }
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 4be25d6..fd9c1b1 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1146,16 +1146,24 @@
   CHECK(!allow_new_monitors_);
 }
 
+void MonitorList::BroadcastForNewMonitors() {
+  CHECK(kUseReadBarrier);
+  Thread* self = Thread::Current();
+  MutexLock mu(self, monitor_list_lock_);
+  monitor_add_condition_.Broadcast(self);
+}
+
 void MonitorList::Add(Monitor* m) {
   Thread* self = Thread::Current();
   MutexLock mu(self, monitor_list_lock_);
-  while (UNLIKELY(!allow_new_monitors_)) {
+  while (UNLIKELY((!kUseReadBarrier && !allow_new_monitors_) ||
+                  (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
     monitor_add_condition_.WaitHoldingLocks(self);
   }
   list_.push_front(m);
 }
 
-void MonitorList::SweepMonitorList(IsMarkedCallback* callback, void* arg) {
+void MonitorList::SweepMonitorList(IsMarkedVisitor* visitor) {
   Thread* self = Thread::Current();
   MutexLock mu(self, monitor_list_lock_);
   for (auto it = list_.begin(); it != list_.end(); ) {
@@ -1163,7 +1171,7 @@
     // Disable the read barrier in GetObject() as this is called by GC.
     mirror::Object* obj = m->GetObject<kWithoutReadBarrier>();
     // The object of a monitor can be null if we have deflated it.
-    mirror::Object* new_obj = obj != nullptr ? callback(obj, arg) : nullptr;
+    mirror::Object* new_obj = obj != nullptr ? visitor->IsMarked(obj) : nullptr;
     if (new_obj == nullptr) {
       VLOG(monitor) << "freeing monitor " << m << " belonging to unmarked object "
                     << obj;
@@ -1176,29 +1184,30 @@
   }
 }
 
-struct MonitorDeflateArgs {
-  MonitorDeflateArgs() : self(Thread::Current()), deflate_count(0) {}
-  Thread* const self;
-  size_t deflate_count;
+class MonitorDeflateVisitor : public IsMarkedVisitor {
+ public:
+  MonitorDeflateVisitor() : self_(Thread::Current()), deflate_count_(0) {}
+
+  virtual mirror::Object* IsMarked(mirror::Object* object) OVERRIDE
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (Monitor::Deflate(self_, object)) {
+      DCHECK_NE(object->GetLockWord(true).GetState(), LockWord::kFatLocked);
+      ++deflate_count_;
+      // If we deflated, return null so that the monitor gets removed from the array.
+      return nullptr;
+    }
+    return object;  // Monitor was not deflated.
+  }
+
+  Thread* const self_;
+  size_t deflate_count_;
 };
 
-static mirror::Object* MonitorDeflateCallback(mirror::Object* object, void* arg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  MonitorDeflateArgs* args = reinterpret_cast<MonitorDeflateArgs*>(arg);
-  if (Monitor::Deflate(args->self, object)) {
-    DCHECK_NE(object->GetLockWord(true).GetState(), LockWord::kFatLocked);
-    ++args->deflate_count;
-    // If we deflated, return null so that the monitor gets removed from the array.
-    return nullptr;
-  }
-  return object;  // Monitor was not deflated.
-}
-
 size_t MonitorList::DeflateMonitors() {
-  MonitorDeflateArgs args;
-  Locks::mutator_lock_->AssertExclusiveHeld(args.self);
-  SweepMonitorList(MonitorDeflateCallback, &args);
-  return args.deflate_count;
+  MonitorDeflateVisitor visitor;
+  Locks::mutator_lock_->AssertExclusiveHeld(visitor.self_);
+  SweepMonitorList(&visitor);
+  return visitor.deflate_count_;
 }
 
 MonitorInfo::MonitorInfo(mirror::Object* obj) : owner_(nullptr), entry_count_(0) {
diff --git a/runtime/monitor.h b/runtime/monitor.h
index 8f3a91d..09a6cb6 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -287,11 +287,12 @@
 
   void Add(Monitor* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SweepMonitorList(IsMarkedCallback* callback, void* arg)
+  void SweepMonitorList(IsMarkedVisitor* visitor)
       LOCKS_EXCLUDED(monitor_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DisallowNewMonitors() LOCKS_EXCLUDED(monitor_list_lock_);
   void AllowNewMonitors() LOCKS_EXCLUDED(monitor_list_lock_);
   void EnsureNewMonitorsDisallowed() LOCKS_EXCLUDED(monitor_list_lock_);
+  void BroadcastForNewMonitors() LOCKS_EXCLUDED(monitor_list_lock_);
   // Returns how many monitors were deflated.
   size_t DeflateMonitors() LOCKS_EXCLUDED(monitor_list_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 1078492..8febb62 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -257,21 +257,45 @@
 static jlong VMDebug_countInstancesOfClass(JNIEnv* env, jclass, jclass javaClass,
                                            jboolean countAssignable) {
   ScopedObjectAccess soa(env);
-  gc::Heap* heap = Runtime::Current()->GetHeap();
-  // We only want reachable instances, so do a GC. Heap::VisitObjects visits all of the heap
-  // objects in the all spaces and the allocation stack.
-  heap->CollectGarbage(false);
+  gc::Heap* const heap = Runtime::Current()->GetHeap();
+  // Caller's responsibility to do GC if desired.
   mirror::Class* c = soa.Decode<mirror::Class*>(javaClass);
   if (c == nullptr) {
     return 0;
   }
-  std::vector<mirror::Class*> classes;
-  classes.push_back(c);
+  std::vector<mirror::Class*> classes {c};
   uint64_t count = 0;
   heap->CountInstances(classes, countAssignable, &count);
   return count;
 }
 
+static jlongArray VMDebug_countInstancesOfClasses(JNIEnv* env, jclass, jobjectArray javaClasses,
+                                                  jboolean countAssignable) {
+  ScopedObjectAccess soa(env);
+  gc::Heap* const heap = Runtime::Current()->GetHeap();
+  // Caller's responsibility to do GC if desired.
+  auto* decoded_classes = soa.Decode<mirror::ObjectArray<mirror::Class>*>(javaClasses);
+  if (decoded_classes == nullptr) {
+    return nullptr;
+  }
+  std::vector<mirror::Class*> classes;
+  for (size_t i = 0, count = decoded_classes->GetLength(); i < count; ++i) {
+    classes.push_back(decoded_classes->Get(i));
+  }
+  std::vector<uint64_t> counts(classes.size(), 0u);
+  // Heap::CountInstances can handle null and will put 0 for these classes.
+  heap->CountInstances(classes, countAssignable, &counts[0]);
+  auto* long_counts = mirror::LongArray::Alloc(soa.Self(), counts.size());
+  if (long_counts == nullptr) {
+    soa.Self()->AssertPendingOOMException();
+    return nullptr;
+  }
+  for (size_t i = 0; i < counts.size(); ++i) {
+    long_counts->Set(i, counts[i]);
+  }
+  return soa.AddLocalReference<jlongArray>(long_counts);
+}
+
 // We export the VM internal per-heap-space size/alloc/free metrics
 // for the zygote space, alloc space (application heap), and the large
 // object space for dumpsys meminfo. The other memory region data such
@@ -452,6 +476,7 @@
 
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"),
+  NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"),
   NATIVE_METHOD(VMDebug, crash, "()V"),
   NATIVE_METHOD(VMDebug, dumpHprofData, "(Ljava/lang/String;Ljava/io/FileDescriptor;)V"),
   NATIVE_METHOD(VMDebug, dumpHprofDataDdms, "()V"),
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 736b42b..97aae67 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -105,15 +105,21 @@
         dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count);
         return;
       case Primitive::kPrimInt:
-      case Primitive::kPrimFloat:
         DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
         dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count);
         return;
+      case Primitive::kPrimFloat:
+        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U);
+        dstArray->AsFloatArray()->Memmove(dstPos, srcArray->AsFloatArray(), srcPos, count);
+        return;
       case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
         DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
         dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count);
         return;
+      case Primitive::kPrimDouble:
+        DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U);
+        dstArray->AsDoubleArray()->Memmove(dstPos, srcArray->AsDoubleArray(), srcPos, count);
+        return;
       case Primitive::kPrimNot: {
         mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
         mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 1dd2aad..5725b6f 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -97,7 +97,7 @@
   image_file_location_oat_checksum_ = image_file_location_oat_checksum;
   UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_));
 
-  CHECK(IsAligned<kPageSize>(image_file_location_oat_data_begin));
+  CHECK_ALIGNED(image_file_location_oat_data_begin, kPageSize);
   image_file_location_oat_data_begin_ = image_file_location_oat_data_begin;
   UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_));
 
diff --git a/runtime/oat.h b/runtime/oat.h
index 000ae8e..3451d0f 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '6', '4', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '6', '6', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index 6b3b666..5df6525 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -22,7 +22,7 @@
 namespace art {
 
 inline const OatQuickMethodHeader* OatFile::OatMethod::GetOatQuickMethodHeader() const {
-  const void* code = ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  const void* code = ArtMethod::EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_));
   if (code == nullptr) {
     return nullptr;
   }
@@ -38,14 +38,6 @@
   return reinterpret_cast<const uint8_t*>(method_header) - begin_;
 }
 
-inline uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
-  const void* code = ArtMethod::EntryPointToCodePointer(GetQuickCode());
-  if (code == nullptr) {
-    return 0u;
-  }
-  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
-}
-
 inline uint32_t OatFile::OatMethod::GetQuickCodeSizeOffset() const {
   const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
   if (method_header == nullptr) {
@@ -78,8 +70,8 @@
   return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.FpSpillMask();
 }
 
-const uint8_t* OatFile::OatMethod::GetGcMap() const {
-  const void* code = ArtMethod::EntryPointToCodePointer(GetQuickCode());
+inline const uint8_t* OatFile::OatMethod::GetGcMap() const {
+  const void* code = ArtMethod::EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_));
   if (code == nullptr) {
     return nullptr;
   }
@@ -90,12 +82,12 @@
   return reinterpret_cast<const uint8_t*>(code) - offset;
 }
 
-uint32_t OatFile::OatMethod::GetGcMapOffset() const {
+inline uint32_t OatFile::OatMethod::GetGcMapOffset() const {
   const uint8_t* gc_map = GetGcMap();
   return static_cast<uint32_t>(gc_map != nullptr ? gc_map - begin_ : 0u);
 }
 
-uint32_t OatFile::OatMethod::GetGcMapOffsetOffset() const {
+inline uint32_t OatFile::OatMethod::GetGcMapOffsetOffset() const {
   const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
   if (method_header == nullptr) {
     return 0u;
@@ -130,7 +122,7 @@
 }
 
 inline const uint8_t* OatFile::OatMethod::GetMappingTable() const {
-  const void* code = ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  const void* code = ArtMethod::EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_));
   if (code == nullptr) {
     return nullptr;
   }
@@ -142,7 +134,7 @@
 }
 
 inline const uint8_t* OatFile::OatMethod::GetVmapTable() const {
-  const void* code = ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  const void* code = ArtMethod::EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_));
   if (code == nullptr) {
     return nullptr;
   }
@@ -153,6 +145,22 @@
   return reinterpret_cast<const uint8_t*>(code) - offset;
 }
 
+inline uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
+  const void* code = ArtMethod::EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_));
+  if (code == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
+}
+
+inline uint32_t OatFile::OatMethod::GetCodeOffset() const {
+  return (GetQuickCodeSize() == 0) ? 0 : code_offset_;
+}
+
+inline const void* OatFile::OatMethod::GetQuickCode() const {
+  return GetOatPointer<const void*>(GetCodeOffset());
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_OAT_FILE_INL_H_
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ad5741e..098fe61 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -41,6 +41,7 @@
 #include "mem_map.h"
 #include "mirror/class.h"
 #include "mirror/object-inl.h"
+#include "oat_file-inl.h"
 #include "os.h"
 #include "runtime.h"
 #include "utils.h"
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 1a782de..7c4ef8b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -100,13 +100,9 @@
    public:
     void LinkMethod(ArtMethod* method) const;
 
-    uint32_t GetCodeOffset() const {
-      return code_offset_;
-    }
+    uint32_t GetCodeOffset() const;
 
-    const void* GetQuickCode() const {
-      return GetOatPointer<const void*>(code_offset_);
-    }
+    const void* GetQuickCode() const;
 
     // Returns size of quick code.
     uint32_t GetQuickCodeSize() const;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index b28adf9..df0cf45 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -698,18 +698,13 @@
     return false;
   }
 
-  ClassLinker* linker = runtime->GetClassLinker();
-  CHECK(linker != nullptr) << "ClassLinker is not created yet";
-  const OatFile* primary_oat_file = linker->GetPrimaryOatFile();
-  const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable();
-
   std::vector<std::string> argv;
   argv.push_back(runtime->GetCompilerExecutable());
   argv.push_back("--runtime-arg");
   argv.push_back("-classpath");
   argv.push_back("--runtime-arg");
   argv.push_back(runtime->GetClassPathString());
-  if (debuggable) {
+  if (runtime->IsDebuggable()) {
     argv.push_back("--debuggable");
   }
   runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 8e99dbb..4d726ec 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -17,42 +17,34 @@
 #ifndef ART_RUNTIME_OBJECT_CALLBACKS_H_
 #define ART_RUNTIME_OBJECT_CALLBACKS_H_
 
-// For ostream.
-#include <ostream>
-// For uint32_t.
-#include <stdint.h>
-// For size_t.
-#include <stdlib.h>
-
 #include "base/macros.h"
 
 namespace art {
 namespace mirror {
-  class Class;
   class Object;
   template<class MirrorType> class HeapReference;
-  class Reference;
 }  // namespace mirror
-class StackVisitor;
 
 // A callback for visiting an object in the heap.
 typedef void (ObjectCallback)(mirror::Object* obj, void* arg);
-// A callback used for marking an object, returns the new address of the object if the object moved.
-typedef mirror::Object* (MarkObjectCallback)(mirror::Object* obj, void* arg) WARN_UNUSED;
 
-typedef void (MarkHeapReferenceCallback)(mirror::HeapReference<mirror::Object>* ref, void* arg);
-typedef void (DelayReferenceReferentCallback)(mirror::Class* klass, mirror::Reference* ref,
-    void* arg);
+class IsMarkedVisitor {
+ public:
+  virtual ~IsMarkedVisitor() {}
+  // Return null if an object is not marked, otherwise returns the new address of that object.
+  // May return the same address as the input if the object did not move.
+  virtual mirror::Object* IsMarked(mirror::Object* obj) = 0;
+};
 
-// A callback for testing if an object is marked, returns null if not marked, otherwise the new
-// address the object (if the object didn't move, returns the object input parameter).
-typedef mirror::Object* (IsMarkedCallback)(mirror::Object* object, void* arg) WARN_UNUSED;
-
-// Returns true if the object in the heap reference is marked, if it is marked and has moved the
-// callback updates the heap reference contain the new value.
-typedef bool (IsHeapReferenceMarkedCallback)(mirror::HeapReference<mirror::Object>* object,
-    void* arg) WARN_UNUSED;
-typedef void (ProcessMarkStackCallback)(void* arg);
+class MarkObjectVisitor {
+ public:
+  virtual ~MarkObjectVisitor() {}
+  // Mark an object and return the new address of an object.
+  // May return the same address as the input if the object did not move.
+  virtual mirror::Object* MarkObject(mirror::Object* obj) = 0;
+  // Mark an object and update the value stored in the heap reference if the object moved.
+  virtual void MarkHeapReference(mirror::HeapReference<mirror::Object>* obj) = 0;
+};
 
 }  // namespace art
 
diff --git a/runtime/os.h b/runtime/os.h
index 6248d5f..befe2e8 100644
--- a/runtime/os.h
+++ b/runtime/os.h
@@ -35,7 +35,8 @@
   // Open an existing file with read/write access.
   static File* OpenFileReadWrite(const char* name);
 
-  // Create an empty file with read/write access.
+  // Create an empty file with read/write access. This is a *new* file, that is, if the file
+  // already exists, it is *not* overwritten, but unlinked, and a new inode will be used.
   static File* CreateEmptyFile(const char* name);
 
   // Open a file with the specified open(2) flags.
diff --git a/runtime/os_linux.cc b/runtime/os_linux.cc
index 2282789..675699d 100644
--- a/runtime/os_linux.cc
+++ b/runtime/os_linux.cc
@@ -36,6 +36,10 @@
 }
 
 File* OS::CreateEmptyFile(const char* name) {
+  // In case the file exists, unlink it so we get a new file. This is necessary as the previous
+  // file may be in use and must not be changed.
+  unlink(name);
+
   return OpenFileWithFlags(name, O_RDWR | O_CREAT | O_TRUNC);
 }
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 5e84df5..d08af71 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -257,6 +257,8 @@
           .IntoKey(M::ZygoteMaxFailedBoots)
       .Define("-Xno-dex-file-fallback")
           .IntoKey(M::NoDexFileFallback)
+      .Define("-Xno-sig-chain")
+          .IntoKey(M::NoSigChain)
       .Define("--cpu-abilist=_")
           .WithType<std::string>()
           .IntoKey(M::CpuAbiList)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 96c15ea..3b0ca9e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -26,7 +26,7 @@
 #include <cutils/trace.h>
 #include <signal.h>
 #include <sys/syscall.h>
-#include <valgrind.h>
+#include "base/memory_tool.h"
 
 #include <cstdio>
 #include <cstdlib>
@@ -177,7 +177,7 @@
       exit_(nullptr),
       abort_(nullptr),
       stats_enabled_(false),
-      running_on_valgrind_(RUNNING_ON_VALGRIND > 0),
+      is_running_on_memory_tool_(RUNNING_ON_MEMORY_TOOL),
       profiler_started_(false),
       instrumentation_(),
       main_thread_group_(nullptr),
@@ -191,6 +191,7 @@
       implicit_null_checks_(false),
       implicit_so_checks_(false),
       implicit_suspend_checks_(false),
+      no_sig_chain_(false),
       is_native_bridge_loaded_(false),
       zygote_max_failed_boots_(0),
       experimental_lambdas_(false) {
@@ -402,11 +403,11 @@
   }
 }
 
-void Runtime::SweepSystemWeaks(IsMarkedCallback* visitor, void* arg) {
-  GetInternTable()->SweepInternTableWeaks(visitor, arg);
-  GetMonitorList()->SweepMonitorList(visitor, arg);
-  GetJavaVM()->SweepJniWeakGlobals(visitor, arg);
-  GetHeap()->SweepAllocationRecords(visitor, arg);
+void Runtime::SweepSystemWeaks(IsMarkedVisitor* visitor) {
+  GetInternTable()->SweepInternTableWeaks(visitor);
+  GetMonitorList()->SweepMonitorList(visitor);
+  GetJavaVM()->SweepJniWeakGlobals(visitor);
+  GetHeap()->SweepAllocationRecords(visitor);
 }
 
 bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
@@ -487,6 +488,8 @@
 bool Runtime::Start() {
   VLOG(startup) << "Runtime::Start entering";
 
+  CHECK(!no_sig_chain_) << "A started runtime should have sig chain enabled";
+
   // Restore main thread state to kNative as expected by native code.
   Thread* self = Thread::Current();
 
@@ -677,6 +680,11 @@
   return IsShuttingDownLocked();
 }
 
+bool Runtime::IsDebuggable() const {
+  const OatFile* oat_file = GetClassLinker()->GetPrimaryOatFile();
+  return oat_file != nullptr && oat_file->IsDebuggable();
+}
+
 void Runtime::StartDaemonThreads() {
   VLOG(startup) << "Runtime::StartDaemonThreads entering";
 
@@ -838,6 +846,8 @@
   verify_ = runtime_options.GetOrDefault(Opt::Verify);
   allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
 
+  no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
+
   Split(runtime_options.GetOrDefault(Opt::CpuAbiList), ',', &cpu_abilist_);
 
   if (runtime_options.GetOrDefault(Opt::Interpret)) {
@@ -924,42 +934,48 @@
     case kX86:
     case kArm64:
     case kX86_64:
+    case kMips:
+    case kMips64:
       implicit_null_checks_ = true;
       // Installing stack protection does not play well with valgrind.
-      implicit_so_checks_ = (RUNNING_ON_VALGRIND == 0);
+      implicit_so_checks_ = !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind);
       break;
     default:
       // Keep the defaults.
       break;
   }
 
-  // Always initialize the signal chain so that any calls to sigaction get
-  // correctly routed to the next in the chain regardless of whether we
-  // have claimed the signal or not.
-  InitializeSignalChain();
+  if (!no_sig_chain_) {
+    // Dex2Oat's Runtime does not need the signal chain or the fault handler.
 
-  if (implicit_null_checks_ || implicit_so_checks_ || implicit_suspend_checks_) {
-    fault_manager.Init();
+    // Initialize the signal chain so that any calls to sigaction get
+    // correctly routed to the next in the chain regardless of whether we
+    // have claimed the signal or not.
+    InitializeSignalChain();
 
-    // These need to be in a specific order.  The null point check handler must be
-    // after the suspend check and stack overflow check handlers.
-    //
-    // Note: the instances attach themselves to the fault manager and are handled by it. The manager
-    //       will delete the instance on Shutdown().
-    if (implicit_suspend_checks_) {
-      new SuspensionHandler(&fault_manager);
-    }
+    if (implicit_null_checks_ || implicit_so_checks_ || implicit_suspend_checks_) {
+      fault_manager.Init();
 
-    if (implicit_so_checks_) {
-      new StackOverflowHandler(&fault_manager);
-    }
+      // These need to be in a specific order.  The null point check handler must be
+      // after the suspend check and stack overflow check handlers.
+      //
+      // Note: the instances attach themselves to the fault manager and are handled by it. The manager
+      //       will delete the instance on Shutdown().
+      if (implicit_suspend_checks_) {
+        new SuspensionHandler(&fault_manager);
+      }
 
-    if (implicit_null_checks_) {
-      new NullPointerHandler(&fault_manager);
-    }
+      if (implicit_so_checks_) {
+        new StackOverflowHandler(&fault_manager);
+      }
 
-    if (kEnableJavaStackTraceHandler) {
-      new JavaStackTraceHandler(&fault_manager);
+      if (implicit_null_checks_) {
+        new NullPointerHandler(&fault_manager);
+      }
+
+      if (kEnableJavaStackTraceHandler) {
+        new JavaStackTraceHandler(&fault_manager);
+      }
     }
   }
 
@@ -1499,7 +1515,13 @@
   monitor_list_->EnsureNewMonitorsDisallowed();
   intern_table_->EnsureNewInternsDisallowed();
   java_vm_->EnsureNewWeakGlobalsDisallowed();
-  heap_->EnsureNewAllocationRecordsDisallowed();
+}
+
+void Runtime::BroadcastForNewSystemWeaks() {
+  CHECK(kUseReadBarrier);
+  monitor_list_->BroadcastForNewMonitors();
+  intern_table_->BroadcastForNewInterns();
+  java_vm_->BroadcastForNewWeakGlobals();
 }
 
 void Runtime::SetInstructionSet(InstructionSet instruction_set) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 3cd7404..9ee96a3 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -299,6 +299,7 @@
   void DisallowNewSystemWeaks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AllowNewSystemWeaks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void EnsureNewSystemWeaksDisallowed() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void BroadcastForNewSystemWeaks() 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.
@@ -335,7 +336,7 @@
 
   // Sweep system weaks, the system weak is deleted if the visitor return null. Otherwise, the
   // system weak is updated to be the visitor's returned value.
-  void SweepSystemWeaks(IsMarkedCallback* visitor, void* arg)
+  void SweepSystemWeaks(IsMarkedVisitor* visitor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Constant roots are the roots which never change after the runtime is initialized, they only
@@ -511,8 +512,8 @@
     return cpu_abilist_;
   }
 
-  bool RunningOnValgrind() const {
-    return running_on_valgrind_;
+  bool IsRunningOnMemoryTool() const {
+    return is_running_on_memory_tool_;
   }
 
   void SetTargetSdkVersion(int32_t version) {
@@ -552,6 +553,8 @@
     return method_ref_string_init_reg_map_;
   }
 
+  bool IsDebuggable() const;
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -675,7 +678,7 @@
   bool stats_enabled_;
   RuntimeStats stats_;
 
-  const bool running_on_valgrind_;
+  const bool is_running_on_memory_tool_;
 
   std::string profile_output_filename_;
   ProfilerOptions profiler_options_;
@@ -715,6 +718,11 @@
   bool implicit_so_checks_;         // StackOverflow checks are implicit.
   bool implicit_suspend_checks_;    // Thread suspension checks are implicit.
 
+  // Whether or not the sig chain (and implicitly the fault handler) should be
+  // disabled. Tools like dex2oat or patchoat don't need them. This enables
+  // building a statically link version of dex2oat.
+  bool no_sig_chain_;
+
   // Whether or not a native bridge has been loaded.
   //
   // The native bridge allows running native code compiled for a foreign ISA. The way it works is,
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index fc05cc4..dc4c0c7 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -91,6 +91,7 @@
 RUNTIME_OPTIONS_KEY (BackgroundGcOption,  BackgroundGc)
 
 RUNTIME_OPTIONS_KEY (Unit,                DisableExplicitGC)
+RUNTIME_OPTIONS_KEY (Unit,                NoSigChain)
 RUNTIME_OPTIONS_KEY (LogVerbosity,        Verbose)
 RUNTIME_OPTIONS_KEY (unsigned int,        LockProfThreshold)
 RUNTIME_OPTIONS_KEY (std::string,         StackTraceFile)
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 11c94db..fede91c 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -857,7 +857,6 @@
               << " native=" << method->IsNative()
               << " entrypoints=" << method->GetEntryPointFromQuickCompiledCode()
               << "," << method->GetEntryPointFromJni()
-              << "," << method->GetEntryPointFromInterpreter()
               << " next=" << *cur_quick_frame_;
         }
 
@@ -905,7 +904,7 @@
       CHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), pointer_size);
     }
   }
-  DCHECK_EQ(frame_size & (kStackAlignment - 1), 0U);
+  DCHECK_ALIGNED(frame_size, kStackAlignment);
   DCHECK_NE(reg, -1);
   int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa)
       + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa)
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 741cd90..962132b 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -95,40 +95,37 @@
                                 DexRegisterLocation location,
                                 const std::string& prefix = "v",
                                 const std::string& suffix = "") {
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << prefix << dex_register_num << ": "
-              << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
-              << " (" << location.GetValue() << ")" << suffix << '\n';
+  os << prefix << dex_register_num << ": "
+     << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
+     << " (" << location.GetValue() << ")" << suffix << '\n';
 }
 
-void CodeInfo::Dump(std::ostream& os,
+void CodeInfo::Dump(VariableIndentationOutputStream* vios,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     bool dump_stack_maps) const {
   StackMapEncoding encoding = ExtractEncoding();
   uint32_t code_info_size = GetOverallSize();
   size_t number_of_stack_maps = GetNumberOfStackMaps();
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "Optimized CodeInfo (size=" << code_info_size
-              << ", number_of_dex_registers=" << number_of_dex_registers
-              << ", number_of_stack_maps=" << number_of_stack_maps
-              << ", has_inline_info=" << encoding.HasInlineInfo()
-              << ", number_of_bytes_for_inline_info=" << encoding.NumberOfBytesForInlineInfo()
-              << ", number_of_bytes_for_dex_register_map="
-                  << encoding.NumberOfBytesForDexRegisterMap()
-              << ", number_of_bytes_for_dex_pc=" << encoding.NumberOfBytesForDexPc()
-              << ", number_of_bytes_for_native_pc=" << encoding.NumberOfBytesForNativePc()
-              << ", number_of_bytes_for_register_mask=" << encoding.NumberOfBytesForRegisterMask()
-              << ")\n";
+  vios->Stream()
+      << "Optimized CodeInfo (size=" << code_info_size
+      << ", number_of_dex_registers=" << number_of_dex_registers
+      << ", number_of_stack_maps=" << number_of_stack_maps
+      << ", has_inline_info=" << encoding.HasInlineInfo()
+      << ", number_of_bytes_for_inline_info=" << encoding.NumberOfBytesForInlineInfo()
+      << ", number_of_bytes_for_dex_register_map=" << encoding.NumberOfBytesForDexRegisterMap()
+      << ", number_of_bytes_for_dex_pc=" << encoding.NumberOfBytesForDexPc()
+      << ", number_of_bytes_for_native_pc=" << encoding.NumberOfBytesForNativePc()
+      << ", number_of_bytes_for_register_mask=" << encoding.NumberOfBytesForRegisterMask()
+      << ")\n";
+  ScopedIndentation indent1(vios);
   // Display the Dex register location catalog.
-  GetDexRegisterLocationCatalog(encoding).Dump(indented_os, *this);
+  GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
   // Display stack maps along with (live) Dex register maps.
   if (dump_stack_maps) {
     for (size_t i = 0; i < number_of_stack_maps; ++i) {
       StackMap stack_map = GetStackMapAt(i, encoding);
-      stack_map.Dump(indented_os,
+      stack_map.Dump(vios,
                      *this,
                      encoding,
                      code_offset,
@@ -140,30 +137,28 @@
   //       we need to know the number of dex registers for each inlined method.
 }
 
-void DexRegisterLocationCatalog::Dump(std::ostream& os, const CodeInfo& code_info) {
+void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios,
+                                      const CodeInfo& code_info) {
   StackMapEncoding encoding = code_info.ExtractEncoding();
   size_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
   size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding);
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os
+  vios->Stream()
       << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
       << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
   for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
     DexRegisterLocation location = GetDexRegisterLocation(i);
-    DumpRegisterMapping(indented_os, i, location, "entry ");
+    ScopedIndentation indent1(vios);
+    DumpRegisterMapping(vios->Stream(), i, location, "entry ");
   }
 }
 
-void DexRegisterMap::Dump(std::ostream& os,
+void DexRegisterMap::Dump(VariableIndentationOutputStream* vios,
                           const CodeInfo& code_info,
                           uint16_t number_of_dex_registers) const {
   StackMapEncoding encoding = code_info.ExtractEncoding();
   size_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
   // TODO: Display the bit mask of live Dex registers.
   for (size_t j = 0; j < number_of_dex_registers; ++j) {
     if (IsDexRegisterLive(j)) {
@@ -173,70 +168,70 @@
                                                             number_of_dex_registers,
                                                             code_info,
                                                             encoding);
+      ScopedIndentation indent1(vios);
       DumpRegisterMapping(
-          indented_os, j, location, "v",
+          vios->Stream(), j, location, "v",
           "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
     }
   }
 }
 
-void StackMap::Dump(std::ostream& os,
+void StackMap::Dump(VariableIndentationOutputStream* vios,
                     const CodeInfo& code_info,
                     const StackMapEncoding& encoding,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
                     const std::string& header_suffix) const {
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "StackMap" << header_suffix
-              << std::hex
-              << " [native_pc=0x" << code_offset + GetNativePcOffset(encoding) << "]"
-              << " (dex_pc=0x" << GetDexPc(encoding)
-              << ", native_pc_offset=0x" << GetNativePcOffset(encoding)
-              << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(encoding)
-              << ", inline_info_offset=0x" << GetInlineDescriptorOffset(encoding)
-              << ", register_mask=0x" << GetRegisterMask(encoding)
-              << std::dec
-              << ", stack_mask=0b";
+  vios->Stream()
+      << "StackMap" << header_suffix
+      << std::hex
+      << " [native_pc=0x" << code_offset + GetNativePcOffset(encoding) << "]"
+      << " (dex_pc=0x" << GetDexPc(encoding)
+      << ", native_pc_offset=0x" << GetNativePcOffset(encoding)
+      << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(encoding)
+      << ", inline_info_offset=0x" << GetInlineDescriptorOffset(encoding)
+      << ", register_mask=0x" << GetRegisterMask(encoding)
+      << std::dec
+      << ", stack_mask=0b";
   MemoryRegion stack_mask = GetStackMask(encoding);
   for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
-    indented_os << stack_mask.LoadBit(e - i - 1);
+    vios->Stream() << stack_mask.LoadBit(e - i - 1);
   }
-  indented_os << ")\n";
+  vios->Stream() << ")\n";
   if (HasDexRegisterMap(encoding)) {
     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
         *this, encoding, number_of_dex_registers);
-    dex_register_map.Dump(os, code_info, number_of_dex_registers);
+    dex_register_map.Dump(vios, code_info, number_of_dex_registers);
   }
   if (HasInlineInfo(encoding)) {
     InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding);
     // We do not know the length of the dex register maps of inlined frames
     // at this level, so we just pass null to `InlineInfo::Dump` to tell
     // it not to look at these maps.
-    inline_info.Dump(os, code_info, nullptr);
+    inline_info.Dump(vios, code_info, nullptr);
   }
 }
 
-void InlineInfo::Dump(std::ostream& os,
+void InlineInfo::Dump(VariableIndentationOutputStream* vios,
                       const CodeInfo& code_info,
                       uint16_t number_of_dex_registers[]) const {
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indented_os(&indent_filter);
-  indented_os << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
+  vios->Stream() << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
 
   for (size_t i = 0; i < GetDepth(); ++i) {
-    indented_os << " At depth " << i
-                << std::hex
-                << " (dex_pc=0x" << GetDexPcAtDepth(i)
-                << std::dec
-                << ", method_index=" << GetMethodIndexAtDepth(i)
-                << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
-                << ")\n";
+    vios->Stream()
+        << " At depth " << i
+        << std::hex
+        << " (dex_pc=0x" << GetDexPcAtDepth(i)
+        << std::dec
+        << ", method_index=" << GetMethodIndexAtDepth(i)
+        << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
+        << ")\n";
     if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) {
       StackMapEncoding encoding = code_info.ExtractEncoding();
       DexRegisterMap dex_register_map =
           code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
-      dex_register_map.Dump(indented_os, code_info, number_of_dex_registers[i]);
+      ScopedIndentation indent1(vios);
+      dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]);
     }
   }
 }
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 4e42008..1acc442 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -23,6 +23,8 @@
 
 namespace art {
 
+class VariableIndentationOutputStream;
+
 // Size of a frame slot, in bytes.  This constant is a signed value,
 // to please the compiler in arithmetic operations involving int32_t
 // (signed) values.
@@ -31,6 +33,11 @@
 // Size of Dex virtual registers.
 static constexpr size_t kVRegSize = 4;
 
+// We encode the number of bytes needed for writing a value on 3 bits
+// (i.e. up to 8 values), for values that we know are maximum 32-bit
+// long.
+static constexpr size_t kNumberOfBitForNumberOfBytesForEncoding = 3;
+
 class CodeInfo;
 class StackMapEncoding;
 
@@ -357,7 +364,7 @@
     return region_.size();
   }
 
-  void Dump(std::ostream& os, const CodeInfo& code_info);
+  void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info);
 
   // Special (invalid) Dex register location catalog entry index meaning
   // that there is no location for a given Dex register (i.e., it is
@@ -610,7 +617,8 @@
     return region_.size();
   }
 
-  void Dump(std::ostream& o, const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
+  void Dump(VariableIndentationOutputStream* vios,
+            const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
 
  private:
   // Return the index in the Dex register map corresponding to the Dex
@@ -837,7 +845,7 @@
        && region_.size() == other.region_.size();
   }
 
-  void Dump(std::ostream& os,
+  void Dump(VariableIndentationOutputStream* vios,
             const CodeInfo& code_info,
             const StackMapEncoding& encoding,
             uint32_t code_offset,
@@ -931,7 +939,8 @@
     return kFixedEntrySize;
   }
 
-  void Dump(std::ostream& os, const CodeInfo& info, uint16_t* number_of_dex_registers) const;
+  void Dump(VariableIndentationOutputStream* vios,
+            const CodeInfo& info, uint16_t* number_of_dex_registers) const;
 
  private:
   // TODO: Instead of plain types such as "uint8_t", introduce
@@ -987,17 +996,11 @@
   }
 
   void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
-    // We encode the number of bytes needed for writing a value on 3 bits,
-    // for values that we know are maximum 32bits.
-    region_.StoreBit(bit_offset, (number_of_bytes & 1));
-    region_.StoreBit(bit_offset + 1, (number_of_bytes & 2));
-    region_.StoreBit(bit_offset + 2, (number_of_bytes & 4));
+    region_.StoreBits(bit_offset, number_of_bytes, kNumberOfBitForNumberOfBytesForEncoding);
   }
 
   size_t GetNumberOfBytesForEncoding(size_t bit_offset) const {
-    return region_.LoadBit(bit_offset)
-        + (region_.LoadBit(bit_offset + 1) << 1)
-        + (region_.LoadBit(bit_offset + 2) << 2);
+    return region_.LoadBits(bit_offset, kNumberOfBitForNumberOfBytesForEncoding);
   }
 
   bool HasInlineInfo() const {
@@ -1120,7 +1123,7 @@
   // number of Dex virtual registers used in this method.  If
   // `dump_stack_maps` is true, also dump the stack maps and the
   // associated Dex register maps.
-  void Dump(std::ostream& os,
+  void Dump(VariableIndentationOutputStream* vios,
             uint32_t code_offset,
             uint16_t number_of_dex_registers,
             bool dump_stack_maps) const;
@@ -1139,10 +1142,14 @@
 
   static constexpr int kHasInlineInfoBitOffset = (kEncodingInfoOffset * kBitsPerByte);
   static constexpr int kInlineInfoBitOffset = kHasInlineInfoBitOffset + 1;
-  static constexpr int kDexRegisterMapBitOffset = kInlineInfoBitOffset + 3;
-  static constexpr int kDexPcBitOffset = kDexRegisterMapBitOffset + 3;
-  static constexpr int kNativePcBitOffset = kDexPcBitOffset + 3;
-  static constexpr int kRegisterMaskBitOffset = kNativePcBitOffset + 3;
+  static constexpr int kDexRegisterMapBitOffset =
+      kInlineInfoBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
+  static constexpr int kDexPcBitOffset =
+      kDexRegisterMapBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
+  static constexpr int kNativePcBitOffset =
+      kDexPcBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
+  static constexpr int kRegisterMaskBitOffset =
+      kNativePcBitOffset + kNumberOfBitForNumberOfBytesForEncoding;
 
   MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
     return region_.size() == 0
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index f7ef894..39ef68a 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -25,6 +25,7 @@
 #include "base/mutex-inl.h"
 #include "gc/heap.h"
 #include "jni_env_ext.h"
+#include "thread_pool.h"
 
 namespace art {
 
@@ -66,8 +67,10 @@
 }
 
 inline ThreadState Thread::SetState(ThreadState new_state) {
-  // Cannot use this code to change into Runnable as changing to Runnable should fail if
-  // old_state_and_flags.suspend_request is true.
+  // Should only be used to change between suspended states.
+  // Cannot use this code to change into or from Runnable as changing to Runnable should
+  // fail if old_state_and_flags.suspend_request is true and changing from Runnable might
+  // miss passing an active suspend barrier.
   DCHECK_NE(new_state, kRunnable);
   if (kIsDebugBuild && this != Thread::Current()) {
     std::string name;
@@ -77,6 +80,7 @@
   }
   union StateAndFlags old_state_and_flags;
   old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
+  CHECK_NE(old_state_and_flags.as_struct.state, kRunnable);
   tls32_.state_and_flags.as_struct.state = new_state;
   return static_cast<ThreadState>(old_state_and_flags.as_struct.state);
 }
@@ -125,20 +129,34 @@
     new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags;
     new_state_and_flags.as_struct.state = new_state;
 
-    // CAS the value without a memory ordering as that is given by the lock release below.
+    // CAS the value with a memory ordering.
     bool done =
-        tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,
+        tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelease(old_state_and_flags.as_int,
                                                                         new_state_and_flags.as_int);
     if (LIKELY(done)) {
       break;
     }
   }
-  // Release share on mutator_lock_.
-  Locks::mutator_lock_->SharedUnlock(this);
+
+  // Change to non-runnable state, thereby appearing suspended to the system.
+  // Mark the release of the share of the mutator_lock_.
+  Locks::mutator_lock_->TransitionFromRunnableToSuspended(this);
+
+  // Once suspended - check the active suspend barrier flag
+  while (true) {
+    uint16_t current_flags = tls32_.state_and_flags.as_struct.flags;
+    if (LIKELY((current_flags & (kCheckpointRequest | kActiveSuspendBarrier)) == 0)) {
+      break;
+    } else if ((current_flags & kActiveSuspendBarrier) != 0) {
+      PassActiveSuspendBarriers(this);
+    } else {
+      // Impossible
+      LOG(FATAL) << "Fatal, thread transited into suspended without running the checkpoint";
+    }
+  }
 }
 
 inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
-  bool done = false;
   union StateAndFlags old_state_and_flags;
   old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
   int16_t old_state = old_state_and_flags.as_struct.state;
@@ -147,7 +165,26 @@
     Locks::mutator_lock_->AssertNotHeld(this);  // Otherwise we starve GC..
     old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
     DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
-    if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) {
+    if (LIKELY(old_state_and_flags.as_struct.flags == 0)) {
+      // Optimize for the return from native code case - this is the fast path.
+      // Atomically change from suspended to runnable if no suspend request pending.
+      union StateAndFlags new_state_and_flags;
+      new_state_and_flags.as_int = old_state_and_flags.as_int;
+      new_state_and_flags.as_struct.state = kRunnable;
+      // CAS the value with a memory barrier.
+      if (LIKELY(tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakAcquire(
+                                                 old_state_and_flags.as_int,
+                                                 new_state_and_flags.as_int))) {
+        // Mark the acquisition of a share of the mutator_lock_.
+        Locks::mutator_lock_->TransitionFromSuspendedToRunnable(this);
+        break;
+      }
+    } else if ((old_state_and_flags.as_struct.flags & kActiveSuspendBarrier) != 0) {
+      PassActiveSuspendBarriers(this);
+    } else if ((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0) {
+      // Impossible
+      LOG(FATAL) << "Fatal, wrong checkpoint flag";
+    } else if ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
       // Wait while our suspend count is non-zero.
       MutexLock mu(this, *Locks::thread_suspend_count_lock_);
       old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
@@ -160,32 +197,13 @@
       }
       DCHECK_EQ(GetSuspendCount(), 0);
     }
-    // Re-acquire shared mutator_lock_ access.
-    Locks::mutator_lock_->SharedLock(this);
-    // Atomically change from suspended to runnable if no suspend request pending.
-    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
-    DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
-    if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) {
-      union StateAndFlags new_state_and_flags;
-      new_state_and_flags.as_int = old_state_and_flags.as_int;
-      new_state_and_flags.as_struct.state = kRunnable;
-      // CAS the value without a memory ordering as that is given by the lock acquisition above.
-      done =
-          tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,
-                                                                          new_state_and_flags.as_int);
-    }
-    if (UNLIKELY(!done)) {
-      // Failed to transition to Runnable. Release shared mutator_lock_ access and try again.
-      Locks::mutator_lock_->SharedUnlock(this);
-    } else {
-      // Run the flip function, if set.
-      Closure* flip_func = GetFlipFunction();
-      if (flip_func != nullptr) {
-        flip_func->Run(this);
-      }
-      return static_cast<ThreadState>(old_state);
-    }
   } while (true);
+  // Run the flip function, if set.
+  Closure* flip_func = GetFlipFunction();
+  if (flip_func != nullptr) {
+    flip_func->Run(this);
+  }
+  return static_cast<ThreadState>(old_state);
 }
 
 inline void Thread::VerifyStack() {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 37a86f1..cede998 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -35,6 +35,7 @@
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/bit_utils.h"
+#include "base/memory_tool.h"
 #include "base/mutex.h"
 #include "base/timing_logger.h"
 #include "base/to_str.h"
@@ -74,6 +75,14 @@
 #include "vmap_table.h"
 #include "well_known_classes.h"
 
+#if ART_USE_FUTEXES
+#include "linux/futex.h"
+#include "sys/syscall.h"
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#endif  // ART_USE_FUTEXES
+
 namespace art {
 
 bool Thread::is_started_ = false;
@@ -81,6 +90,12 @@
 ConditionVariable* Thread::resume_cond_ = nullptr;
 const size_t Thread::kStackOverflowImplicitCheckSize = GetStackOverflowReservedBytes(kRuntimeISA);
 
+// For implicit overflow checks we reserve an extra piece of memory at the bottom
+// of the stack (lowest memory).  The higher portion of the memory
+// is protected against reads and the lower is available for use while
+// throwing the StackOverflow exception.
+constexpr size_t kStackOverflowProtectedSize = 4 * kMemoryToolStackGuardSizeScale * KB;
+
 static const char* kThreadNameDuringStartup = "<native thread without managed peer>";
 
 void Thread::InitCardTable() {
@@ -351,6 +366,10 @@
 // to make sure the pages for the stack are mapped in before we call mprotect.  We do
 // this by reading every page from the stack bottom (highest address) to the stack top.
 // We then madvise this away.
+
+// AddressSanitizer does not like the part of this functions that reads every stack page.
+// Looks a lot like an out-of-bounds access.
+ATTRIBUTE_NO_SANITIZE_ADDRESS
 void Thread::InstallImplicitProtection() {
   uint8_t* pregion = tlsPtr_.stack_begin - kStackOverflowProtectedSize;
   uint8_t* stack_himem = tlsPtr_.stack_end;
@@ -388,6 +407,24 @@
 void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
   CHECK(java_peer != nullptr);
   Thread* self = static_cast<JNIEnvExt*>(env)->self;
+
+  if (VLOG_IS_ON(threads)) {
+    ScopedObjectAccess soa(env);
+
+    ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
+    mirror::String* java_name = reinterpret_cast<mirror::String*>(f->GetObject(
+        soa.Decode<mirror::Object*>(java_peer)));
+    std::string thread_name;
+    if (java_name != nullptr) {
+      thread_name = java_name->ToModifiedUtf8();
+    } else {
+      thread_name = "(Unnamed)";
+    }
+
+    VLOG(threads) << "Creating native thread for " << thread_name;
+    self->Dump(LOG(INFO));
+  }
+
   Runtime* runtime = Runtime::Current();
 
   // Atomically start the birth of the thread ensuring the runtime isn't shutting down.
@@ -556,6 +593,16 @@
     }
   }
 
+  if (VLOG_IS_ON(threads)) {
+    if (thread_name != nullptr) {
+      VLOG(threads) << "Attaching thread " << thread_name;
+    } else {
+      VLOG(threads) << "Attaching unnamed thread.";
+    }
+    ScopedObjectAccess soa(self);
+    self->Dump(LOG(INFO));
+  }
+
   {
     ScopedObjectAccess soa(self);
     Dbg::PostThreadStart(self);
@@ -758,7 +805,8 @@
   LOG(FATAL) << ss.str();
 }
 
-void Thread::ModifySuspendCount(Thread* self, int delta, bool for_debugger) {
+bool Thread::ModifySuspendCount(Thread* self, int delta, AtomicInteger* suspend_barrier,
+                                bool for_debugger) {
   if (kIsDebugBuild) {
     DCHECK(delta == -1 || delta == +1 || delta == -tls32_.debug_suspend_count)
           << delta << " " << tls32_.debug_suspend_count << " " << this;
@@ -770,7 +818,24 @@
   }
   if (UNLIKELY(delta < 0 && tls32_.suspend_count <= 0)) {
     UnsafeLogFatalForSuspendCount(self, this);
-    return;
+    return false;
+  }
+
+  uint16_t flags = kSuspendRequest;
+  if (delta > 0 && suspend_barrier != nullptr) {
+    uint32_t available_barrier = kMaxSuspendBarriers;
+    for (uint32_t i = 0; i < kMaxSuspendBarriers; ++i) {
+      if (tlsPtr_.active_suspend_barriers[i] == nullptr) {
+        available_barrier = i;
+        break;
+      }
+    }
+    if (available_barrier == kMaxSuspendBarriers) {
+      // No barrier spaces available, we can't add another.
+      return false;
+    }
+    tlsPtr_.active_suspend_barriers[available_barrier] = suspend_barrier;
+    flags |= kActiveSuspendBarrier;
   }
 
   tls32_.suspend_count += delta;
@@ -781,9 +846,76 @@
   if (tls32_.suspend_count == 0) {
     AtomicClearFlag(kSuspendRequest);
   } else {
-    AtomicSetFlag(kSuspendRequest);
+    // Two bits might be set simultaneously.
+    tls32_.state_and_flags.as_atomic_int.FetchAndOrSequentiallyConsistent(flags);
     TriggerSuspend();
   }
+  return true;
+}
+
+bool Thread::PassActiveSuspendBarriers(Thread* self) {
+  // Grab the suspend_count lock and copy the current set of
+  // barriers. Then clear the list and the flag. The ModifySuspendCount
+  // function requires the lock so we prevent a race between setting
+  // the kActiveSuspendBarrier flag and clearing it.
+  AtomicInteger* pass_barriers[kMaxSuspendBarriers];
+  {
+    MutexLock mu(self, *Locks::thread_suspend_count_lock_);
+    if (!ReadFlag(kActiveSuspendBarrier)) {
+      // quick exit test: the barriers have already been claimed - this is
+      // possible as there may be a race to claim and it doesn't matter
+      // who wins.
+      // All of the callers of this function (except the SuspendAllInternal)
+      // will first test the kActiveSuspendBarrier flag without lock. Here
+      // double-check whether the barrier has been passed with the
+      // suspend_count lock.
+      return false;
+    }
+
+    for (uint32_t i = 0; i < kMaxSuspendBarriers; ++i) {
+      pass_barriers[i] = tlsPtr_.active_suspend_barriers[i];
+      tlsPtr_.active_suspend_barriers[i] = nullptr;
+    }
+    AtomicClearFlag(kActiveSuspendBarrier);
+  }
+
+  uint32_t barrier_count = 0;
+  for (uint32_t i = 0; i < kMaxSuspendBarriers; i++) {
+    AtomicInteger* pending_threads = pass_barriers[i];
+    if (pending_threads != nullptr) {
+      bool done = false;
+      do {
+        int32_t cur_val = pending_threads->LoadRelaxed();
+        CHECK_GT(cur_val, 0) << "Unexpected value for PassActiveSuspendBarriers(): " << cur_val;
+        // Reduce value by 1.
+        done = pending_threads->CompareExchangeWeakRelaxed(cur_val, cur_val - 1);
+#if ART_USE_FUTEXES
+        if (done && (cur_val - 1) == 0) {  // Weak CAS may fail spuriously.
+          futex(pending_threads->Address(), FUTEX_WAKE, -1, nullptr, nullptr, 0);
+        }
+#endif
+      } while (!done);
+      ++barrier_count;
+    }
+  }
+  CHECK_GT(barrier_count, 0U);
+  return true;
+}
+
+void Thread::ClearSuspendBarrier(AtomicInteger* target) {
+  CHECK(ReadFlag(kActiveSuspendBarrier));
+  bool clear_flag = true;
+  for (uint32_t i = 0; i < kMaxSuspendBarriers; ++i) {
+    AtomicInteger* ptr = tlsPtr_.active_suspend_barriers[i];
+    if (ptr == target) {
+      tlsPtr_.active_suspend_barriers[i] = nullptr;
+    } else if (ptr != nullptr) {
+      clear_flag = false;
+    }
+  }
+  if (LIKELY(clear_flag)) {
+    AtomicClearFlag(kActiveSuspendBarrier);
+  }
 }
 
 void Thread::RunCheckpointFunction() {
@@ -1288,7 +1420,11 @@
   for (uint32_t i = 0; i < kMaxCheckpoints; ++i) {
     tlsPtr_.checkpoint_functions[i] = nullptr;
   }
+  for (uint32_t i = 0; i < kMaxSuspendBarriers; ++i) {
+    tlsPtr_.active_suspend_barriers[i] = nullptr;
+  }
   tlsPtr_.flip_function = nullptr;
+  tlsPtr_.thread_local_mark_stack = nullptr;
   tls32_.suspended_at_suspend_check = false;
 }
 
@@ -1407,6 +1543,9 @@
   {
     ScopedObjectAccess soa(self);
     Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
+    if (kUseReadBarrier) {
+      Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->RevokeThreadLocalMarkStack(this);
+    }
   }
 }
 
diff --git a/runtime/thread.h b/runtime/thread.h
index 0e71c08..7826e62 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -46,6 +46,9 @@
 namespace art {
 
 namespace gc {
+namespace accounting {
+  template<class T> class AtomicStack;
+}  // namespace accounting
 namespace collector {
   class SemiSpace;
 }  // namespace collector
@@ -98,7 +101,8 @@
 enum ThreadFlag {
   kSuspendRequest   = 1,  // If set implies that suspend_count_ > 0 and the Thread should enter the
                           // safepoint handler.
-  kCheckpointRequest = 2  // Request that the thread do some checkpoint work and then continue.
+  kCheckpointRequest = 2,  // Request that the thread do some checkpoint work and then continue.
+  kActiveSuspendBarrier = 4  // Register that at least 1 suspend barrier needs to be passed.
 };
 
 enum class StackedShadowFrameType {
@@ -138,11 +142,6 @@
 
 class Thread {
  public:
-  // For implicit overflow checks we reserve an extra piece of memory at the bottom
-  // of the stack (lowest memory).  The higher portion of the memory
-  // is protected against reads and the lower is available for use while
-  // throwing the StackOverflow exception.
-  static constexpr size_t kStackOverflowProtectedSize = 4 * KB;
   static const size_t kStackOverflowImplicitCheckSize;
 
   // Creates a new native thread corresponding to the given managed peer.
@@ -223,7 +222,7 @@
         (state_and_flags.as_struct.flags & kSuspendRequest) != 0;
   }
 
-  void ModifySuspendCount(Thread* self, int delta, bool for_debugger)
+  bool ModifySuspendCount(Thread* self, int delta, AtomicInteger* suspend_barrier, bool for_debugger)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_suspend_count_lock_);
 
   bool RequestCheckpoint(Closure* function)
@@ -232,6 +231,15 @@
   void SetFlipFunction(Closure* function);
   Closure* GetFlipFunction();
 
+  gc::accounting::AtomicStack<mirror::Object>* GetThreadLocalMarkStack() {
+    CHECK(kUseReadBarrier);
+    return tlsPtr_.thread_local_mark_stack;
+  }
+  void SetThreadLocalMarkStack(gc::accounting::AtomicStack<mirror::Object>* stack) {
+    CHECK(kUseReadBarrier);
+    tlsPtr_.thread_local_mark_stack = stack;
+  }
+
   // Called when thread detected that the thread_suspend_count_ was non-zero. Gives up share of
   // mutator_lock_ and waits until it is resumed and thread_suspend_count_ is zero.
   void FullSuspendCheck()
@@ -772,6 +780,16 @@
     tls32_.debug_method_entry_ = false;
   }
 
+  bool GetWeakRefAccessEnabled() const {
+    CHECK(kUseReadBarrier);
+    return tls32_.weak_ref_access_enabled;
+  }
+
+  void SetWeakRefAccessEnabled(bool enabled) {
+    CHECK(kUseReadBarrier);
+    tls32_.weak_ref_access_enabled = enabled;
+  }
+
   // Activates single step control for debugging. The thread takes the
   // ownership of the given SingleStepControl*. It is deleted by a call
   // to DeactivateSingleStepControl or upon thread destruction.
@@ -846,6 +864,12 @@
 
   void RunCheckpointFunction();
 
+  bool PassActiveSuspendBarriers(Thread* self)
+      LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_);
+
+  void ClearSuspendBarrier(AtomicInteger* target)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_suspend_count_lock_);
+
   bool ReadFlag(ThreadFlag flag) const {
     return (tls32_.state_and_flags.as_struct.flags & flag) != 0;
   }
@@ -964,6 +988,11 @@
   ThreadState SetStateUnsafe(ThreadState new_state) {
     ThreadState old_state = GetState();
     tls32_.state_and_flags.as_struct.state = new_state;
+    // if transit to a suspended state, check the pass barrier request.
+    if (UNLIKELY((new_state != kRunnable) &&
+                 (tls32_.state_and_flags.as_struct.flags & kActiveSuspendBarrier))) {
+      PassActiveSuspendBarriers(this);
+    }
     return old_state;
   }
 
@@ -1034,6 +1063,9 @@
   // Maximum number of checkpoint functions.
   static constexpr uint32_t kMaxCheckpoints = 3;
 
+  // Maximum number of suspend barriers.
+  static constexpr uint32_t kMaxSuspendBarriers = 3;
+
   // Has Thread::Startup been called?
   static bool is_started_;
 
@@ -1060,7 +1092,7 @@
       daemon(is_daemon), throwing_OutOfMemoryError(false), no_thread_suspension(0),
       thread_exit_check_count(0), handling_signal_(false),
       deoptimization_return_value_is_reference(false), suspended_at_suspend_check(false),
-      ready_for_debug_invoke(false), debug_method_entry_(false) {
+      ready_for_debug_invoke(false), debug_method_entry_(false), weak_ref_access_enabled(true) {
     }
 
     union StateAndFlags state_and_flags;
@@ -1117,6 +1149,15 @@
     // True if the thread enters a method. This is used to detect method entry
     // event for the debugger.
     bool32_t debug_method_entry_;
+
+    // True if the thread is allowed to access a weak ref (Reference::GetReferent() and system
+    // weaks) and to potentially mark an object alive/gray. This is used for concurrent reference
+    // processing of the CC collector only. This is thread local so that we can enable/disable weak
+    // ref access by using a checkpoint and avoid a race around the time weak ref access gets
+    // disabled and concurrent reference processing begins (if weak ref access is disabled during a
+    // pause, this is not an issue.) Other collectors use Runtime::DisallowNewSystemWeaks() and
+    // ReferenceProcessor::EnableSlowPath().
+    bool32_t weak_ref_access_enabled;
   } tls32_;
 
   struct PACKED(8) tls_64bit_sized_values {
@@ -1238,6 +1279,12 @@
     // Locks::thread_suspend_count_lock_.
     Closure* checkpoint_functions[kMaxCheckpoints];
 
+    // Pending barriers that require passing or NULL if non-pending. Installation guarding by
+    // Locks::thread_suspend_count_lock_.
+    // They work effectively as art::Barrier, but implemented directly using AtomicInteger and futex
+    // to avoid additional cost of a mutex and a condition variable, as used in art::Barrier.
+    AtomicInteger* active_suspend_barriers[kMaxSuspendBarriers];
+
     // Entrypoint function pointers.
     // TODO: move this to more of a global offset table model to avoid per-thread duplication.
     InterpreterEntryPoints interpreter_entrypoints;
@@ -1268,6 +1315,9 @@
 
     // Current method verifier, used for root marking.
     verifier::MethodVerifier* method_verifier;
+
+    // Thread-local mark stack for the concurrent copying collector.
+    gc::accounting::AtomicStack<mirror::Object>* thread_local_mark_stack;
   } tlsPtr_;
 
   // Guards the 'interrupted_' and 'wait_monitor_' members.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index b697b43..60c9b5e 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -28,11 +28,11 @@
 #include <sstream>
 
 #include "base/histogram-inl.h"
-#include "base/mutex.h"
 #include "base/mutex-inl.h"
 #include "base/time_utils.h"
 #include "base/timing_logger.h"
 #include "debugger.h"
+#include "gc/collector/concurrent_copying.h"
 #include "jni_internal.h"
 #include "lock_word.h"
 #include "monitor.h"
@@ -41,6 +41,14 @@
 #include "trace.h"
 #include "well_known_classes.h"
 
+#if ART_USE_FUTEXES
+#include "linux/futex.h"
+#include "sys/syscall.h"
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#endif  // ART_USE_FUTEXES
+
 namespace art {
 
 static constexpr uint64_t kLongThreadSuspendThreshold = MsToNs(5);
@@ -279,7 +287,7 @@
               // Spurious fail, try again.
               continue;
             }
-            thread->ModifySuspendCount(self, +1, false);
+            thread->ModifySuspendCount(self, +1, nullptr, false);
             suspended_count_modified_threads.push_back(thread);
             break;
           }
@@ -317,7 +325,7 @@
     checkpoint_function->Run(thread);
     {
       MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
-      thread->ModifySuspendCount(self, -1, false);
+      thread->ModifySuspendCount(self, -1, nullptr, false);
     }
   }
 
@@ -373,23 +381,7 @@
   Locks::thread_suspend_count_lock_->AssertNotHeld(self);
   CHECK_NE(self->GetState(), kRunnable);
 
-  std::vector<Thread*> runnable_threads;
-  std::vector<Thread*> other_threads;
-
-  // Suspend all threads once.
-  {
-    MutexLock mu(self, *Locks::thread_list_lock_);
-    MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
-    // Update global suspend all state for attaching threads.
-    ++suspend_all_count_;
-    // Increment everybody's suspend count (except our own).
-    for (const auto& thread : list_) {
-      if (thread == self) {
-        continue;
-      }
-      thread->ModifySuspendCount(self, +1, false);
-    }
-  }
+  SuspendAllInternal(self, self, nullptr);
 
   // Run the flip callback for the collector.
   Locks::mutator_lock_->ExclusiveLock(self);
@@ -398,6 +390,8 @@
   collector->RegisterPause(NanoTime() - start_time);
 
   // Resume runnable threads.
+  std::vector<Thread*> runnable_threads;
+  std::vector<Thread*> other_threads;
   {
     MutexLock mu(self, *Locks::thread_list_lock_);
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
@@ -414,7 +408,7 @@
       thread->SetFlipFunction(thread_flip_visitor);
       if (thread->IsSuspendedAtSuspendCheck()) {
         // The thread will resume right after the broadcast.
-        thread->ModifySuspendCount(self, -1, false);
+        thread->ModifySuspendCount(self, -1, nullptr, false);
         runnable_threads.push_back(thread);
       } else {
         other_threads.push_back(thread);
@@ -440,7 +434,7 @@
   {
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
     for (const auto& thread : other_threads) {
-      thread->ModifySuspendCount(self, -1, false);
+      thread->ModifySuspendCount(self, -1, nullptr, false);
     }
     Thread::resume_cond_->Broadcast(self);
   }
@@ -459,28 +453,9 @@
   ATRACE_BEGIN("Suspending mutator threads");
   const uint64_t start_time = NanoTime();
 
-  Locks::mutator_lock_->AssertNotHeld(self);
-  Locks::thread_list_lock_->AssertNotHeld(self);
-  Locks::thread_suspend_count_lock_->AssertNotHeld(self);
-  if (kDebugLocking && self != nullptr) {
-    CHECK_NE(self->GetState(), kRunnable);
-  }
-  {
-    MutexLock mu(self, *Locks::thread_list_lock_);
-    MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
-    // Update global suspend all state for attaching threads.
-    ++suspend_all_count_;
-    // Increment everybody's suspend count (except our own).
-    for (const auto& thread : list_) {
-      if (thread == self) {
-        continue;
-      }
-      VLOG(threads) << "requesting thread suspend: " << *thread;
-      thread->ModifySuspendCount(self, +1, false);
-    }
-  }
-
-  // Block on the mutator lock until all Runnable threads release their share of access.
+  SuspendAllInternal(self, self);
+  // All threads are known to have suspended (but a thread may still own the mutator lock)
+  // Make sure this thread grabs exclusive access to the mutator lock and its protected data.
 #if HAVE_TIMED_RWLOCK
   while (true) {
     if (Locks::mutator_lock_->ExclusiveLockWithTimeout(self, kThreadSuspendTimeoutMs, 0)) {
@@ -520,6 +495,114 @@
   }
 }
 
+// Ensures all threads running Java suspend and that those not running Java don't start.
+// Debugger thread might be set to kRunnable for a short period of time after the
+// SuspendAllInternal. This is safe because it will be set back to suspended state before
+// the SuspendAll returns.
+void ThreadList::SuspendAllInternal(Thread* self, Thread* ignore1, Thread* ignore2,
+                                    bool debug_suspend) {
+  Locks::mutator_lock_->AssertNotExclusiveHeld(self);
+  Locks::thread_list_lock_->AssertNotHeld(self);
+  Locks::thread_suspend_count_lock_->AssertNotHeld(self);
+  if (kDebugLocking && self != nullptr) {
+    CHECK_NE(self->GetState(), kRunnable);
+  }
+
+  // First request that all threads suspend, then wait for them to suspend before
+  // returning. This suspension scheme also relies on other behaviour:
+  // 1. Threads cannot be deleted while they are suspended or have a suspend-
+  //    request flag set - (see Unregister() below).
+  // 2. When threads are created, they are created in a suspended state (actually
+  //    kNative) and will never begin executing Java code without first checking
+  //    the suspend-request flag.
+
+  // The atomic counter for number of threads that need to pass the barrier.
+  AtomicInteger pending_threads;
+  uint32_t num_ignored = 0;
+  if (ignore1 != nullptr) {
+    ++num_ignored;
+  }
+  if (ignore2 != nullptr && ignore1 != ignore2) {
+    ++num_ignored;
+  }
+  {
+    MutexLock mu(self, *Locks::thread_list_lock_);
+    MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
+    // Update global suspend all state for attaching threads.
+    ++suspend_all_count_;
+    if (debug_suspend)
+      ++debug_suspend_all_count_;
+    pending_threads.StoreRelaxed(list_.size() - num_ignored);
+    // Increment everybody's suspend count (except those that should be ignored).
+    for (const auto& thread : list_) {
+      if (thread == ignore1 || thread == ignore2) {
+        continue;
+      }
+      VLOG(threads) << "requesting thread suspend: " << *thread;
+      while (true) {
+        if (LIKELY(thread->ModifySuspendCount(self, +1, &pending_threads, debug_suspend))) {
+          break;
+        } else {
+          // Failure means the list of active_suspend_barriers is full, we should release the
+          // thread_suspend_count_lock_ (to avoid deadlock) and wait till the target thread has
+          // executed Thread::PassActiveSuspendBarriers(). Note that we could not simply wait for
+          // the thread to change to a suspended state, because it might need to run checkpoint
+          // function before the state change, which also needs thread_suspend_count_lock_.
+
+          // This is very unlikely to happen since more than kMaxSuspendBarriers threads need to
+          // execute SuspendAllInternal() simultaneously, and target thread stays in kRunnable
+          // in the mean time.
+          Locks::thread_suspend_count_lock_->ExclusiveUnlock(self);
+          NanoSleep(100000);
+          Locks::thread_suspend_count_lock_->ExclusiveLock(self);
+        }
+      }
+
+      // Must install the pending_threads counter first, then check thread->IsSuspend() and clear
+      // the counter. Otherwise there's a race with Thread::TransitionFromRunnableToSuspended()
+      // that can lead a thread to miss a call to PassActiveSuspendBarriers().
+      if (thread->IsSuspended()) {
+        // Only clear the counter for the current thread.
+        thread->ClearSuspendBarrier(&pending_threads);
+        pending_threads.FetchAndSubSequentiallyConsistent(1);
+      }
+    }
+  }
+
+  // Wait for the barrier to be passed by all runnable threads. This wait
+  // is done with a timeout so that we can detect problems.
+#if ART_USE_FUTEXES
+  timespec wait_timeout;
+  InitTimeSpec(true, CLOCK_MONOTONIC, 10000, 0, &wait_timeout);
+#endif
+  while (true) {
+    int32_t cur_val = pending_threads.LoadRelaxed();
+    if (LIKELY(cur_val > 0)) {
+#if ART_USE_FUTEXES
+      if (futex(pending_threads.Address(), FUTEX_WAIT, cur_val, &wait_timeout, nullptr, 0) != 0) {
+        // EAGAIN and EINTR both indicate a spurious failure, try again from the beginning.
+        if ((errno != EAGAIN) && (errno != EINTR)) {
+          if (errno == ETIMEDOUT) {
+            LOG(kIsDebugBuild ? FATAL : ERROR) << "Unexpected time out during suspend all.";
+          } else {
+            PLOG(FATAL) << "futex wait failed for SuspendAllInternal()";
+          }
+        }
+      } else {
+        cur_val = pending_threads.LoadRelaxed();
+        CHECK_EQ(cur_val, 0);
+        break;
+      }
+#else
+      // Spin wait. This is likely to be slow, but on most architecture ART_USE_FUTEXES is set.
+#endif
+    } else {
+      CHECK_EQ(cur_val, 0);
+      break;
+    }
+  }
+}
+
 void ThreadList::ResumeAll() {
   Thread* self = Thread::Current();
 
@@ -550,7 +633,7 @@
       if (thread == self) {
         continue;
       }
-      thread->ModifySuspendCount(self, -1, false);
+      thread->ModifySuspendCount(self, -1, nullptr, false);
     }
 
     // Broadcast a notification to all suspended threads, some or all of
@@ -593,7 +676,7 @@
           << ") thread not within thread list";
       return;
     }
-    thread->ModifySuspendCount(self, -1, for_debugger);
+    thread->ModifySuspendCount(self, -1, nullptr, for_debugger);
   }
 
   {
@@ -645,7 +728,7 @@
           // If we incremented the suspend count but the thread reset its peer, we need to
           // re-decrement it since it is shutting down and may deadlock the runtime in
           // ThreadList::WaitForOtherNonDaemonThreadsToExit.
-          suspended_thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
+          suspended_thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
         }
         ThreadSuspendByPeerWarning(self, WARNING, "No such thread for suspend", peer);
         return nullptr;
@@ -668,7 +751,7 @@
           }
           CHECK(suspended_thread == nullptr);
           suspended_thread = thread;
-          suspended_thread->ModifySuspendCount(self, +1, debug_suspension);
+          suspended_thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
           request_suspension = false;
         } else {
           // If the caller isn't requesting suspension, a suspension should have already occurred.
@@ -697,7 +780,7 @@
           ThreadSuspendByPeerWarning(self, FATAL, "Thread suspension timed out", peer);
           if (suspended_thread != nullptr) {
             CHECK_EQ(suspended_thread, thread);
-            suspended_thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
+            suspended_thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
           }
           *timed_out = true;
           return nullptr;
@@ -766,7 +849,7 @@
             // which will allow this thread to be suspended.
             continue;
           }
-          thread->ModifySuspendCount(self, +1, debug_suspension);
+          thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
           suspended_thread = thread;
         } else {
           CHECK_EQ(suspended_thread, thread);
@@ -795,7 +878,7 @@
         if (total_delay >= MsToNs(kThreadSuspendTimeoutMs)) {
           ThreadSuspendByThreadIdWarning(WARNING, "Thread suspension timed out", thread_id);
           if (suspended_thread != nullptr) {
-            thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
+            thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
           }
           *timed_out = true;
           return nullptr;
@@ -832,25 +915,7 @@
 
   VLOG(threads) << *self << " SuspendAllForDebugger starting...";
 
-  {
-    MutexLock thread_list_mu(self, *Locks::thread_list_lock_);
-    {
-      MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_);
-      // Update global suspend all state for attaching threads.
-      DCHECK_GE(suspend_all_count_, debug_suspend_all_count_);
-      ++suspend_all_count_;
-      ++debug_suspend_all_count_;
-      // Increment everybody's suspend count (except our own).
-      for (const auto& thread : list_) {
-        if (thread == self || thread == debug_thread) {
-          continue;
-        }
-        VLOG(threads) << "requesting thread suspend: " << *thread;
-        thread->ModifySuspendCount(self, +1, true);
-      }
-    }
-  }
-
+  SuspendAllInternal(self, self, debug_thread, true);
   // Block on the mutator lock until all Runnable threads release their share of access then
   // immediately unlock again.
 #if HAVE_TIMED_RWLOCK
@@ -888,7 +953,7 @@
     // to ensure that we're the only one fiddling with the suspend count
     // though.
     MutexLock mu(self, *Locks::thread_suspend_count_lock_);
-    self->ModifySuspendCount(self, +1, true);
+    self->ModifySuspendCount(self, +1, nullptr, true);
     CHECK_GT(self->GetSuspendCount(), 0);
 
     VLOG(threads) << *self << " self-suspending (debugger)";
@@ -972,7 +1037,7 @@
           continue;
         }
         VLOG(threads) << "requesting thread resume: " << *thread;
-        thread->ModifySuspendCount(self, -1, true);
+        thread->ModifySuspendCount(self, -1, nullptr, true);
       }
     }
   }
@@ -1001,7 +1066,7 @@
       if (thread == self || thread->GetDebugSuspendCount() == 0) {
         continue;
       }
-      thread->ModifySuspendCount(self, -thread->GetDebugSuspendCount(), true);
+      thread->ModifySuspendCount(self, -thread->GetDebugSuspendCount(), nullptr, true);
     }
   }
 
@@ -1054,7 +1119,7 @@
       // daemons.
       CHECK(thread->IsDaemon()) << *thread;
       if (thread != self) {
-        thread->ModifySuspendCount(self, +1, false);
+        thread->ModifySuspendCount(self, +1, nullptr, false);
       }
     }
   }
@@ -1095,13 +1160,19 @@
   // Modify suspend count in increments of 1 to maintain invariants in ModifySuspendCount. While
   // this isn't particularly efficient the suspend counts are most commonly 0 or 1.
   for (int delta = debug_suspend_all_count_; delta > 0; delta--) {
-    self->ModifySuspendCount(self, +1, true);
+    self->ModifySuspendCount(self, +1, nullptr, true);
   }
   for (int delta = suspend_all_count_ - debug_suspend_all_count_; delta > 0; delta--) {
-    self->ModifySuspendCount(self, +1, false);
+    self->ModifySuspendCount(self, +1, nullptr, false);
   }
   CHECK(!Contains(self));
   list_.push_back(self);
+  if (kUseReadBarrier) {
+    // Initialize this according to the state of the CC collector.
+    bool weak_ref_access_enabled =
+        Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->IsWeakRefAccessEnabled();
+    self->SetWeakRefAccessEnabled(weak_ref_access_enabled);
+  }
 }
 
 void ThreadList::Unregister(Thread* self) {
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 2c1f813..edd1e05 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -155,6 +155,8 @@
 
   bool Contains(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_);
   bool Contains(pid_t tid) EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_);
+  size_t RunCheckpoint(Closure* checkpoint_function, bool includeSuspended)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_);
 
   void DumpUnattachedThreads(std::ostream& os)
       LOCKS_EXCLUDED(Locks::thread_list_lock_);
@@ -166,6 +168,11 @@
       LOCKS_EXCLUDED(Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
 
+  void SuspendAllInternal(Thread* self, Thread* ignore1, Thread* ignore2 = nullptr,
+                          bool debug_suspend = false)
+      LOCKS_EXCLUDED(Locks::thread_list_lock_,
+                     Locks::thread_suspend_count_lock_);
+
   void AssertThreadsAreSuspended(Thread* self, Thread* ignore1, Thread* ignore2 = nullptr)
       LOCKS_EXCLUDED(Locks::thread_list_lock_,
                      Locks::thread_suspend_count_lock_);
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index 1e84c9d..d8f80fa 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -201,112 +201,4 @@
   return tasks_.size();
 }
 
-WorkStealingWorker::WorkStealingWorker(ThreadPool* thread_pool, const std::string& name,
-                                       size_t stack_size)
-    : ThreadPoolWorker(thread_pool, name, stack_size), task_(nullptr) {}
-
-void WorkStealingWorker::Run() {
-  Thread* self = Thread::Current();
-  Task* task = nullptr;
-  WorkStealingThreadPool* thread_pool = down_cast<WorkStealingThreadPool*>(thread_pool_);
-  while ((task = thread_pool_->GetTask(self)) != nullptr) {
-    WorkStealingTask* stealing_task = down_cast<WorkStealingTask*>(task);
-
-    {
-      CHECK(task_ == nullptr);
-      MutexLock mu(self, thread_pool->work_steal_lock_);
-      // Register that we are running the task
-      ++stealing_task->ref_count_;
-      task_ = stealing_task;
-    }
-    stealing_task->Run(self);
-    // Mark ourselves as not running a task so that nobody tries to steal from us.
-    // There is a race condition that someone starts stealing from us at this point. This is okay
-    // due to the reference counting.
-    task_ = nullptr;
-
-    bool finalize;
-
-    // Steal work from tasks until there is none left to steal. Note: There is a race, but
-    // all that happens when the race occurs is that we steal some work instead of processing a
-    // task from the queue.
-    while (thread_pool->GetTaskCount(self) == 0) {
-      WorkStealingTask* steal_from_task  = nullptr;
-
-      {
-        MutexLock mu(self, thread_pool->work_steal_lock_);
-        // Try finding a task to steal from.
-        steal_from_task = thread_pool->FindTaskToStealFrom();
-        if (steal_from_task != nullptr) {
-          CHECK_NE(stealing_task, steal_from_task)
-              << "Attempting to steal from completed self task";
-          steal_from_task->ref_count_++;
-        } else {
-          break;
-        }
-      }
-
-      if (steal_from_task != nullptr) {
-        // Task which completed earlier is going to steal some work.
-        stealing_task->StealFrom(self, steal_from_task);
-
-        {
-          // We are done stealing from the task, lets decrement its reference count.
-          MutexLock mu(self, thread_pool->work_steal_lock_);
-          finalize = !--steal_from_task->ref_count_;
-        }
-
-        if (finalize) {
-          steal_from_task->Finalize();
-        }
-      }
-    }
-
-    {
-      MutexLock mu(self, thread_pool->work_steal_lock_);
-      // If nobody is still referencing task_ we can finalize it.
-      finalize = !--stealing_task->ref_count_;
-    }
-
-    if (finalize) {
-      stealing_task->Finalize();
-    }
-  }
-}
-
-WorkStealingWorker::~WorkStealingWorker() {}
-
-WorkStealingThreadPool::WorkStealingThreadPool(const char* name, size_t num_threads)
-    : ThreadPool(name, 0),
-      work_steal_lock_("work stealing lock"),
-      steal_index_(0) {
-  while (GetThreadCount() < num_threads) {
-    const std::string worker_name = StringPrintf("Work stealing worker %zu", GetThreadCount());
-    threads_.push_back(new WorkStealingWorker(this, worker_name,
-                                              ThreadPoolWorker::kDefaultStackSize));
-  }
-}
-
-WorkStealingTask* WorkStealingThreadPool::FindTaskToStealFrom() {
-  const size_t thread_count = GetThreadCount();
-  for (size_t i = 0; i < thread_count; ++i) {
-    // TODO: Use CAS instead of lock.
-    ++steal_index_;
-    if (steal_index_ >= thread_count) {
-      steal_index_-= thread_count;
-    }
-
-    WorkStealingWorker* worker = down_cast<WorkStealingWorker*>(threads_[steal_index_]);
-    WorkStealingTask* task = worker->task_;
-    if (task) {
-      // Not null, we can probably steal from this worker.
-      return task;
-    }
-  }
-  // Couldn't find something to steal.
-  return nullptr;
-}
-
-WorkStealingThreadPool::~WorkStealingThreadPool() {}
-
 }  // namespace art
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index 0557708..88700e6 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -144,58 +144,6 @@
   DISALLOW_COPY_AND_ASSIGN(ThreadPool);
 };
 
-class WorkStealingTask : public Task {
- public:
-  WorkStealingTask() : ref_count_(0) {}
-
-  size_t GetRefCount() const {
-    return ref_count_;
-  }
-
-  virtual void StealFrom(Thread* self, WorkStealingTask* source) = 0;
-
- private:
-  // How many people are referencing this task.
-  size_t ref_count_;
-
-  friend class WorkStealingWorker;
-};
-
-class WorkStealingWorker : public ThreadPoolWorker {
- public:
-  virtual ~WorkStealingWorker();
-
-  bool IsRunningTask() const {
-    return task_ != nullptr;
-  }
-
- protected:
-  WorkStealingTask* task_;
-
-  WorkStealingWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size);
-  virtual void Run();
-
- private:
-  friend class WorkStealingThreadPool;
-  DISALLOW_COPY_AND_ASSIGN(WorkStealingWorker);
-};
-
-class WorkStealingThreadPool : public ThreadPool {
- public:
-  explicit WorkStealingThreadPool(const char* name, size_t num_threads);
-  virtual ~WorkStealingThreadPool();
-
- private:
-  Mutex work_steal_lock_;
-  // Which thread we are stealing from (round robin).
-  size_t steal_index_;
-
-  // Find a task to steal from
-  WorkStealingTask* FindTaskToStealFrom() EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_);
-
-  friend class WorkStealingWorker;
-};
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_THREAD_POOL_H_
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 4923342..194d9fe 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1094,7 +1094,7 @@
     ArtMethod* current_method, void* ucontext_ptr) {
 #if __linux__
   // b/18119146
-  if (RUNNING_ON_VALGRIND != 0) {
+  if (RUNNING_ON_MEMORY_TOOL != 0) {
     return;
   }
 
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 66e38b1..f00edff 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -26,7 +26,7 @@
 #include "scoped_thread_state_change.h"
 #include "handle_scope-inl.h"
 
-#include <valgrind.h>
+#include "base/memory_tool.h"
 
 namespace art {
 
@@ -358,7 +358,7 @@
     command.push_back("/usr/bin/id");
   }
   std::string error_msg;
-  if (RUNNING_ON_VALGRIND == 0) {
+  if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
     // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
     EXPECT_TRUE(Exec(command, &error_msg));
   }
@@ -372,7 +372,7 @@
   std::vector<std::string> command;
   command.push_back("bogus");
   std::string error_msg;
-  if (RUNNING_ON_VALGRIND == 0) {
+  if (!(RUNNING_ON_MEMORY_TOOL && kMemoryToolDetectsLeaks)) {
     // Running on valgrind fails due to some memory that leaks in thread alternate signal stacks.
     EXPECT_FALSE(Exec(command, &error_msg));
     EXPECT_NE(0U, error_msg.size());
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 8a8b455..11c3e65 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -349,27 +349,29 @@
   return result;
 }
 
-MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t dex_method_idx,
-                                         const DexFile* dex_file,
-                                         Handle<mirror::DexCache> dex_cache,
-                                         Handle<mirror::ClassLoader> class_loader,
-                                         const DexFile::ClassDef* class_def,
-                                         const DexFile::CodeItem* code_item,
-                                         ArtMethod* method,
-                                         uint32_t method_access_flags) {
+MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self,
+                                                    VariableIndentationOutputStream* vios,
+                                                    uint32_t dex_method_idx,
+                                                    const DexFile* dex_file,
+                                                    Handle<mirror::DexCache> dex_cache,
+                                                    Handle<mirror::ClassLoader> class_loader,
+                                                    const DexFile::ClassDef* class_def,
+                                                    const DexFile::CodeItem* code_item,
+                                                    ArtMethod* method,
+                                                    uint32_t method_access_flags) {
   MethodVerifier* verifier = new MethodVerifier(self, dex_file, dex_cache, class_loader,
                                                 class_def, code_item, dex_method_idx, method,
                                                 method_access_flags, true, true, true, true);
   verifier->Verify();
-  verifier->DumpFailures(os);
-  os << verifier->info_messages_.str();
+  verifier->DumpFailures(vios->Stream());
+  vios->Stream() << verifier->info_messages_.str();
   // Only dump and return if no hard failures. Otherwise the verifier may be not fully initialized
   // and querying any info is dangerous/can abort.
   if (verifier->have_pending_hard_failure_) {
     delete verifier;
     return nullptr;
   } else {
-    verifier->Dump(os);
+    verifier->Dump(vios);
     return verifier;
   }
 }
@@ -1023,12 +1025,21 @@
   }
   /* offset to array data table is a relative branch-style offset */
   array_data = insns + array_data_offset;
-  /* make sure the table is 32-bit aligned */
-  if ((reinterpret_cast<uintptr_t>(array_data) & 0x03) != 0) {
+  // Make sure the table is at an even dex pc, that is, 32-bit aligned.
+  if (!IsAligned<4>(array_data)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unaligned array data table: at " << cur_offset
                                       << ", data offset " << array_data_offset;
     return false;
   }
+  // Make sure the array-data is marked as an opcode. This ensures that it was reached when
+  // traversing the code item linearly. It is an approximation for a by-spec padding value.
+  if (!insn_flags_[cur_offset + array_data_offset].IsOpcode()) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array data table at " << cur_offset
+                                      << ", data offset " << array_data_offset
+                                      << " not correctly visited, probably bad padding.";
+    return false;
+  }
+
   uint32_t value_width = array_data[1];
   uint32_t value_count = *reinterpret_cast<const uint32_t*>(&array_data[2]);
   uint32_t table_size = 4 + (value_width * value_count + 1) / 2;
@@ -1126,12 +1137,21 @@
   }
   /* offset to switch table is a relative branch-style offset */
   const uint16_t* switch_insns = insns + switch_offset;
-  /* make sure the table is 32-bit aligned */
-  if ((reinterpret_cast<uintptr_t>(switch_insns) & 0x03) != 0) {
+  // Make sure the table is at an even dex pc, that is, 32-bit aligned.
+  if (!IsAligned<4>(switch_insns)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unaligned switch table: at " << cur_offset
                                       << ", switch offset " << switch_offset;
     return false;
   }
+  // Make sure the switch data is marked as an opcode. This ensures that it was reached when
+  // traversing the code item linearly. It is an approximation for a by-spec padding value.
+  if (!insn_flags_[cur_offset + switch_offset].IsOpcode()) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "switch table at " << cur_offset
+                                      << ", switch offset " << switch_offset
+                                      << " not correctly visited, probably bad padding.";
+    return false;
+  }
+
   uint32_t switch_count = switch_insns[1];
   int32_t keys_offset, targets_offset;
   uint16_t expected_signature;
@@ -1262,32 +1282,36 @@
 }
 
 void MethodVerifier::Dump(std::ostream& os) {
+  VariableIndentationOutputStream vios(&os);
+  Dump(&vios);
+}
+
+void MethodVerifier::Dump(VariableIndentationOutputStream* vios) {
   if (code_item_ == nullptr) {
-    os << "Native method\n";
+    vios->Stream() << "Native method\n";
     return;
   }
   {
-    os << "Register Types:\n";
-    Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-    std::ostream indent_os(&indent_filter);
-    reg_types_.Dump(indent_os);
+    vios->Stream() << "Register Types:\n";
+    ScopedIndentation indent1(vios);
+    reg_types_.Dump(vios->Stream());
   }
-  os << "Dumping instructions and register lines:\n";
-  Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
-  std::ostream indent_os(&indent_filter);
+  vios->Stream() << "Dumping instructions and register lines:\n";
+  ScopedIndentation indent1(vios);
   const Instruction* inst = Instruction::At(code_item_->insns_);
   for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
       dex_pc += inst->SizeInCodeUnits()) {
     RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
     if (reg_line != nullptr) {
-      indent_os << reg_line->Dump(this) << "\n";
+      vios->Stream() << reg_line->Dump(this) << "\n";
     }
-    indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].ToString() << " ";
+    vios->Stream()
+        << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].ToString() << " ";
     const bool kDumpHexOfInstruction = false;
     if (kDumpHexOfInstruction) {
-      indent_os << inst->DumpHex(5) << " ";
+      vios->Stream() << inst->DumpHex(5) << " ";
     }
-    indent_os << inst->DumpString(dex_file_) << "\n";
+    vios->Stream() << inst->DumpString(dex_file_) << "\n";
     inst = inst->Next();
   }
 }
@@ -4115,7 +4139,9 @@
                     << " to be compatible with type '" << insn_type
                     << "' but found type '" << *field_type
                     << "' in get-object";
-        work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        if (error != VERIFY_ERROR_BAD_CLASS_HARD) {
+          work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        }
         return;
       }
     }
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 2550694..d933448 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -32,6 +32,7 @@
 class Instruction;
 struct ReferenceMap2Visitor;
 class Thread;
+class VariableIndentationOutputStream;
 
 namespace verifier {
 
@@ -157,7 +158,9 @@
                                  bool allow_soft_failures, std::string* error)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static MethodVerifier* VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t method_idx,
+  static MethodVerifier* VerifyMethodAndDump(Thread* self,
+                                             VariableIndentationOutputStream* vios,
+                                             uint32_t method_idx,
                                              const DexFile* dex_file,
                                              Handle<mirror::DexCache> dex_cache,
                                              Handle<mirror::ClassLoader> class_loader,
@@ -191,6 +194,7 @@
   // Dump the state of the verifier, namely each instruction, what flags are set on it, register
   // information
   void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void Dump(VariableIndentationOutputStream* vios) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
   // to the locks held at 'dex_pc' in method 'm'.
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index c8aa4fd..9c52819 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -583,16 +583,20 @@
 
 const RegType& RegType::Merge(const RegType& incoming_type, RegTypeCache* reg_types) const {
   DCHECK(!Equals(incoming_type));  // Trivial equality handled by caller
-  // Perform pointer equality tests for conflict to avoid virtual method dispatch.
+  // Perform pointer equality tests for undefined and conflict to avoid virtual method dispatch.
+  const UndefinedType& undefined = reg_types->Undefined();
   const ConflictType& conflict = reg_types->Conflict();
-  if (this == &conflict) {
-    DCHECK(IsConflict());
-    return *this;  // Conflict MERGE * => Conflict
-  } else if (&incoming_type == &conflict) {
-    DCHECK(incoming_type.IsConflict());
-    return incoming_type;  // * MERGE Conflict => Conflict
-  } else if (IsUndefined() || incoming_type.IsUndefined()) {
-    return conflict;  // Unknown MERGE * => Conflict
+  DCHECK_EQ(this == &undefined, IsUndefined());
+  DCHECK_EQ(&incoming_type == &undefined, incoming_type.IsUndefined());
+  DCHECK_EQ(this == &conflict, IsConflict());
+  DCHECK_EQ(&incoming_type == &conflict, incoming_type.IsConflict());
+  if (this == &undefined || &incoming_type == &undefined) {
+    // There is a difference between undefined and conflict. Conflicts may be copied around, but
+    // not used. Undefined registers must not be copied. So any merge with undefined should return
+    // undefined.
+    return undefined;
+  } else if (this == &conflict || &incoming_type == &conflict) {
+    return conflict;  // (Conflict MERGE *) or (* MERGE Conflict) => Conflict
   } else if (IsConstant() && incoming_type.IsConstant()) {
     const ConstantType& type1 = *down_cast<const ConstantType*>(this);
     const ConstantType& type2 = *down_cast<const ConstantType*>(&incoming_type);
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 244deed..9cd2bdf 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -38,10 +38,9 @@
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
         << new_type << "'";
     return false;
-  } else if (new_type.IsConflict()) {  // should only be set during a merge
-    verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
-    return false;
   } else {
+    // Note: previously we failed when asked to set a conflict. However, conflicts are OK as long
+    //       as they are not accessed, and our backends can handle this nowadays.
     line_[vdst] = new_type.GetId();
   }
   // Clear the monitor entry bits for this register.
@@ -93,8 +92,9 @@
   if (!SetRegisterType(verifier, vdst, type)) {
     return;
   }
-  if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
-      (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
+  if (!type.IsConflict() &&                                  // Allow conflicts to be copied around.
+      ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
+       (cat == kTypeCategoryRef && !type.IsReferenceTypes()))) {
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
                                                  << " cat=" << static_cast<int>(cat);
   } else if (cat == kTypeCategoryRef) {
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
index 11f44fe..b9e37a1 100644
--- a/sigchainlib/Android.mk
+++ b/sigchainlib/Android.mk
@@ -76,3 +76,19 @@
 LOCAL_LDLIBS = -ldl
 LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
+
+# Create a dummy version of libsigchain which expose the necessary symbols
+# but throws when called. This can be used to get static binaries which don't
+# need the real functionality of the sig chain but need to please the linker.
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+LOCAL_MODULE_TAGS := optional
+LOCAL_IS_HOST_MODULE := true
+LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+LOCAL_CLANG = $(ART_HOST_CLANG)
+LOCAL_SRC_FILES := sigchain_dummy.cc
+LOCAL_MODULE:= libsigchain_dummy
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_LDLIBS = -ldl
+LOCAL_MULTILIB := both
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index f909fb2..faa2983 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -22,5 +22,10 @@
 rm classes/UnresClass.class
 ${JAVAC} -d classes `find src2 -name '*.java'`
 
-${DX} -JXmx256m --debug --dex --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+  fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index ca256ec..db0dd32 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -626,3 +626,7 @@
   assert(strcmp(test_array, chars6) == 0);
   env->ReleaseStringUTFChars(s6, chars6);
 }
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_testGetMethodID(JNIEnv* env, jclass, jclass c) {
+  return reinterpret_cast<jlong>(env->GetMethodID(c, "a", "()V"));
+}
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java
index ac20417..810dda0 100644
--- a/test/004-JniTest/src/Main.java
+++ b/test/004-JniTest/src/Main.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 
 public class Main {
     public static void main(String[] args) {
@@ -35,6 +37,7 @@
         testCallNonvirtual();
         testNewStringObject();
         testRemoveLocalObject();
+        testProxyGetMethodID();
     }
 
     private static native void testFindClassOnAttachedNativeThread();
@@ -194,6 +197,31 @@
     private static native void testCallNonvirtual();
 
     private static native void testNewStringObject();
+
+    private interface SimpleInterface {
+        void a();
+    }
+
+    private static class DummyInvocationHandler implements InvocationHandler {
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            return null;
+        }
+    }
+
+    private static void testProxyGetMethodID() {
+        InvocationHandler handler = new DummyInvocationHandler();
+        SimpleInterface proxy =
+                (SimpleInterface) Proxy.newProxyInstance(SimpleInterface.class.getClassLoader(),
+                        new Class[] {SimpleInterface.class}, handler);
+        if (testGetMethodID(SimpleInterface.class) == 0) {
+            throw new AssertionError();
+        }
+        if (testGetMethodID(proxy.getClass()) == 0) {
+            throw new AssertionError();
+        }
+    }
+
+    private static native long testGetMethodID(Class<?> c);
 }
 
 class JniCallNonvirtualTest {
diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/004-ReferenceMap/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/004-StackWalk/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/005-annotations/build b/test/005-annotations/build
index 2474055..3f00a1a 100644
--- a/test/005-annotations/build
+++ b/test/005-annotations/build
@@ -25,4 +25,12 @@
 # ...but not at run time.
 rm 'classes/android/test/anno/MissingAnnotation.class'
 rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class'
-${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
+
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+fi
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/011-array-copy/src/Main.java b/test/011-array-copy/src/Main.java
index 505d8b0..96e1dbf 100644
--- a/test/011-array-copy/src/Main.java
+++ b/test/011-array-copy/src/Main.java
@@ -23,6 +23,7 @@
     public static void main(String args[]) {
         testObjectCopy();
         testOverlappingMoves();
+        testFloatAndDouble();
     }
 
     public static void testObjectCopy() {
@@ -143,4 +144,13 @@
         /* copy forward, mixed alignment, trivial length */
         makeCopies(0, 5, 1);
     }
+
+    private static void testFloatAndDouble() {
+        // Float & double copies have the same implementation as int & long. However, there are
+        // protective DCHECKs in the code (there is nothing unifying like ByteSizedArray or
+        // ShortSizedArray). Just test that we don't fail those checks.
+        final int len = 10;
+        System.arraycopy(new float[len], 0, new float[len], 0, len);
+        System.arraycopy(new double[len], 0, new double[len], 0, len);
+    }
 }
diff --git a/test/022-interface/build b/test/022-interface/build
index c86b1dc..3f8915c 100644
--- a/test/022-interface/build
+++ b/test/022-interface/build
@@ -19,5 +19,11 @@
 
 # Use classes that are compiled with ecj that exposes an invokeinterface
 # issue when interfaces override methods in Object
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index ad42a2d..3bb6747 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -21,8 +21,14 @@
 gcc -Wall -Werror -o iface-gen iface-gen.c
 ./iface-gen
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  # Use the default Jack commands
+  ./default-build
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+  # dx needs more memory for that test so do not pass Xmx option here.
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+  zip $TEST_NAME.jar classes.dex
+fi
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index 8c7c27d..0de56f9 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -68,14 +68,17 @@
         return s[0];
     }
 
+    private static void printWeakReference(WeakReference<FinalizerTest> wimp) {
+        // Reference ft so we are sure the WeakReference cannot be cleared.
+        FinalizerTest keepLive = wimp.get();
+        System.out.println("wimp: " + wimpString(wimp));
+    }
+
     public static void main(String[] args) {
         WeakReference<FinalizerTest> wimp = makeRef();
-        FinalizerTest keepLive = wimp.get();
-
-        System.out.println("wimp: " + wimpString(wimp));
+        printWeakReference(wimp);
 
         /* this will try to collect and finalize ft */
-        keepLive = null;
         System.out.println("gc");
         Runtime.getRuntime().gc();
 
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index ef286d1..ae42519 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -39,8 +39,13 @@
     printf("}\n") > fileName;
 }'
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes
+  ${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
index 238e73a..f947d0b 100644
--- a/test/074-gc-thrash/src/Main.java
+++ b/test/074-gc-thrash/src/Main.java
@@ -218,17 +218,7 @@
             return;
         }
 
-        /*
-         * Check the results of the last trip through.  Everything in
-         * "weak" should be matched in "strong", and the two should be
-         * equivalent (object-wise, not just string-equality-wise).
-         */
-        for (int i = 0; i < MAX_DEPTH; i++) {
-            if (strong[i] != weak[i].get()) {
-                System.err.println("Deep: " + i + " strong=" + strong[i] +
-                    ", weak=" + weak[i].get());
-            }
-        }
+        checkStringReferences();
 
         /*
          * Wipe "strong", do a GC, see if "weak" got collected.
@@ -248,6 +238,26 @@
             System.out.println("Deep: iters=" + iter / MAX_DEPTH);
     }
 
+
+    /**
+     * Check the results of the last trip through.  Everything in
+     * "weak" should be matched in "strong", and the two should be
+     * equivalent (object-wise, not just string-equality-wise).
+     *
+     * We do that check in a separate method to avoid retaining these
+     * String references in local DEX registers. In interpreter mode,
+     * they would retain these references until the end of the method
+     * or until they are updated to another value.
+     */
+    private static void checkStringReferences() {
+      for (int i = 0; i < MAX_DEPTH; i++) {
+          if (strong[i] != weak[i].get()) {
+              System.err.println("Deep: " + i + " strong=" + strong[i] +
+                  ", weak=" + weak[i].get());
+          }
+      }
+    }
+
     /**
      * Recursively dive down, setting one or more local variables.
      *
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 4dfa73c..177c5a4 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -1000,6 +1000,45 @@
     Assert.assertEquals(Long.reverse(0x8765432187654321L), 0x84c2a6e184c2a6e1L);
     Assert.assertEquals(Long.reverse(Long.MAX_VALUE), 0xfffffffffffffffeL);
     Assert.assertEquals(Long.reverse(Long.MIN_VALUE), 1L);
+
+    Assert.assertEquals(test_Long_reverse_b22324327(0xaaaaaaaaaaaaaaaaL, 0x5555555555555555L),
+            157472205507277347L);
+  }
+
+  // A bit more complicated than the above. Use local variables to stress register allocation.
+  private static long test_Long_reverse_b22324327(long l1, long l2) {
+    // A couple of local integers. Use them in a loop, so they get promoted.
+    int i1 = 0, i2 = 1, i3 = 2, i4 = 3, i5 = 4, i6 = 5, i7 = 6, i8 = 7;
+    for (int k = 0; k < 10; k++) {
+      i1 += 1;
+      i2 += 2;
+      i3 += 3;
+      i4 += 4;
+      i5 += 5;
+      i6 += 6;
+      i7 += 7;
+      i8 += 8;
+    }
+
+    // Do the Long.reverse() calls, save the results.
+    long r1 = Long.reverse(l1);
+    long r2 = Long.reverse(l2);
+
+    // Some more looping with the ints.
+    for (int k = 0; k < 10; k++) {
+      i1 += 1;
+      i2 += 2;
+      i3 += 3;
+      i4 += 4;
+      i5 += 5;
+      i6 += 6;
+      i7 += 7;
+      i8 += 8;
+    }
+
+    // Include everything in the result, so things are kept live. Try to be a little bit clever to
+    // avoid things being folded somewhere.
+    return (r1 / i1) + (r2 / i2) + i3 + i4 + i5 + i6 + i7 + i8;
   }
 
   static Object runtime;
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index 963d6b3..6f50a76 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -22,7 +22,12 @@
 mkdir classes
 ${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
 
-# Suppress stderr to keep the inner class warnings out of the expected output.
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  # Suppress stderr to keep the inner class warnings out of the expected output.
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
+fi
 
 zip $TEST_NAME.jar classes.dex
diff --git a/test/089-many-methods/build b/test/089-many-methods/build
index 7ede759..ff77c60 100644
--- a/test/089-many-methods/build
+++ b/test/089-many-methods/build
@@ -43,7 +43,8 @@
     printf("}\n") > fileName;
 }'
 
+# The test relies on the error message produced by dx, not jack, so keep building with dx for now
+# (b/19467889).
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 ${DX} -JXmx1024m --dex --no-optimize classes
-
diff --git a/test/097-duplicate-method/build b/test/097-duplicate-method/build
index 6576779..a855873 100644
--- a/test/097-duplicate-method/build
+++ b/test/097-duplicate-method/build
@@ -18,8 +18,19 @@
 set -e
 
 mkdir classes
-${JAVAC} -d classes src/*.java
-${JASMIN} -d classes src/*.j
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-jack src.jack src
+
+  ${JASMIN} -d classes src/*.j
+  ${JILL} classes --output jasmin.jack
+
+  # We set jack.import.type.policy=keep-first to consider class definitions from jasmin first.
+  ${JACK} --import jasmin.jack --import src.jack -D jack.import.type.policy=keep-first --output-dex .
+else
+  ${JAVAC} -d classes src/*.java
+  ${JASMIN} -d classes src/*.j
+
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/099-vmdebug/expected.txt b/test/099-vmdebug/expected.txt
index 579f98f..b8d72f6 100644
--- a/test/099-vmdebug/expected.txt
+++ b/test/099-vmdebug/expected.txt
@@ -17,3 +17,9 @@
 Got expected exception
 Test sampling with bogus (<= 0) interval
 Got expected exception
+Instances of ClassA 2
+Instances of ClassB 1
+Instances of null 0
+Instances of ClassA assignable 3
+Array counts [2, 1, 0]
+Array counts assignable [3, 1, 0]
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index add2ff6..1be5765 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -17,6 +17,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Map;
 
 public class Main {
@@ -30,7 +32,9 @@
             return;
         }
         testMethodTracing();
+        testCountInstances();
         testRuntimeStat();
+        testRuntimeStats();
     }
 
     private static File createTempFile() throws Exception {
@@ -220,12 +224,39 @@
         checkHistogram(blocking_gc_count_rate_histogram);
     }
 
+    static class ClassA { }
+    static class ClassB { }
+    static class ClassC extends ClassA { }
+
+    private static void testCountInstances() throws Exception {
+        ArrayList<Object> l = new ArrayList<Object>();
+        l.add(new ClassA());
+        l.add(new ClassB());
+        l.add(new ClassA());
+        l.add(new ClassC());
+        Runtime.getRuntime().gc();
+        System.out.println("Instances of ClassA " +
+                VMDebug.countInstancesofClass(ClassA.class, false));
+        System.out.println("Instances of ClassB " +
+                VMDebug.countInstancesofClass(ClassB.class, false));
+        System.out.println("Instances of null " + VMDebug.countInstancesofClass(null, false));
+        System.out.println("Instances of ClassA assignable " +
+                VMDebug.countInstancesofClass(ClassA.class, true));
+        Class[] classes = new Class[]{ClassA.class, ClassB.class, null};
+        long[] counts = VMDebug.countInstancesofClasses(classes, false);
+        System.out.println("Array counts " + Arrays.toString(counts));
+        counts = VMDebug.countInstancesofClasses(classes, true);
+        System.out.println("Array counts assignable " + Arrays.toString(counts));
+    }
+
     private static class VMDebug {
         private static final Method startMethodTracingMethod;
         private static final Method stopMethodTracingMethod;
         private static final Method getMethodTracingModeMethod;
         private static final Method getRuntimeStatMethod;
         private static final Method getRuntimeStatsMethod;
+        private static final Method countInstancesOfClassMethod;
+        private static final Method countInstancesOfClassesMethod;
         static {
             try {
                 Class c = Class.forName("dalvik.system.VMDebug");
@@ -235,6 +266,10 @@
                 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode");
                 getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class);
                 getRuntimeStatsMethod = c.getDeclaredMethod("getRuntimeStats");
+                countInstancesOfClassMethod = c.getDeclaredMethod("countInstancesOfClass",
+                        Class.class, Boolean.TYPE);
+                countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses",
+                        Class[].class, Boolean.TYPE);
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
@@ -257,5 +292,13 @@
         public static Map<String, String> getRuntimeStats() throws Exception {
             return (Map<String, String>) getRuntimeStatsMethod.invoke(null);
         }
+        public static long countInstancesofClass(Class c, boolean assignable) throws Exception {
+            return (long) countInstancesOfClassMethod.invoke(null, new Object[]{c, assignable});
+        }
+        public static long[] countInstancesofClasses(Class[] classes, boolean assignable)
+                throws Exception {
+            return (long[]) countInstancesOfClassesMethod.invoke(
+                    null, new Object[]{classes, assignable});
+        }
     }
 }
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
index c21a9ef..e772fb8 100644
--- a/test/111-unresolvable-exception/build
+++ b/test/111-unresolvable-exception/build
@@ -21,5 +21,10 @@
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/TestException.class
 
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/113-multidex/build b/test/113-multidex/build
index ec8706e..8ef5c0e 100644
--- a/test/113-multidex/build
+++ b/test/113-multidex/build
@@ -17,16 +17,32 @@
 # Stop if something fails.
 set -e
 
-mkdir classes
-
 # All except Main
+mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/Main.class
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 
 # Only Main
-${JAVAC} -d classes `find src -name '*.java'`
-rm classes/Second.class classes/FillerA.class classes/FillerB.class classes/Inf*.class
-${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+mkdir classes2
+${JAVAC} -d classes2 `find src -name '*.java'`
+rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/Inf*.class
 
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes2 --output classes2.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  mv classes.dex classes-1.dex
+  ${JACK} --import classes2.jack --output-dex .
+  mv classes.dex classes2.dex
+  mv classes-1.dex classes.dex
+else
+  # All except Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+  # Only Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+fi
 zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 46029cf..159dd5c 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -53,20 +53,21 @@
         }
 
         // Allocate objects to definitely run GC before quitting.
-        ArrayList<Object> l = new ArrayList<Object>();
-        try {
-            for (int i = 0; i < 100000; i++) {
-                l.add(new ArrayList<Object>(i));
-            }
-        } catch (OutOfMemoryError oom) {
-        }
-        // Make the (outer) ArrayList unreachable. Note it may still
-        // be reachable under an interpreter or a compiler without a
-        // liveness analysis.
-        l = null;
+        allocateObjectsToRunGc();
+
         new ArrayList<Object>(50);
     }
 
+    private static void allocateObjectsToRunGc() {
+      ArrayList<Object> l = new ArrayList<Object>();
+      try {
+          for (int i = 0; i < 100000; i++) {
+              l.add(new ArrayList<Object>(i));
+          }
+      } catch (OutOfMemoryError oom) {
+      }
+    }
+
     private Main(CyclicBarrier startBarrier) {
         this.startBarrier = startBarrier;
     }
diff --git a/test/121-modifiers/build b/test/121-modifiers/build
index d73be86..85b69e9 100644
--- a/test/121-modifiers/build
+++ b/test/121-modifiers/build
@@ -30,5 +30,11 @@
 # mv NonInf.out classes/NonInf.class
 # mv Main.class A.class A\$B.class A\$C.class classes/
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  # Workaround b/19561685: disable sanity checks to produce a DEX file with invalid modifiers.
+  ${JACK} --sanity-checks off --import classes.jack --output-dex .
+else
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build
index 62e57c8..b92ecf9 100644
--- a/test/124-missing-classes/build
+++ b/test/124-missing-classes/build
@@ -25,4 +25,11 @@
 # ...but not at run time.
 rm 'classes/MissingClass.class'
 rm 'classes/Main$MissingInnerClass.class'
-${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
+
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+fi
+zip $TEST_NAME.jar classes.dex
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
index 4c30f3f..b7f2118 100644
--- a/test/126-miranda-multidex/build
+++ b/test/126-miranda-multidex/build
@@ -17,16 +17,32 @@
 # Stop if something fails.
 set -e
 
+# All except MirandaInterface
 mkdir classes
-
-# All except Main
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/MirandaInterface.class
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 
-# Only Main
-${JAVAC} -d classes `find src -name '*.java'`
-rm classes/Main.class classes/MirandaAbstract.class classes/MirandaClass*.class classes/MirandaInterface2*.class
-${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+# Only MirandaInterface
+mkdir classes2
+${JAVAC} -d classes2 `find src -name '*.java'`
+rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.class classes2/MirandaInterface2*.class
 
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes2 --output classes2.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  mv classes.dex classes-1.dex
+  ${JACK} --import classes2.jack --output-dex .
+  mv classes.dex classes2.dex
+  mv classes-1.dex classes.dex
+else
+  # All except Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+  # Only Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+fi
 zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/127-secondarydex/build b/test/127-secondarydex/build
index 712774f..0d9f4d6 100755
--- a/test/127-secondarydex/build
+++ b/test/127-secondarydex/build
@@ -23,9 +23,21 @@
 mkdir classes-ex
 mv classes/Super.class classes-ex
 
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes-ex --output classes-ex.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  ${JACK} --import classes-ex.jack --output-dex .
   zip ${TEST_NAME}-ex.jar classes.dex
+else
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
 fi
diff --git a/test/131-structural-change/build b/test/131-structural-change/build
index 7ddc81d..ff0da20 100755
--- a/test/131-structural-change/build
+++ b/test/131-structural-change/build
@@ -17,15 +17,23 @@
 # Stop if something fails.
 set -e
 
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-${JAVAC} -d classes-ex `find src-ex -name '*.java'`
-
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+
+  ${JACK} --output-dex . src-ex
   zip ${TEST_NAME}-ex.jar classes.dex
+else
+  mkdir classes
+  ${JAVAC} -d classes `find src -name '*.java'`
+
+  mkdir classes-ex
+  ${JAVAC} -d classes-ex `find src-ex -name '*.java'`
+
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
 fi
diff --git a/test/140-dce-regression/expected.txt b/test/140-dce-regression/expected.txt
new file mode 100644
index 0000000..863339f
--- /dev/null
+++ b/test/140-dce-regression/expected.txt
@@ -0,0 +1 @@
+Passed
diff --git a/test/140-dce-regression/info.txt b/test/140-dce-regression/info.txt
new file mode 100644
index 0000000..de6ad34
--- /dev/null
+++ b/test/140-dce-regression/info.txt
@@ -0,0 +1 @@
+Regression test for quick dead code elimination.
diff --git a/test/140-dce-regression/src/Main.java b/test/140-dce-regression/src/Main.java
new file mode 100644
index 0000000..f255029
--- /dev/null
+++ b/test/140-dce-regression/src/Main.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+public class Main {
+
+    public static void testArrayLength() {
+      int[] arr = null;
+      int len = 0;
+      try {
+        len = arr.length;
+        len = 5;
+      } catch (NullPointerException npe) {
+        System.out.println("Passed");
+      }
+    }
+
+    public static void main(String[] args) {
+      testArrayLength();
+    }
+}
diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build
index 789d38e..5ff73ec 100644
--- a/test/303-verification-stress/build
+++ b/test/303-verification-stress/build
@@ -21,8 +21,14 @@
 gcc -Wall -Werror -o classes-gen classes-gen.c
 ./classes-gen
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  # Use the default Jack commands
+  ./default-build
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} --debug --dex --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+  # dx needs more memory for that test so do not pass Xmx option here.
+  ${DX} --debug --dex --output=classes.dex classes
+  zip $TEST_NAME.jar classes.dex
+fi
diff --git a/test/454-get-vreg/build b/test/454-get-vreg/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/454-get-vreg/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/463-checker-boolean-simplifier/src/Main.java b/test/463-checker-boolean-simplifier/src/Main.java
index 0b75930..dd17e77 100644
--- a/test/463-checker-boolean-simplifier/src/Main.java
+++ b/test/463-checker-boolean-simplifier/src/Main.java
@@ -119,9 +119,6 @@
   /// CHECK-DAG:     <<Cond:z\d+>>     LessThan [<<ParamX>>,<<ParamY>>]
   /// CHECK-DAG:                       Return [<<Cond>>]
 
-  /// CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
-  /// CHECK-NOT:                       GreaterThanOrEqual
-
   public static boolean LessThan(int x, int y) {
     return (x < y) ? true : false;
   }
diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java
index a4280de..18125fa 100644
--- a/test/482-checker-loop-back-edge-use/src/Main.java
+++ b/test/482-checker-loop-back-edge-use/src/Main.java
@@ -36,11 +36,11 @@
   }
 
   /// CHECK-START: void Main.loop3(boolean) liveness (after)
-  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,64)} uses:[60,64]
-  /// CHECK:         Goto            liveness:62
+  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,60)} uses:[56,60]
+  /// CHECK:         Goto            liveness:58
 
-  /// CHECK-START: void Main.loop3(boolean) liveness (after)
-  /// CHECK-NOT:     Goto liveness:56
+  // CHECK-START: void Main.loop3(boolean) liveness (after)
+  // CHECK-NOT:     Goto liveness:50
   public static void loop3(boolean incoming) {
     // 'incoming' only needs a use at the outer loop's back edge.
     while (System.currentTimeMillis() != 42) {
@@ -49,11 +49,11 @@
     }
   }
 
-  /// CHECK-START: void Main.loop4(boolean) liveness (after)
-  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,24)} uses:[24]
+  // CHECK-START: void Main.loop4(boolean) liveness (after)
+  // CHECK:         ParameterValue  liveness:4  ranges:{[4,22)} uses:[22]
 
-  /// CHECK-START: void Main.loop4(boolean) liveness (after)
-  /// CHECK-NOT:     Goto            liveness:22
+  // CHECK-START: void Main.loop4(boolean) liveness (after)
+  // CHECK-NOT:     Goto            liveness:18
   public static void loop4(boolean incoming) {
     // 'incoming' has no loop use, so should not have back edge uses.
     System.out.println(incoming);
diff --git a/test/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
index 95708a2..2274ba4 100644
--- a/test/510-checker-try-catch/smali/Builder.smali
+++ b/test/510-checker-try-catch/smali/Builder.smali
@@ -630,6 +630,172 @@
     goto :return
 .end method
 
+## CHECK-START: int Builder.testSwitchTryEnter(int, int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BPSwitch0:B\d+>>"
+
+## CHECK:  name             "<<BPSwitch0>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BEnterTry2:B\d+>>" "<<BPSwitch1:B\d+>>"
+## CHECK:  If
+
+## CHECK:  name             "<<BPSwitch1>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BOutside:B\d+>>" "<<BEnterTry1:B\d+>>"
+## CHECK:  If
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BTry2:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry2>>"
+## CHECK:  predecessors     "<<BEnterTry2>>" "<<BTry1>>"
+## CHECK:  successors       "<<BExitTry:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BOutside>>"
+## CHECK:  predecessors     "<<BPSwitch1>>" "<<BExitTry>>"
+## CHECK:  successors       "<<BCatchReturn:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BCatchReturn>>"
+## CHECK:  predecessors     "<<BOutside>>" "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  Return
+
+## CHECK:  name             "<<BEnterTry1>>"
+## CHECK:  predecessors     "<<BPSwitch1>>"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testSwitchTryEnter(IIII)I
+    .registers 4
+
+    packed-switch p0, :pswitch_data
+
+    :try_start
+    div-int/2addr p0, p1
+
+    :pswitch1
+    div-int/2addr p0, p2
+    goto :pswitch2
+
+    :pswitch_data
+    .packed-switch 0x0
+        :pswitch1
+        :pswitch2
+    .end packed-switch
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :pswitch2
+    div-int/2addr p0, p3
+
+    :catch_all
+    return p0
+.end method
+
+## CHECK-START: int Builder.testSwitchTryExit(int, int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
+
+## CHECK:  name             "<<BPSwitch0:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BTry2:B\d+>>" "<<BExitTry1:B\d+>>"
+## CHECK:  If
+
+## CHECK:  name             "<<BPSwitch1:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BOutside:B\d+>>" "<<BEnterTry2:B\d+>>"
+## CHECK:  If
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry2>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BExitTry2:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BOutside>>"
+## CHECK:  predecessors     "<<BPSwitch1>>" "<<BExitTry2>>"
+## CHECK:  successors       "<<BCatchReturn:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BCatchReturn>>"
+## CHECK:  predecessors     "<<BOutside>>" "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2>>" "<<BExitTry2>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  Return
+
+## CHECK:  name             "<<BEnterTry1>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BPSwitch0>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BPSwitch1>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BPSwitch1>>"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testSwitchTryExit(IIII)I
+    .registers 4
+
+    :try_start
+    div-int/2addr p0, p1
+    packed-switch p0, :pswitch_data
+
+    div-int/2addr p0, p1
+
+    :pswitch1
+    div-int/2addr p0, p2
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :pswitch2
+    div-int/2addr p0, p3
+
+    :catch_all
+    return p0
+
+    :pswitch_data
+    .packed-switch 0x0
+        :pswitch1
+        :pswitch2
+    .end packed-switch
+.end method
+
 # Test that a TryBoundary is inserted between a Throw instruction and the exit
 # block when covered by a try range.
 
@@ -650,6 +816,10 @@
 ## CHECK:  flags            "catch_block"
 ## CHECK:  StoreLocal       [v0,<<Minus1>>]
 
+## CHECK:  name             "<<BExit>>"
+## CHECK:  predecessors     "<<BExitTry>>" "<<BCatch>>"
+## CHECK:  Exit
+
 ## CHECK:  name             "<<BEnterTry>>"
 ## CHECK:  predecessors     "B0"
 ## CHECK:  successors       "<<BTry>>"
@@ -662,10 +832,6 @@
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
-## CHECK:  name             "<<BExit>>"
-## CHECK:  predecessors     "<<BExitTry>>" "<<BCatch>>"
-## CHECK:  Exit
-
 .method public static testThrow(Ljava/lang/Exception;)I
     .registers 2
 
@@ -693,6 +859,9 @@
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
+
+## CHECK:  name             "<<BExit>>"
 
 ## CHECK:  name             "<<BTry:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry>>"
@@ -745,6 +914,14 @@
 ## CHECK:  name             "<<BReturn:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry2>>"
 
+## CHECK:  name             "{{B\d+}}"
+## CHECK:  Exit
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BExitTry2>>"
+## CHECK:  Div
+
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "B0"
 ## CHECK:  successors       "<<BTry1>>"
@@ -757,11 +934,6 @@
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
-## CHECK:  name             "<<BTry2:B\d+>>"
-## CHECK:  predecessors     "<<BEnterTry2>>"
-## CHECK:  successors       "<<BExitTry2>>"
-## CHECK:  Div
-
 ## CHECK:  name             "<<BEnterTry2>>"
 ## CHECK:  predecessors     "<<BCatch>>"
 ## CHECK:  successors       "<<BTry2>>"
@@ -797,48 +969,51 @@
 ## CHECK:  successors       "<<BCatch1:B\d+>>"
 
 ## CHECK:  name             "<<BCatch1>>"
-## CHECK:  predecessors     "B0" "<<BEnter2:B\d+>>" "<<BExit2:B\d+>>"
-## CHECK:  successors       "<<BEnter1:B\d+>>"
+## CHECK:  predecessors     "B0" "<<BEnterTry2:B\d+>>" "<<BExitTry2:B\d+>>"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BCatch2:B\d+>>"
-## CHECK:  predecessors     "<<BExit1:B\d+>>" "<<BEnter1>>" "<<BExit1>>"
-## CHECK:  successors       "<<BEnter2>>"
+## CHECK:  predecessors     "<<BExitTry1:B\d+>>" "<<BEnterTry1>>" "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExit2>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
 ## CHECK:  Return
 
+## CHECK:  name             "<<BExit>>"
+
 ## CHECK:  name             "<<BTry1:B\d+>>"
-## CHECK:  predecessors     "<<BEnter1>>"
-## CHECK:  successors       "<<BExit1>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BExitTry1>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BEnter1>>"
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BExitTry2>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "<<BCatch1>>"
 ## CHECK:  successors       "<<BTry1>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:entry
 
-## CHECK:  name             "<<BExit1>>"
+## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
 ## CHECK:  successors       "<<BCatch2>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:exit
 
-## CHECK:  name             "<<BTry2:B\d+>>"
-## CHECK:  predecessors     "<<BEnter2>>"
-## CHECK:  successors       "<<BExit2>>"
-## CHECK:  Div
-
-## CHECK:  name             "<<BEnter2>>"
+## CHECK:  name             "<<BEnterTry2>>"
 ## CHECK:  predecessors     "<<BCatch2>>"
 ## CHECK:  successors       "<<BTry2>>"
 ## CHECK:  xhandlers        "<<BCatch1>>"
 ## CHECK:  TryBoundary      kind:entry
 
-## CHECK:  name             "<<BExit2>>"
+## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  xhandlers        "<<BCatch1>>"
@@ -972,3 +1147,29 @@
     :try_end
     .catchall {:try_start .. :try_end} :catch_all
 .end method
+
+## CHECK-START: int Builder.testSynchronized(java.lang.Object) builder (after)
+## CHECK:      flags "catch_block"
+## CHECK-NOT:  end_block
+## CHECK:      MonitorOperation kind:exit
+
+.method public static testSynchronized(Ljava/lang/Object;)I
+  .registers 2
+
+  monitor-enter p0
+
+  :try_start_9
+  invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
+  move-result v0
+
+  monitor-exit p0
+  return v0
+
+  :catchall_11
+  move-exception v0
+  monitor-exit p0
+  :try_end_15
+  .catchall {:try_start_9 .. :try_end_15} :catchall_11
+
+  throw v0
+.end method
diff --git a/test/510-checker-try-catch/smali/SsaBuilder.smali b/test/510-checker-try-catch/smali/SsaBuilder.smali
new file mode 100644
index 0000000..2ddcbce
--- /dev/null
+++ b/test/510-checker-try-catch/smali/SsaBuilder.smali
@@ -0,0 +1,199 @@
+# Copyright (C) 2015 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.
+
+.class public LSsaBuilder;
+
+.super Ljava/lang/Object;
+
+# Tests that catch blocks with both normal and exceptional predecessors are
+# split in two.
+
+## CHECK-START: int SsaBuilder.testSimplifyCatchBlock(int, int, int) ssa_builder (after)
+
+## CHECK:      name             "B0"
+## CHECK-NEXT: from_bci
+## CHECK-NEXT: to_bci
+## CHECK-NEXT: predecessors
+## CHECK-NEXT: successors       "<<BExtracted:B\d+>>"
+
+## CHECK:      name             "<<BCatch:B\d+>>"
+## CHECK-NEXT: from_bci
+## CHECK-NEXT: to_bci
+## CHECK-NEXT: predecessors
+## CHECK-NEXT: successors       "<<BExtracted>>"
+## CHECK-NEXT: xhandlers
+## CHECK-NEXT: flags            "catch_block"
+## CHECK-NOT:  Add
+
+## CHECK:      name             "<<BExtracted>>"
+## CHECK-NEXT: from_bci
+## CHECK-NEXT: to_bci
+## CHECK-NEXT: predecessors     "B0" "<<BCatch>>"
+## CHECK-NOT:  flags            "catch_block"
+## CHECK:      Add
+
+.method public static testSimplifyCatchBlock(III)I
+    .registers 4
+
+    :catch_all
+    add-int/2addr p0, p1
+
+    :try_start
+    div-int/2addr p0, p2
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    return p0
+.end method
+
+# Should be rejected because :catch_all is a loop header.
+
+## CHECK-START: int SsaBuilder.testCatchLoopHeader(int, int, int) ssa_builder (after, bad_state)
+
+.method public static testCatchLoopHeader(III)I
+    .registers 4
+
+    :try_start_1
+    div-int/2addr p0, p1
+    return p0
+    :try_end_1
+    .catchall {:try_start_1 .. :try_end_1} :catch_all
+
+    :catch_all
+    :try_start_2
+    div-int/2addr p0, p2
+    return p0
+    :try_end_2
+    .catchall {:try_start_2 .. :try_end_2} :catch_all
+
+.end method
+
+# Tests creation of catch Phis.
+
+## CHECK-START: int SsaBuilder.testPhiCreation(int, int, int) ssa_builder (after)
+## CHECK-DAG:     <<P0:i\d+>>   ParameterValue
+## CHECK-DAG:     <<P1:i\d+>>   ParameterValue
+## CHECK-DAG:     <<P2:i\d+>>   ParameterValue
+
+## CHECK-DAG:     <<DZC1:i\d+>> DivZeroCheck [<<P1>>]
+## CHECK-DAG:     <<Div1:i\d+>> Div [<<P0>>,<<DZC1>>]
+## CHECK-DAG:     <<DZC2:i\d+>> DivZeroCheck [<<P1>>]
+## CHECK-DAG:     <<Div2:i\d+>> Div [<<Div1>>,<<DZC2>>]
+## CHECK-DAG:     <<DZC3:i\d+>> DivZeroCheck [<<P1>>]
+## CHECK-DAG:     <<Div3:i\d+>> Div [<<Div2>>,<<DZC3>>]
+
+## CHECK-DAG:     <<Phi1:i\d+>> Phi [<<P0>>,<<P1>>,<<P2>>] reg:0 is_catch_phi:true
+## CHECK-DAG:     <<Phi2:i\d+>> Phi [<<Div3>>,<<Phi1>>]    reg:0 is_catch_phi:false
+## CHECK-DAG:                   Return [<<Phi2>>]
+
+.method public static testPhiCreation(III)I
+    .registers 4
+
+    :try_start
+    move v0, p0
+    div-int/2addr p0, p1
+
+    move v0, p1
+    div-int/2addr p0, p1
+
+    move v0, p2
+    div-int/2addr p0, p1
+
+    move v0, p0
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return v0
+
+    :catch_all
+    goto :return
+.end method
+
+# Tests that phi elimination does not remove catch phis where the value does
+# not dominate the phi.
+
+## CHECK-START: int SsaBuilder.testPhiElimination(int, int) ssa_builder (after)
+## CHECK-DAG:     <<P0:i\d+>>   ParameterValue
+## CHECK-DAG:     <<P1:i\d+>>   ParameterValue
+## CHECK-DAG:     <<Cst5:i\d+>> IntConstant 5
+## CHECK-DAG:     <<Cst7:i\d+>> IntConstant 7
+
+## CHECK-DAG:     <<Add1:i\d+>> Add [<<Cst7>>,<<Cst7>>]
+## CHECK-DAG:     <<DZC:i\d+>>  DivZeroCheck [<<P1>>]
+## CHECK-DAG:     <<Div:i\d+>>  Div [<<P0>>,<<DZC>>]
+
+## CHECK-DAG:     <<Phi1:i\d+>> Phi [<<Add1>>] reg:1 is_catch_phi:true
+## CHECK-DAG:     <<Add2:i\d+>> Add [<<Cst5>>,<<Phi1>>]
+
+## CHECK-DAG:     <<Phi2:i\d+>> Phi [<<Cst5>>,<<Add2>>] reg:0 is_catch_phi:false
+## CHECK-DAG:                   Return [<<Phi2>>]
+
+.method public static testPhiElimination(II)I
+    .registers 4
+
+    :try_start
+    # The constant in entry block will dominate the vreg 0 catch phi.
+    const v0, 5
+
+    # Insert addition so that the value of vreg 1 does not dominate the phi.
+    const v1, 7
+    add-int/2addr v1, v1
+
+    div-int/2addr p0, p1
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return v0
+
+    :catch_all
+    add-int/2addr v0, v1
+    goto :return
+.end method
+
+# Tests that dead catch blocks are removed.
+
+## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) ssa_builder (before)
+## CHECK:                       Mul
+
+## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) ssa_builder (after)
+## CHECK-DAG:     <<P0:i\d+>>   ParameterValue
+## CHECK-DAG:     <<P1:i\d+>>   ParameterValue
+## CHECK-DAG:     <<P2:i\d+>>   ParameterValue
+## CHECK-DAG:     <<Add1:i\d+>> Add [<<P0>>,<<P1>>]
+## CHECK-DAG:     <<Add2:i\d+>> Add [<<Add1>>,<<P2>>]
+## CHECK-DAG:                   Return [<<Add2>>]
+
+## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) ssa_builder (after)
+## CHECK-NOT:                   flags "catch_block"
+## CHECK-NOT:                   Mul
+
+.method public static testDeadCatchBlock(III)I
+    .registers 4
+
+    :try_start
+    add-int/2addr p0, p1
+    add-int/2addr p0, p2
+    move v0, p0
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return v0
+
+    :catch_all
+    mul-int/2addr v1, v1
+    goto :return
+.end method
diff --git a/test/519-bound-load-class/src/Main.java b/test/519-bound-load-class/src/Main.java
index 41bb951..cddeb09 100644
--- a/test/519-bound-load-class/src/Main.java
+++ b/test/519-bound-load-class/src/Main.java
@@ -16,9 +16,24 @@
 
 public class Main {
   public static void main(String[] args) {
+    testInstanceOf();
+    try {
+      testNull();
+      throw new Error("Expected ClassClastException");
+    } catch (ClassCastException e) { /* ignore */ }
+  }
+
+  public static void testInstanceOf() {
     Object o = Main.class;
     if (o instanceof Main) {
       System.out.println((Main)o);
     }
   }
+
+  public static void testNull() {
+    Object o = Main.class;
+    if (o != null) {
+      System.out.println((Main)o);
+    }
+  }
 }
diff --git a/test/522-checker-regression-monitor-exit/expected.txt b/test/522-checker-regression-monitor-exit/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/expected.txt
diff --git a/test/522-checker-regression-monitor-exit/info.txt b/test/522-checker-regression-monitor-exit/info.txt
new file mode 100644
index 0000000..7cfc963
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/info.txt
@@ -0,0 +1,3 @@
+Regression test for removal of monitor-exit due to lack of specified side-effects.
+The test invokes a synchronized version of Object.hashCode in multiple threads.
+If monitor-exit is removed, the following threads will get stuck and timeout.
\ No newline at end of file
diff --git a/test/522-checker-regression-monitor-exit/smali/Test.smali b/test/522-checker-regression-monitor-exit/smali/Test.smali
new file mode 100644
index 0000000..c8e9198
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/smali/Test.smali
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2015 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.
+
+.class public LTest;
+
+.super Ljava/lang/Object;
+
+## CHECK-START: int Test.synchronizedHashCode(java.lang.Object) dead_code_elimination (before)
+## CHECK:         MonitorOperation [<<Param:l\d+>>] kind:enter
+## CHECK:         MonitorOperation [<<Param>>]      kind:exit
+
+## CHECK-START: int Test.synchronizedHashCode(java.lang.Object) dead_code_elimination (after)
+## CHECK:         MonitorOperation [<<Param:l\d+>>] kind:enter
+## CHECK:         MonitorOperation [<<Param>>]      kind:exit
+
+.method public static synchronizedHashCode(Ljava/lang/Object;)I
+  .registers 2
+
+  monitor-enter p0
+  invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
+  move-result v0
+
+  # Must not get removed by DCE.
+  monitor-exit p0
+
+  return v0
+
+.end method
diff --git a/test/522-checker-regression-monitor-exit/src/Main.java b/test/522-checker-regression-monitor-exit/src/Main.java
new file mode 100644
index 0000000..c85ac96
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/src/Main.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeoutException;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  private static class HashCodeQuery implements Callable<Integer> {
+    public HashCodeQuery(Object obj) {
+      m_obj = obj;
+    }
+
+    public Integer call() {
+      Integer result;
+      try {
+        Class<?> c = Class.forName("Test");
+        Method m = c.getMethod("synchronizedHashCode", new Class[] { Object.class });
+        result = (Integer) m.invoke(null, m_obj);
+      } catch (Exception e) {
+        System.err.println("Hash code query exception");
+        e.printStackTrace();
+        result = -1;
+      }
+      return result;
+    }
+
+    private Object m_obj;
+    private int m_index;
+  }
+
+  public static void main(String args[]) throws Exception {
+    Object obj = new Object();
+    int numThreads = 10;
+
+    ExecutorService pool = Executors.newFixedThreadPool(numThreads);
+
+    List<HashCodeQuery> queries = new ArrayList<HashCodeQuery>(numThreads);
+    for (int i = 0; i < numThreads; ++i) {
+      queries.add(new HashCodeQuery(obj));
+    }
+
+    try {
+      List<Future<Integer>> results = pool.invokeAll(queries, 5, TimeUnit.SECONDS);
+
+      int hash = obj.hashCode();
+      for (int i = 0; i < numThreads; ++i) {
+        int result = results.get(i).get();
+        if (hash != result) {
+          throw new Error("Query #" + i + " wrong. Expected " + hash + ", got " + result);
+        }
+      }
+      pool.shutdown();
+    } catch (CancellationException ex) {
+      System.err.println("Job timeout");
+      System.exit(1);
+    }
+  }
+}
diff --git a/test/523-checker-can-throw-regression/expected.txt b/test/523-checker-can-throw-regression/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/523-checker-can-throw-regression/expected.txt
diff --git a/test/523-checker-can-throw-regression/info.txt b/test/523-checker-can-throw-regression/info.txt
new file mode 100644
index 0000000..720dc85
--- /dev/null
+++ b/test/523-checker-can-throw-regression/info.txt
@@ -0,0 +1,2 @@
+Regression test for the HGraphBuilder which would split a throwing catch block
+but would not update information about which blocks throw.
\ No newline at end of file
diff --git a/test/523-checker-can-throw-regression/smali/Test.smali b/test/523-checker-can-throw-regression/smali/Test.smali
new file mode 100644
index 0000000..87192ea
--- /dev/null
+++ b/test/523-checker-can-throw-regression/smali/Test.smali
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2015 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.
+
+.class public LTest;
+
+.super Ljava/lang/Object;
+
+## CHECK-START: int Test.testCase(int, int, int) builder (after)
+## CHECK:         TryBoundary kind:entry
+## CHECK:         TryBoundary kind:entry
+## CHECK-NOT:     TryBoundary kind:entry
+
+## CHECK-START: int Test.testCase(int, int, int) builder (after)
+## CHECK:         TryBoundary kind:exit
+## CHECK:         TryBoundary kind:exit
+## CHECK-NOT:     TryBoundary kind:exit
+
+.method public static testCase(III)I
+  .registers 4
+
+  :try_start_1
+  div-int/2addr p0, p1
+  return p0
+  :try_end_1
+  .catchall {:try_start_1 .. :try_end_1} :catchall
+
+  :catchall
+  :try_start_2
+  move-exception v0
+  # Block would be split here but second part not marked as throwing.
+  div-int/2addr p0, p1
+  if-eqz p2, :else
+
+  div-int/2addr p0, p1
+  :else
+  div-int/2addr p0, p2
+  return p0
+  :try_end_2
+  .catchall {:try_start_2 .. :try_end_2} :catchall
+
+.end method
diff --git a/test/523-checker-can-throw-regression/src/Main.java b/test/523-checker-can-throw-regression/src/Main.java
new file mode 100644
index 0000000..3ff48f3
--- /dev/null
+++ b/test/523-checker-can-throw-regression/src/Main.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeoutException;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String args[]) {}
+}
diff --git a/test/524-boolean-simplifier-regression/expected.txt b/test/524-boolean-simplifier-regression/expected.txt
new file mode 100644
index 0000000..863339f
--- /dev/null
+++ b/test/524-boolean-simplifier-regression/expected.txt
@@ -0,0 +1 @@
+Passed
diff --git a/test/524-boolean-simplifier-regression/info.txt b/test/524-boolean-simplifier-regression/info.txt
new file mode 100644
index 0000000..b38d71c
--- /dev/null
+++ b/test/524-boolean-simplifier-regression/info.txt
@@ -0,0 +1 @@
+Regression test for optimizing boolean simplifier.
diff --git a/test/524-boolean-simplifier-regression/src/Main.java b/test/524-boolean-simplifier-regression/src/Main.java
new file mode 100644
index 0000000..a8830bb
--- /dev/null
+++ b/test/524-boolean-simplifier-regression/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+public class Main {
+
+    public static boolean test2() {
+        throw new NullPointerException();
+    }
+
+    public static boolean test1()  {
+        System.out.println("Passed");
+        try {
+            test2();
+        } catch (NullPointerException npe) {
+        }
+        return true;
+    }
+
+    public static void main(String[] args) {
+      boolean b=false;
+
+      b = (test1() || (b = b)) & b;
+    }
+}
diff --git a/test/525-arrays-and-fields/expected.txt b/test/525-arrays-and-fields/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/525-arrays-and-fields/expected.txt
diff --git a/test/525-arrays-and-fields/info.txt b/test/525-arrays-and-fields/info.txt
new file mode 100644
index 0000000..3e16abf
--- /dev/null
+++ b/test/525-arrays-and-fields/info.txt
@@ -0,0 +1 @@
+Test on (in)variant static and instance field and array references in loops.
diff --git a/test/525-arrays-and-fields/src/Main.java b/test/525-arrays-and-fields/src/Main.java
new file mode 100644
index 0000000..cd976b2
--- /dev/null
+++ b/test/525-arrays-and-fields/src/Main.java
@@ -0,0 +1,614 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+//
+// Test on (in)variant static and instance field and array references in loops.
+//
+public class Main {
+
+  private static Object anObject = new Object();
+  private static Object anotherObject = new Object();
+
+  //
+  // Static fields.
+  //
+
+  private static boolean sZ;
+  private static byte sB;
+  private static char sC;
+  private static short sS;
+  private static int sI;
+  private static long sJ;
+  private static float sF;
+  private static double sD;
+  private static Object sL;
+
+  //
+  // Static arrays.
+  //
+
+  private static boolean[] sArrZ;
+  private static byte[] sArrB;
+  private static char[] sArrC;
+  private static short[] sArrS;
+  private static int[] sArrI;
+  private static long[] sArrJ;
+  private static float[] sArrF;
+  private static double[] sArrD;
+  private static Object[] sArrL;
+
+  //
+  // Instance fields.
+  //
+
+  private boolean mZ;
+  private byte mB;
+  private char mC;
+  private short mS;
+  private int mI;
+  private long mJ;
+  private float mF;
+  private double mD;
+  private Object mL;
+
+  //
+  // Instance arrays.
+  //
+
+  private boolean[] mArrZ;
+  private byte[] mArrB;
+  private char[] mArrC;
+  private short[] mArrS;
+  private int[] mArrI;
+  private long[] mArrJ;
+  private float[] mArrF;
+  private double[] mArrD;
+  private Object[] mArrL;
+
+  //
+  // Loops on static arrays with invariant static field references.
+  //
+
+  private static void SInvLoopZ() {
+    for (int i = 0; i < sArrZ.length; i++) {
+      sArrZ[i] = sZ;
+    }
+  }
+
+  private static void SInvLoopB() {
+    for (int i = 0; i < sArrB.length; i++) {
+      sArrB[i] = sB;
+    }
+  }
+
+  private static void SInvLoopC() {
+    for (int i = 0; i < sArrC.length; i++) {
+      sArrC[i] = sC;
+    }
+  }
+
+  private static void SInvLoopS() {
+    for (int i = 0; i < sArrS.length; i++) {
+      sArrS[i] = sS;
+    }
+  }
+
+  private static void SInvLoopI() {
+    for (int i = 0; i < sArrI.length; i++) {
+      sArrI[i] = sI;
+    }
+  }
+
+  private static void SInvLoopJ() {
+    for (int i = 0; i < sArrJ.length; i++) {
+      sArrJ[i] = sJ;
+    }
+  }
+
+  private static void SInvLoopF() {
+    for (int i = 0; i < sArrF.length; i++) {
+      sArrF[i] = sF;
+    }
+  }
+
+  private static void SInvLoopD() {
+    for (int i = 0; i < sArrD.length; i++) {
+      sArrD[i] = sD;
+    }
+  }
+
+  private static void SInvLoopL() {
+    for (int i = 0; i < sArrL.length; i++) {
+      sArrL[i] = sL;
+    }
+  }
+
+  //
+  // Loops on static arrays with variant static field references.
+  //
+
+  private static void SVarLoopZ() {
+    for (int i = 0; i < sArrZ.length; i++) {
+      sArrZ[i] = sZ;
+      if (i == 10)
+        sZ = !sZ;
+    }
+  }
+
+  private static void SVarLoopB() {
+    for (int i = 0; i < sArrB.length; i++) {
+      sArrB[i] = sB;
+      if (i == 10)
+        sB++;
+    }
+  }
+
+  private static void SVarLoopC() {
+    for (int i = 0; i < sArrC.length; i++) {
+      sArrC[i] = sC;
+      if (i == 10)
+        sC++;
+    }
+  }
+
+  private static void SVarLoopS() {
+    for (int i = 0; i < sArrS.length; i++) {
+      sArrS[i] = sS;
+      if (i == 10)
+        sS++;
+    }
+  }
+
+  private static void SVarLoopI() {
+    for (int i = 0; i < sArrI.length; i++) {
+      sArrI[i] = sI;
+      if (i == 10)
+        sI++;
+    }
+  }
+
+  private static void SVarLoopJ() {
+    for (int i = 0; i < sArrJ.length; i++) {
+      sArrJ[i] = sJ;
+      if (i == 10)
+        sJ++;
+    }
+  }
+
+  private static void SVarLoopF() {
+    for (int i = 0; i < sArrF.length; i++) {
+      sArrF[i] = sF;
+      if (i == 10)
+        sF++;
+    }
+  }
+
+  private static void SVarLoopD() {
+    for (int i = 0; i < sArrD.length; i++) {
+      sArrD[i] = sD;
+      if (i == 10)
+        sD++;
+    }
+  }
+
+  private static void SVarLoopL() {
+    for (int i = 0; i < sArrL.length; i++) {
+      sArrL[i] = sL;
+      if (i == 10)
+        sL = anotherObject;
+    }
+  }
+
+  //
+  // Loops on instance arrays with invariant instance field references.
+  //
+
+  private void InvLoopZ() {
+    for (int i = 0; i < mArrZ.length; i++) {
+      mArrZ[i] = mZ;
+    }
+  }
+
+  private void InvLoopB() {
+    for (int i = 0; i < mArrB.length; i++) {
+      mArrB[i] = mB;
+    }
+  }
+
+  private void InvLoopC() {
+    for (int i = 0; i < mArrC.length; i++) {
+      mArrC[i] = mC;
+    }
+  }
+
+  private void InvLoopS() {
+    for (int i = 0; i < mArrS.length; i++) {
+      mArrS[i] = mS;
+    }
+  }
+
+  private void InvLoopI() {
+    for (int i = 0; i < mArrI.length; i++) {
+      mArrI[i] = mI;
+    }
+  }
+
+  private void InvLoopJ() {
+    for (int i = 0; i < mArrJ.length; i++) {
+      mArrJ[i] = mJ;
+    }
+  }
+
+  private void InvLoopF() {
+    for (int i = 0; i < mArrF.length; i++) {
+      mArrF[i] = mF;
+    }
+  }
+
+  private void InvLoopD() {
+    for (int i = 0; i < mArrD.length; i++) {
+      mArrD[i] = mD;
+    }
+  }
+
+  private void InvLoopL() {
+    for (int i = 0; i < mArrL.length; i++) {
+      mArrL[i] = mL;
+    }
+  }
+
+  //
+  // Loops on instance arrays with variant instance field references.
+  //
+
+  private void VarLoopZ() {
+    for (int i = 0; i < mArrZ.length; i++) {
+      mArrZ[i] = mZ;
+      if (i == 10)
+        mZ = !mZ;
+    }
+  }
+
+  private void VarLoopB() {
+    for (int i = 0; i < mArrB.length; i++) {
+      mArrB[i] = mB;
+      if (i == 10)
+        mB++;
+    }
+  }
+
+  private void VarLoopC() {
+    for (int i = 0; i < mArrC.length; i++) {
+      mArrC[i] = mC;
+      if (i == 10)
+        mC++;
+    }
+  }
+
+  private void VarLoopS() {
+    for (int i = 0; i < mArrS.length; i++) {
+      mArrS[i] = mS;
+      if (i == 10)
+        mS++;
+    }
+  }
+
+  private void VarLoopI() {
+    for (int i = 0; i < mArrI.length; i++) {
+      mArrI[i] = mI;
+      if (i == 10)
+        mI++;
+    }
+  }
+
+  private void VarLoopJ() {
+    for (int i = 0; i < mArrJ.length; i++) {
+      mArrJ[i] = mJ;
+      if (i == 10)
+        mJ++;
+    }
+  }
+
+  private void VarLoopF() {
+    for (int i = 0; i < mArrF.length; i++) {
+      mArrF[i] = mF;
+      if (i == 10)
+        mF++;
+    }
+  }
+
+  private void VarLoopD() {
+    for (int i = 0; i < mArrD.length; i++) {
+      mArrD[i] = mD;
+      if (i == 10)
+        mD++;
+    }
+  }
+
+  private void VarLoopL() {
+    for (int i = 0; i < mArrL.length; i++) {
+      mArrL[i] = mL;
+      if (i == 10)
+        mL = anotherObject;
+    }
+  }
+  //
+  // Driver and testers.
+  //
+
+  public static void main(String[] args) {
+    DoStaticTests();
+    new Main().DoInstanceTests();
+  }
+
+  private static void DoStaticTests() {
+    // Type Z.
+    sZ = true;
+    sArrZ = new boolean[100];
+    SInvLoopZ();
+    for (int i = 0; i < sArrZ.length; i++) {
+      expectEquals(true, sArrZ[i]);
+    }
+    SVarLoopZ();
+    for (int i = 0; i < sArrZ.length; i++) {
+      expectEquals(i <= 10, sArrZ[i]);
+    }
+    // Type B.
+    sB = 1;
+    sArrB = new byte[100];
+    SInvLoopB();
+    for (int i = 0; i < sArrB.length; i++) {
+      expectEquals(1, sArrB[i]);
+    }
+    SVarLoopB();
+    for (int i = 0; i < sArrB.length; i++) {
+      expectEquals(i <= 10 ? 1 : 2, sArrB[i]);
+    }
+    // Type C.
+    sC = 2;
+    sArrC = new char[100];
+    SInvLoopC();
+    for (int i = 0; i < sArrC.length; i++) {
+      expectEquals(2, sArrC[i]);
+    }
+    SVarLoopC();
+    for (int i = 0; i < sArrC.length; i++) {
+      expectEquals(i <= 10 ? 2 : 3, sArrC[i]);
+    }
+    // Type S.
+    sS = 3;
+    sArrS = new short[100];
+    SInvLoopS();
+    for (int i = 0; i < sArrS.length; i++) {
+      expectEquals(3, sArrS[i]);
+    }
+    SVarLoopS();
+    for (int i = 0; i < sArrS.length; i++) {
+      expectEquals(i <= 10 ? 3 : 4, sArrS[i]);
+    }
+    // Type I.
+    sI = 4;
+    sArrI = new int[100];
+    SInvLoopI();
+    for (int i = 0; i < sArrI.length; i++) {
+      expectEquals(4, sArrI[i]);
+    }
+    SVarLoopI();
+    for (int i = 0; i < sArrI.length; i++) {
+      expectEquals(i <= 10 ? 4 : 5, sArrI[i]);
+    }
+    // Type J.
+    sJ = 5;
+    sArrJ = new long[100];
+    SInvLoopJ();
+    for (int i = 0; i < sArrJ.length; i++) {
+      expectEquals(5, sArrJ[i]);
+    }
+    SVarLoopJ();
+    for (int i = 0; i < sArrJ.length; i++) {
+      expectEquals(i <= 10 ? 5 : 6, sArrJ[i]);
+    }
+    // Type F.
+    sF = 6.0f;
+    sArrF = new float[100];
+    SInvLoopF();
+    for (int i = 0; i < sArrF.length; i++) {
+      expectEquals(6, sArrF[i]);
+    }
+    SVarLoopF();
+    for (int i = 0; i < sArrF.length; i++) {
+      expectEquals(i <= 10 ? 6 : 7, sArrF[i]);
+    }
+    // Type D.
+    sD = 7.0;
+    sArrD = new double[100];
+    SInvLoopD();
+    for (int i = 0; i < sArrD.length; i++) {
+      expectEquals(7.0, sArrD[i]);
+    }
+    SVarLoopD();
+    for (int i = 0; i < sArrD.length; i++) {
+      expectEquals(i <= 10 ? 7 : 8, sArrD[i]);
+    }
+    // Type L.
+    sL = anObject;
+    sArrL = new Object[100];
+    SInvLoopL();
+    for (int i = 0; i < sArrL.length; i++) {
+      expectEquals(anObject, sArrL[i]);
+    }
+    SVarLoopL();
+    for (int i = 0; i < sArrL.length; i++) {
+      expectEquals(i <= 10 ? anObject : anotherObject, sArrL[i]);
+    }
+  }
+
+  private void DoInstanceTests() {
+    // Type Z.
+    mZ = true;
+    mArrZ = new boolean[100];
+    InvLoopZ();
+    for (int i = 0; i < mArrZ.length; i++) {
+      expectEquals(true, mArrZ[i]);
+    }
+    VarLoopZ();
+    for (int i = 0; i < mArrZ.length; i++) {
+      expectEquals(i <= 10, mArrZ[i]);
+    }
+    // Type B.
+    mB = 1;
+    mArrB = new byte[100];
+    InvLoopB();
+    for (int i = 0; i < mArrB.length; i++) {
+      expectEquals(1, mArrB[i]);
+    }
+    VarLoopB();
+    for (int i = 0; i < mArrB.length; i++) {
+      expectEquals(i <= 10 ? 1 : 2, mArrB[i]);
+    }
+    // Type C.
+    mC = 2;
+    mArrC = new char[100];
+    InvLoopC();
+    for (int i = 0; i < mArrC.length; i++) {
+      expectEquals(2, mArrC[i]);
+    }
+    VarLoopC();
+    for (int i = 0; i < mArrC.length; i++) {
+      expectEquals(i <= 10 ? 2 : 3, mArrC[i]);
+    }
+    // Type S.
+    mS = 3;
+    mArrS = new short[100];
+    InvLoopS();
+    for (int i = 0; i < mArrS.length; i++) {
+      expectEquals(3, mArrS[i]);
+    }
+    VarLoopS();
+    for (int i = 0; i < mArrS.length; i++) {
+      expectEquals(i <= 10 ? 3 : 4, mArrS[i]);
+    }
+    // Type I.
+    mI = 4;
+    mArrI = new int[100];
+    InvLoopI();
+    for (int i = 0; i < mArrI.length; i++) {
+      expectEquals(4, mArrI[i]);
+    }
+    VarLoopI();
+    for (int i = 0; i < mArrI.length; i++) {
+      expectEquals(i <= 10 ? 4 : 5, mArrI[i]);
+    }
+    // Type J.
+    mJ = 5;
+    mArrJ = new long[100];
+    InvLoopJ();
+    for (int i = 0; i < mArrJ.length; i++) {
+      expectEquals(5, mArrJ[i]);
+    }
+    VarLoopJ();
+    for (int i = 0; i < mArrJ.length; i++) {
+      expectEquals(i <= 10 ? 5 : 6, mArrJ[i]);
+    }
+    // Type F.
+    mF = 6.0f;
+    mArrF = new float[100];
+    InvLoopF();
+    for (int i = 0; i < mArrF.length; i++) {
+      expectEquals(6, mArrF[i]);
+    }
+    VarLoopF();
+    for (int i = 0; i < mArrF.length; i++) {
+      expectEquals(i <= 10 ? 6 : 7, mArrF[i]);
+    }
+    // Type D.
+    mD = 7.0;
+    mArrD = new double[100];
+    InvLoopD();
+    for (int i = 0; i < mArrD.length; i++) {
+      expectEquals(7.0, mArrD[i]);
+    }
+    VarLoopD();
+    for (int i = 0; i < mArrD.length; i++) {
+      expectEquals(i <= 10 ? 7 : 8, mArrD[i]);
+    }
+    // Type L.
+    mL = anObject;
+    mArrL = new Object[100];
+    InvLoopL();
+    for (int i = 0; i < mArrL.length; i++) {
+      expectEquals(anObject, mArrL[i]);
+    }
+    VarLoopL();
+    for (int i = 0; i < mArrL.length; i++) {
+      expectEquals(i <= 10 ? anObject : anotherObject, mArrL[i]);
+    }
+  }
+
+  private static void expectEquals(boolean expected, boolean result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(byte expected, byte result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(char expected, char result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(short expected, short result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  private static void expectEquals(Object expected, Object result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build
index 1dc8452..666fe89 100644
--- a/test/701-easy-div-rem/build
+++ b/test/701-easy-div-rem/build
@@ -23,6 +23,10 @@
 
 # Increase the file size limitation for classes.lst as the machine generated
 # source file contains a lot of methods and is quite large.
-ulimit -S 4096
+
+# Jack generates big temp files so only apply ulimit for dx.
+if [ ${USE_JACK} = "false" ]; then
+  ulimit -S 4096
+fi
 
 ./default-build
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 7059b6b..4c17240 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -27,4 +27,8 @@
 b/21886894
 b/22080519
 b/21645819
+b/22244733
+b/22331663
+b/22331663 (pass)
+b/22331663 (fail)
 Done!
diff --git a/test/800-smali/smali/b_22244733.smali b/test/800-smali/smali/b_22244733.smali
new file mode 100644
index 0000000..1b62ad9
--- /dev/null
+++ b/test/800-smali/smali/b_22244733.smali
@@ -0,0 +1,7 @@
+.class public LB22244733;
+.super Ljava/lang/Object;
+
+.method public static run(Ljava/lang/String;)Ljava/lang/String;
+.registers 2             # One local and one parameter.
+       return-object p0  # Simple return, use the special-method path in Quick.
+.end method
diff --git a/test/800-smali/smali/b_22331663.smali b/test/800-smali/smali/b_22331663.smali
new file mode 100644
index 0000000..bae75c2
--- /dev/null
+++ b/test/800-smali/smali/b_22331663.smali
@@ -0,0 +1,39 @@
+.class public LB22331663;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :if_eqz_target
+
+       # Construct a java.lang.Object completely, and throw a new exception.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+       new-instance v3, Ljava/lang/RuntimeException;
+       invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+:throw1_begin
+       throw v3
+:throw1_end
+
+:if_eqz_target
+       # Allocate a java.lang.Object (do not initialize), and throw a new exception.
+       new-instance v4, Ljava/lang/Object;
+
+       new-instance v3, Ljava/lang/RuntimeException;
+       invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+:throw2_begin
+       throw v3
+:throw2_end
+
+:catch_entry
+       # Catch handler. Here we had to merge the uninitialized with the initialized reference,
+       # which creates a conflict. Copy the conflict, and then return. This should not make the
+       # verifier fail the method.
+       move-object v0, v4
+
+       return-void
+
+.catchall {:throw1_begin .. :throw1_end} :catch_entry
+.catchall {:throw2_begin .. :throw2_end} :catch_entry
+.end method
diff --git a/test/800-smali/smali/b_22331663_fail.smali b/test/800-smali/smali/b_22331663_fail.smali
new file mode 100644
index 0000000..0c25e30
--- /dev/null
+++ b/test/800-smali/smali/b_22331663_fail.smali
@@ -0,0 +1,20 @@
+.class public LB22331663Fail;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :Label1
+
+       # Construct a java.lang.Object completely. This makes v4 of reference type.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+:Label1
+       # At this point, v4 is the merge of Undefined and ReferenceType. The verifier should
+       # reject any use of this, even a copy. Previously this was a conflict. Conflicts must
+       # be movable now, so ensure that we do not get a conflict (and then allow the move).
+       move-object v0, v4
+
+       return-void
+.end method
diff --git a/test/800-smali/smali/b_22331663_pass.smali b/test/800-smali/smali/b_22331663_pass.smali
new file mode 100644
index 0000000..1b54180
--- /dev/null
+++ b/test/800-smali/smali/b_22331663_pass.smali
@@ -0,0 +1,22 @@
+.class public LB22331663Pass;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :Label1
+
+       # Construct a java.lang.Object completely. This makes v4 of reference type.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+:Label1
+       # At this point, v4 is the merge of Undefined and ReferenceType. The verifier should not
+       # reject this if it is unused.
+
+       # Do an allocation here. This will force heap checking in gcstress mode.
+       new-instance v0, Ljava/lang/Object;
+       invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+
+       return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 30c1b14..8be6418 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -101,6 +101,14 @@
                 new NullPointerException(), null));
         testCases.add(new TestCase("b/21645819", "B21645819", "run", new Object[] { null },
                 null, null));
+        testCases.add(new TestCase("b/22244733", "B22244733", "run", new Object[] { "abc" },
+                null, "abc"));
+        testCases.add(new TestCase("b/22331663", "B22331663", "run", new Object[] { false },
+                null, null));
+        testCases.add(new TestCase("b/22331663 (pass)", "B22331663Pass", "run",
+                new Object[] { false }, null, null));
+        testCases.add(new TestCase("b/22331663 (fail)", "B22331663Fail", "run",
+                new Object[] { false }, new VerifyError(), null));
     }
 
     public void runTests() {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 3d97901..65ddf8d 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -33,22 +33,50 @@
 TEST_ART_RUN_TEST_BUILD_RULES :=
 
 # Dependencies for actually running a run-test.
-TEST_ART_RUN_TEST_DEPENDENCIES := $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger
+TEST_ART_RUN_TEST_DEPENDENCIES := \
+  $(DX) \
+  $(HOST_OUT_EXECUTABLES)/jasmin \
+  $(HOST_OUT_EXECUTABLES)/smali \
+  $(HOST_OUT_EXECUTABLES)/dexmerger
+
+ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+  TEST_ART_RUN_TEST_DEPENDENCIES += \
+    $(JACK_JAR) \
+    $(JACK_LAUNCHER_JAR) \
+    $(JILL_JAR)
+endif
+
+ifeq ($(ART_TEST_DEBUG_GC),true)
+  ART_TEST_WITH_STRACE := true
+endif
 
 # Helper to create individual build targets for tests. Must be called with $(eval).
 # $(1): the test number
 define define-build-art-run-test
   dmart_target := $(art_run_tests_dir)/art-run-tests/$(1)/touch
+  run_test_options = --build-only
+  ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+    run_test_options += --build-with-jack
+  else
+    run_test_options += --build-with-javac-dx
+  endif
+$$(dmart_target): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
 $$(dmart_target): $(TEST_ART_RUN_TEST_DEPENDENCIES)
 	$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
 	$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	  SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	  DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
-	  $(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
+	  JACK=$(abspath $(JACK)) \
+	  JACK_VM_COMMAND="$(JACK_VM) $(DEFAULT_JACK_VM_ARGS) $(JAVA_TMPDIR_ARG) -jar $(abspath $(JACK_LAUNCHER_JAR)) " \
+	  JACK_CLASSPATH=$(TARGET_JACK_CLASSPATH) \
+	  JACK_JAR=$(abspath $(JACK_JAR)) \
+	  JILL_JAR=$(abspath $(JILL_JAR)) \
+	  $(LOCAL_PATH)/run-test $$(PRIVATE_RUN_TEST_OPTIONS) --output-path $$(abspath $$(dir $$@)) $(1)
 	$(hide) touch $$@
 
   TEST_ART_RUN_TEST_BUILD_RULES += $$(dmart_target)
   dmart_target :=
+  run_test_options :=
 endef
 $(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call define-build-art-run-test,$(test))))
 
@@ -170,7 +198,7 @@
 # To generate a full list or tests:
 # $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \
 #        $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
-#        $(DEBUGGABLE_TYPES) $(TEST_ART_RUN_TESTS), $(ALL_ADDRESS_SIZES)
+#        $(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_RUN_TESTS),$(ALL_ADDRESS_SIZES))
 
 # Convert's a rule name to the form used in variables, e.g. no-relocate to NO_RELOCATE
 define name-to-var
@@ -410,37 +438,6 @@
 
 TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS :=
 
-# Known broken tests for the MIPS64 optimizing compiler backend in 64-bit mode.  b/21555893
-TEST_ART_BROKEN_OPTIMIZING_MIPS64_64BIT_RUN_TESTS := \
-  004-SignalTest \
-  018-stack-overflow \
-  107-int-math2 \
-  449-checker-bce
-
-ifeq ($(TARGET_ARCH),mips64)
-  ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
-    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
-        optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
-        $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_MIPS64_64BIT_RUN_TESTS),64)
-  endif
-endif
-
-TEST_ART_BROKEN_OPTIMIZING_MIPS64_64BIT_RUN_TESTS :=
-
-# Known broken tests for the MIPS64 optimizing compiler backend in 32-bit mode.  b/21555893
-TEST_ART_BROKEN_OPTIMIZING_MIPS64_32BIT_RUN_TESTS := \
-  496-checker-inlining-and-class-loader
-
-ifeq ($(TARGET_ARCH),mips64)
-  ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
-    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
-        optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
-        $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_OPTIMIZING_MIPS64_32BIT_RUN_TESTS),32)
-  endif
-endif
-
-TEST_ART_BROKEN_OPTIMIZING_MIPS64_32BIT_RUN_TESTS :=
-
 # Known broken tests for the optimizing compiler.
 TEST_ART_BROKEN_OPTIMIZING_RUN_TESTS :=
 
@@ -616,6 +613,15 @@
   prereq_rule :=
   test_groups :=
   uc_host_or_target :=
+  jack_classpath :=
+  ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+    run_test_options += --build-with-jack
+  else
+    run_test_options += --build-with-javac-dx
+  endif
+  ifeq ($(ART_TEST_WITH_STRACE),true)
+    run_test_options += --strace
+  endif
   ifeq ($(ART_TEST_RUN_TEST_ALWAYS_CLEAN),true)
     run_test_options += --always-clean
   endif
@@ -624,11 +630,13 @@
     test_groups := ART_RUN_TEST_HOST_RULES
     run_test_options += --host
     prereq_rule := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
+    jack_classpath := $(HOST_JACK_CLASSPATH)
   else
     ifeq ($(1),target)
       uc_host_or_target := TARGET
       test_groups := ART_RUN_TEST_TARGET_RULES
       prereq_rule := test-art-target-sync
+      jack_classpath := $(TARGET_JACK_CLASSPATH)
     else
       $$(error found $(1) expected $(TARGET_TYPES))
     endif
@@ -823,12 +831,19 @@
     run_test_options := --android-root $(ART_TEST_ANDROID_ROOT) $$(run_test_options)
   endif
 $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
+$$(run_test_rule_name): PRIVATE_JACK_CLASSPATH := $$(jack_classpath)
 .PHONY: $$(run_test_rule_name)
-$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
+$$(run_test_rule_name): $(TEST_ART_RUN_TEST_DEPENDENCIES) $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+	  DX=$(abspath $(DX)) \
+	    JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	    SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	    DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
+	    JACK=$(abspath $(JACK)) \
+	    JACK_VM_COMMAND="$(JACK_VM) $(DEFAULT_JACK_VM_ARGS) $(JAVA_TMPDIR_ARG) -jar $(abspath $(JACK_LAUNCHER_JAR)) " \
+	    JACK_CLASSPATH=$$(PRIVATE_JACK_CLASSPATH) \
+	    JACK_JAR=$(abspath $(JACK_JAR)) \
+	    JILL_JAR=$(abspath $(JILL_JAR)) \
 	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(12) \
 	      && $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
 	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
@@ -843,6 +858,7 @@
   run_test_options :=
   run_test_rule_name :=
   prereq_rule :=
+  jack_classpath :=
 endef  # define-test-art-run-test
 
 $(foreach target, $(TARGET_TYPES), \
diff --git a/test/dexdump/bytecodes.dex b/test/dexdump/bytecodes.dex
new file mode 100755
index 0000000..91e11b8
--- /dev/null
+++ b/test/dexdump/bytecodes.dex
Binary files differ
diff --git a/test/dexdump/bytecodes.lst b/test/dexdump/bytecodes.lst
new file mode 100644
index 0000000..aeda7b4
--- /dev/null
+++ b/test/dexdump/bytecodes.lst
@@ -0,0 +1,20 @@
+#bytecodes.dex
+0x000009a0 8 com.google.android.test.BuildConfig <init> ()V BuildConfig.java 4
+0x000009b8 8 com.google.android.test.R$attr <init> ()V R.java 11
+0x000009d0 8 com.google.android.test.R$drawable <init> ()V R.java 13
+0x000009e8 8 com.google.android.test.R <init> ()V R.java 10
+0x00000a00 148 com.google.android.test.Test <clinit> ()V Test.java 7
+0x00000aa4 468 com.google.android.test.Test <init> ()V Test.java 43
+0x00000ca4 478 com.google.android.test.Test add (Ljava/lang/Object;)Ljava/lang/Object; Test.java 179
+0x00000ea0 236 com.google.android.test.Test adds (Ljava/lang/Object;)Ljava/lang/Object; Test.java 201
+0x00000f9c 342 com.google.android.test.Test copies ()V Test.java 216
+0x00001104 156 com.google.android.test.Test doit (I)V Test.java 98
+0x000011b0 146 com.google.android.test.Test geta ()Z Test.java 72
+0x00001254 38 com.google.android.test.Test p (I)V Test.java 120
+0x0000128c 636 com.google.android.test.Test params (BCSIJFDLjava/lang/Object;[I)J Test.java 232
+0x00001518 170 com.google.android.test.Test q (II)V Test.java 127
+0x000015d4 186 com.google.android.test.Test r (II)I Test.java 139
+0x000016a0 388 com.google.android.test.Test s (JJ)J Test.java 159
+0x00001834 96 com.google.android.test.Test seta ()V Test.java 60
+0x000018a4 14 com.google.android.test.Test onStart ()V Test.java 86
+0x000018c4 18 com.google.android.test.Test run ()V Test.java 92
diff --git a/test/dexdump/bytecodes.txt b/test/dexdump/bytecodes.txt
new file mode 100755
index 0000000..d14c47c
--- /dev/null
+++ b/test/dexdump/bytecodes.txt
@@ -0,0 +1,1823 @@
+Processing 'bytecodes.dex'...
+Opened 'bytecodes.dex', DEX version '035'
+DEX file header:
+magic               : 'dex\n035\0'
+checksum            : 7d869259
+signature           : 6fb7...9cc4
+file_size           : 10288
+header_size         : 112
+link_size           : 0
+link_off            : 0 (0x000000)
+string_ids_size     : 153
+string_ids_off      : 112 (0x000070)
+type_ids_size       : 42
+type_ids_off        : 724 (0x0002d4)
+proto_ids_size       : 12
+proto_ids_off        : 892 (0x00037c)
+field_ids_size      : 40
+field_ids_off       : 1036 (0x00040c)
+method_ids_size     : 28
+method_ids_off      : 1356 (0x00054c)
+class_defs_size     : 7
+class_defs_off      : 1580 (0x00062c)
+data_size           : 8464
+data_off            : 1824 (0x000720)
+
+Class #0 header:
+class_idx           : 6
+access_flags        : 9729 (0x2601)
+superclass_idx      : 20
+interfaces_off      : 2116 (0x000844)
+source_file_idx     : 46
+annotations_off     : 10256 (0x002810)
+class_data_off      : 2188 (0x00088c)
+static_fields_size  : 0
+instance_fields_size: 0
+direct_methods_size : 0
+virtual_methods_size: 1
+
+Class #0            -
+  Class descriptor  : 'Landroid/annotation/SuppressLint;'
+  Access flags      : 0x2601 (PUBLIC INTERFACE ABSTRACT ANNOTATION)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Ljava/lang/annotation/Annotation;'
+  Static fields     -
+  Instance fields   -
+  Direct methods    -
+  Virtual methods   -
+    #0              : (in Landroid/annotation/SuppressLint;)
+      name          : 'value'
+      type          : '()[Ljava/lang/String;'
+      access        : 0x0401 (PUBLIC ABSTRACT)
+      code          : (none)
+
+  source_file_idx   : 46 (SuppressLint.java)
+
+Class #1 header:
+class_idx           : 7
+access_flags        : 9729 (0x2601)
+superclass_idx      : 20
+interfaces_off      : 2116 (0x000844)
+source_file_idx     : 48
+annotations_off     : 10272 (0x002820)
+class_data_off      : 2196 (0x000894)
+static_fields_size  : 0
+instance_fields_size: 0
+direct_methods_size : 0
+virtual_methods_size: 1
+
+Class #1            -
+  Class descriptor  : 'Landroid/annotation/TargetApi;'
+  Access flags      : 0x2601 (PUBLIC INTERFACE ABSTRACT ANNOTATION)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Ljava/lang/annotation/Annotation;'
+  Static fields     -
+  Instance fields   -
+  Direct methods    -
+  Virtual methods   -
+    #0              : (in Landroid/annotation/TargetApi;)
+      name          : 'value'
+      type          : '()I'
+      access        : 0x0401 (PUBLIC ABSTRACT)
+      code          : (none)
+
+  source_file_idx   : 48 (TargetApi.java)
+
+Class #2 header:
+class_idx           : 9
+access_flags        : 17 (0x0011)
+superclass_idx      : 20
+interfaces_off      : 0 (0x000000)
+source_file_idx     : 3
+annotations_off     : 0 (0x000000)
+class_data_off      : 2204 (0x00089c)
+static_fields_size  : 1
+instance_fields_size: 0
+direct_methods_size : 1
+virtual_methods_size: 0
+
+Class #2            -
+  Class descriptor  : 'Lcom/google/android/test/BuildConfig;'
+  Access flags      : 0x0011 (PUBLIC FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+  Static fields     -
+    #0              : (in Lcom/google/android/test/BuildConfig;)
+      name          : 'DEBUG'
+      type          : 'Z'
+      access        : 0x0019 (PUBLIC STATIC FINAL)
+  Instance fields   -
+  Direct methods    -
+    #0              : (in Lcom/google/android/test/BuildConfig;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 1
+      insns size    : 4 16-bit code units
+000990:                                        |[000990] com.google.android.test.BuildConfig.<init>:()V
+0009a0: 7010 1900 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0019
+0009a6: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=4
+      locals        : 
+        0x0000 - 0x0004 reg=0 this Lcom/google/android/test/BuildConfig; 
+
+  Virtual methods   -
+  source_file_idx   : 3 (BuildConfig.java)
+
+Class #3 header:
+class_idx           : 10
+access_flags        : 17 (0x0011)
+superclass_idx      : 20
+interfaces_off      : 0 (0x000000)
+source_file_idx     : 44
+annotations_off     : 10184 (0x0027c8)
+class_data_off      : 2216 (0x0008a8)
+static_fields_size  : 0
+instance_fields_size: 0
+direct_methods_size : 1
+virtual_methods_size: 0
+
+Class #3            -
+  Class descriptor  : 'Lcom/google/android/test/R$attr;'
+  Access flags      : 0x0011 (PUBLIC FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+  Static fields     -
+  Instance fields   -
+  Direct methods    -
+    #0              : (in Lcom/google/android/test/R$attr;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 1
+      insns size    : 4 16-bit code units
+0009a8:                                        |[0009a8] com.google.android.test.R.attr.<init>:()V
+0009b8: 7010 1900 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0019
+0009be: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=11
+      locals        : 
+        0x0000 - 0x0004 reg=0 this Lcom/google/android/test/R$attr; 
+
+  Virtual methods   -
+  source_file_idx   : 44 (R.java)
+
+Class #4 header:
+class_idx           : 11
+access_flags        : 17 (0x0011)
+superclass_idx      : 20
+interfaces_off      : 0 (0x000000)
+source_file_idx     : 44
+annotations_off     : 10200 (0x0027d8)
+class_data_off      : 2226 (0x0008b2)
+static_fields_size  : 1
+instance_fields_size: 0
+direct_methods_size : 1
+virtual_methods_size: 0
+
+Class #4            -
+  Class descriptor  : 'Lcom/google/android/test/R$drawable;'
+  Access flags      : 0x0011 (PUBLIC FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+  Static fields     -
+    #0              : (in Lcom/google/android/test/R$drawable;)
+      name          : 'icon'
+      type          : 'I'
+      access        : 0x0019 (PUBLIC STATIC FINAL)
+  Instance fields   -
+  Direct methods    -
+    #0              : (in Lcom/google/android/test/R$drawable;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 1
+      insns size    : 4 16-bit code units
+0009c0:                                        |[0009c0] com.google.android.test.R.drawable.<init>:()V
+0009d0: 7010 1900 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0019
+0009d6: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=13
+      locals        : 
+        0x0000 - 0x0004 reg=0 this Lcom/google/android/test/R$drawable; 
+
+  Virtual methods   -
+  source_file_idx   : 44 (R.java)
+
+Class #5 header:
+class_idx           : 12
+access_flags        : 17 (0x0011)
+superclass_idx      : 20
+interfaces_off      : 0 (0x000000)
+source_file_idx     : 44
+annotations_off     : 10216 (0x0027e8)
+class_data_off      : 2238 (0x0008be)
+static_fields_size  : 0
+instance_fields_size: 0
+direct_methods_size : 1
+virtual_methods_size: 0
+
+Class #5            -
+  Class descriptor  : 'Lcom/google/android/test/R;'
+  Access flags      : 0x0011 (PUBLIC FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+  Static fields     -
+  Instance fields   -
+  Direct methods    -
+    #0              : (in Lcom/google/android/test/R;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 1
+      insns size    : 4 16-bit code units
+0009d8:                                        |[0009d8] com.google.android.test.R.<init>:()V
+0009e8: 7010 1900 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0019
+0009ee: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=10
+      locals        : 
+        0x0000 - 0x0004 reg=0 this Lcom/google/android/test/R; 
+
+  Virtual methods   -
+  source_file_idx   : 44 (R.java)
+
+Class #6 header:
+class_idx           : 13
+access_flags        : 1 (0x0001)
+superclass_idx      : 8
+interfaces_off      : 2100 (0x000834)
+source_file_idx     : 49
+annotations_off     : 10232 (0x0027f8)
+class_data_off      : 2248 (0x0008c8)
+static_fields_size  : 10
+instance_fields_size: 20
+direct_methods_size : 13
+virtual_methods_size: 2
+
+Class #6            -
+  Class descriptor  : 'Lcom/google/android/test/Test;'
+  Access flags      : 0x0001 (PUBLIC)
+  Superclass        : 'Landroid/app/Activity;'
+  Interfaces        -
+    #0              : 'Ljava/lang/Runnable;'
+  Static fields     -
+    #0              : (in Lcom/google/android/test/Test;)
+      name          : 'sArray'
+      type          : '[I'
+      access        : 0x000a (PRIVATE STATIC)
+    #1              : (in Lcom/google/android/test/Test;)
+      name          : 'sB'
+      type          : 'B'
+      access        : 0x000a (PRIVATE STATIC)
+    #2              : (in Lcom/google/android/test/Test;)
+      name          : 'sBool'
+      type          : 'Z'
+      access        : 0x000a (PRIVATE STATIC)
+    #3              : (in Lcom/google/android/test/Test;)
+      name          : 'sC'
+      type          : 'C'
+      access        : 0x000a (PRIVATE STATIC)
+    #4              : (in Lcom/google/android/test/Test;)
+      name          : 'sD'
+      type          : 'D'
+      access        : 0x000a (PRIVATE STATIC)
+    #5              : (in Lcom/google/android/test/Test;)
+      name          : 'sF'
+      type          : 'F'
+      access        : 0x000a (PRIVATE STATIC)
+    #6              : (in Lcom/google/android/test/Test;)
+      name          : 'sI'
+      type          : 'I'
+      access        : 0x000a (PRIVATE STATIC)
+    #7              : (in Lcom/google/android/test/Test;)
+      name          : 'sL'
+      type          : 'J'
+      access        : 0x000a (PRIVATE STATIC)
+    #8              : (in Lcom/google/android/test/Test;)
+      name          : 'sO'
+      type          : 'Ljava/lang/Object;'
+      access        : 0x000a (PRIVATE STATIC)
+    #9              : (in Lcom/google/android/test/Test;)
+      name          : 'sS'
+      type          : 'S'
+      access        : 0x000a (PRIVATE STATIC)
+  Instance fields   -
+    #0              : (in Lcom/google/android/test/Test;)
+      name          : 'aBool'
+      type          : '[Z'
+      access        : 0x0002 (PRIVATE)
+    #1              : (in Lcom/google/android/test/Test;)
+      name          : 'aByte'
+      type          : '[B'
+      access        : 0x0002 (PRIVATE)
+    #2              : (in Lcom/google/android/test/Test;)
+      name          : 'aChar'
+      type          : '[C'
+      access        : 0x0002 (PRIVATE)
+    #3              : (in Lcom/google/android/test/Test;)
+      name          : 'aDouble'
+      type          : '[D'
+      access        : 0x0002 (PRIVATE)
+    #4              : (in Lcom/google/android/test/Test;)
+      name          : 'aFloat'
+      type          : '[F'
+      access        : 0x0002 (PRIVATE)
+    #5              : (in Lcom/google/android/test/Test;)
+      name          : 'aInt'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #6              : (in Lcom/google/android/test/Test;)
+      name          : 'aLong'
+      type          : '[J'
+      access        : 0x0002 (PRIVATE)
+    #7              : (in Lcom/google/android/test/Test;)
+      name          : 'aObject'
+      type          : '[Ljava/lang/Object;'
+      access        : 0x0002 (PRIVATE)
+    #8              : (in Lcom/google/android/test/Test;)
+      name          : 'aShort'
+      type          : '[S'
+      access        : 0x0002 (PRIVATE)
+    #9              : (in Lcom/google/android/test/Test;)
+      name          : 'mArray'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #10              : (in Lcom/google/android/test/Test;)
+      name          : 'mB'
+      type          : 'B'
+      access        : 0x0002 (PRIVATE)
+    #11              : (in Lcom/google/android/test/Test;)
+      name          : 'mBool'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #12              : (in Lcom/google/android/test/Test;)
+      name          : 'mC'
+      type          : 'C'
+      access        : 0x0002 (PRIVATE)
+    #13              : (in Lcom/google/android/test/Test;)
+      name          : 'mD'
+      type          : 'D'
+      access        : 0x0002 (PRIVATE)
+    #14              : (in Lcom/google/android/test/Test;)
+      name          : 'mF'
+      type          : 'F'
+      access        : 0x0002 (PRIVATE)
+    #15              : (in Lcom/google/android/test/Test;)
+      name          : 'mI'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #16              : (in Lcom/google/android/test/Test;)
+      name          : 'mL'
+      type          : 'J'
+      access        : 0x0002 (PRIVATE)
+    #17              : (in Lcom/google/android/test/Test;)
+      name          : 'mO'
+      type          : 'Ljava/lang/Object;'
+      access        : 0x0002 (PRIVATE)
+    #18              : (in Lcom/google/android/test/Test;)
+      name          : 'mRunner'
+      type          : 'Ljava/lang/Runnable;'
+      access        : 0x0002 (PRIVATE)
+    #19              : (in Lcom/google/android/test/Test;)
+      name          : 'mS'
+      type          : 'S'
+      access        : 0x0002 (PRIVATE)
+  Direct methods    -
+    #0              : (in Lcom/google/android/test/Test;)
+      name          : '<clinit>'
+      type          : '()V'
+      access        : 0x10008 (STATIC CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 0
+      outs          : 0
+      insns size    : 74 16-bit code units
+0009f0:                                        |[0009f0] com.google.android.test.Test.<clinit>:()V
+000a00: 1200                                   |0000: const/4 v0, #int 0 // #0
+000a02: 6a00 1800                              |0001: sput-boolean v0, Lcom/google/android/test/Test;.sBool:Z // field@0018
+000a06: 1300 1f00                              |0003: const/16 v0, #int 31 // #1f
+000a0a: 6b00 1700                              |0005: sput-byte v0, Lcom/google/android/test/Test;.sB:B // field@0017
+000a0e: 1400 ffff 0000                         |0007: const v0, #float 0.000000 // #0000ffff
+000a14: 6c00 1900                              |000a: sput-char v0, Lcom/google/android/test/Test;.sC:C // field@0019
+000a18: 1300 3412                              |000c: const/16 v0, #int 4660 // #1234
+000a1c: 6d00 1f00                              |000e: sput-short v0, Lcom/google/android/test/Test;.sS:S // field@001f
+000a20: 1400 7856 3412                         |0010: const v0, #float 0.000000 // #12345678
+000a26: 6700 1c00                              |0013: sput v0, Lcom/google/android/test/Test;.sI:I // field@001c
+000a2a: 1800 ffff cdab 7956 3412               |0015: const-wide v0, #double 0.000000 // #12345679abcdffff
+000a34: 6800 1d00                              |001a: sput-wide v0, Lcom/google/android/test/Test;.sL:J // field@001d
+000a38: 1400 00e4 4046                         |001c: const v0, #float 12345.000000 // #4640e400
+000a3e: 6700 1b00                              |001f: sput v0, Lcom/google/android/test/Test;.sF:F // field@001b
+000a42: 1800 0000 0000 801c c840               |0021: const-wide v0, #double 12345.000000 // #40c81c8000000000
+000a4c: 6800 1a00                              |0026: sput-wide v0, Lcom/google/android/test/Test;.sD:D // field@001a
+000a50: 1200                                   |0028: const/4 v0, #int 0 // #0
+000a52: 6900 1e00                              |0029: sput-object v0, Lcom/google/android/test/Test;.sO:Ljava/lang/Object; // field@001e
+000a56: 1300 0800                              |002b: const/16 v0, #int 8 // #8
+000a5a: 2300 2400                              |002d: new-array v0, v0, [I // type@0024
+000a5e: 2600 0700 0000                         |002f: fill-array-data v0, 00000036 // +00000007
+000a64: 6900 1600                              |0032: sput-object v0, Lcom/google/android/test/Test;.sArray:[I // field@0016
+000a68: 0e00                                   |0034: return-void
+000a6a: 0000                                   |0035: nop // spacer
+000a6c: 0003 0400 0800 0000 0100 0000 0200 ... |0036: array-data (20 units)
+      catches       : (none)
+      positions     : 
+        0x0000 line=7
+        0x0003 line=8
+        0x0007 line=9
+        0x000c line=10
+        0x0010 line=11
+        0x0015 line=12
+        0x001c line=13
+        0x0021 line=14
+        0x0028 line=15
+        0x002b line=16
+      locals        : 
+
+    #1              : (in Lcom/google/android/test/Test;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 9
+      ins           : 1
+      outs          : 2
+      insns size    : 234 16-bit code units
+000a94:                                        |[000a94] com.google.android.test.Test.<init>:()V
+000aa4: 1606 0000                              |0000: const-wide/16 v6, #int 0 // #0
+000aa8: 1215                                   |0002: const/4 v5, #int 1 // #1
+000aaa: 1224                                   |0003: const/4 v4, #int 2 // #2
+000aac: 7010 0200 0800                         |0004: invoke-direct {v8}, Landroid/app/Activity;.<init>:()V // method@0002
+000ab2: 1201                                   |0007: const/4 v1, #int 0 // #0
+000ab4: 5c81 0d00                              |0008: iput-boolean v1, v8, Lcom/google/android/test/Test;.mBool:Z // field@000d
+000ab8: 1301 1f00                              |000a: const/16 v1, #int 31 // #1f
+000abc: 5d81 0c00                              |000c: iput-byte v1, v8, Lcom/google/android/test/Test;.mB:B // field@000c
+000ac0: 1401 ffff 0000                         |000e: const v1, #float 0.000000 // #0000ffff
+000ac6: 5e81 0e00                              |0011: iput-char v1, v8, Lcom/google/android/test/Test;.mC:C // field@000e
+000aca: 1301 3412                              |0013: const/16 v1, #int 4660 // #1234
+000ace: 5f81 1500                              |0015: iput-short v1, v8, Lcom/google/android/test/Test;.mS:S // field@0015
+000ad2: 1401 7856 3412                         |0017: const v1, #float 0.000000 // #12345678
+000ad8: 5981 1100                              |001a: iput v1, v8, Lcom/google/android/test/Test;.mI:I // field@0011
+000adc: 1802 ffff cdab 7956 3412               |001c: const-wide v2, #double 0.000000 // #12345679abcdffff
+000ae6: 5a82 1200                              |0021: iput-wide v2, v8, Lcom/google/android/test/Test;.mL:J // field@0012
+000aea: 1401 00e4 4046                         |0023: const v1, #float 12345.000000 // #4640e400
+000af0: 5981 1000                              |0026: iput v1, v8, Lcom/google/android/test/Test;.mF:F // field@0010
+000af4: 1802 0000 0000 801c c840               |0028: const-wide v2, #double 12345.000000 // #40c81c8000000000
+000afe: 5a82 0f00                              |002d: iput-wide v2, v8, Lcom/google/android/test/Test;.mD:D // field@000f
+000b02: 1201                                   |002f: const/4 v1, #int 0 // #0
+000b04: 5b81 1300                              |0030: iput-object v1, v8, Lcom/google/android/test/Test;.mO:Ljava/lang/Object; // field@0013
+000b08: 1241                                   |0032: const/4 v1, #int 4 // #4
+000b0a: 2311 2400                              |0033: new-array v1, v1, [I // type@0024
+000b0e: 2601 7500 0000                         |0035: fill-array-data v1, 000000aa // +00000075
+000b14: 5b81 0b00                              |0038: iput-object v1, v8, Lcom/google/android/test/Test;.mArray:[I // field@000b
+000b18: 2341 2900                              |003a: new-array v1, v4, [Z // type@0029
+000b1c: 4e05 0105                              |003c: aput-boolean v5, v1, v5
+000b20: 5b81 0200                              |003e: iput-object v1, v8, Lcom/google/android/test/Test;.aBool:[Z // field@0002
+000b24: 2341 2000                              |0040: new-array v1, v4, [B // type@0020
+000b28: 2601 7400 0000                         |0042: fill-array-data v1, 000000b6 // +00000074
+000b2e: 5b81 0300                              |0045: iput-object v1, v8, Lcom/google/android/test/Test;.aByte:[B // field@0003
+000b32: 2341 2100                              |0047: new-array v1, v4, [C // type@0021
+000b36: 2601 7300 0000                         |0049: fill-array-data v1, 000000bc // +00000073
+000b3c: 5b81 0400                              |004c: iput-object v1, v8, Lcom/google/android/test/Test;.aChar:[C // field@0004
+000b40: 2341 2800                              |004e: new-array v1, v4, [S // type@0028
+000b44: 5b81 0a00                              |0050: iput-object v1, v8, Lcom/google/android/test/Test;.aShort:[S // field@000a
+000b48: 2341 2400                              |0052: new-array v1, v4, [I // type@0024
+000b4c: 2601 6e00 0000                         |0054: fill-array-data v1, 000000c2 // +0000006e
+000b52: 5b81 0700                              |0057: iput-object v1, v8, Lcom/google/android/test/Test;.aInt:[I // field@0007
+000b56: 2341 2500                              |0059: new-array v1, v4, [J // type@0025
+000b5a: 2601 6f00 0000                         |005b: fill-array-data v1, 000000ca // +0000006f
+000b60: 5b81 0800                              |005e: iput-object v1, v8, Lcom/google/android/test/Test;.aLong:[J // field@0008
+000b64: 2341 2300                              |0060: new-array v1, v4, [F // type@0023
+000b68: 2601 7400 0000                         |0062: fill-array-data v1, 000000d6 // +00000074
+000b6e: 5b81 0600                              |0065: iput-object v1, v8, Lcom/google/android/test/Test;.aFloat:[F // field@0006
+000b72: 2341 2200                              |0067: new-array v1, v4, [D // type@0022
+000b76: 2601 7500 0000                         |0069: fill-array-data v1, 000000de // +00000075
+000b7c: 5b81 0500                              |006c: iput-object v1, v8, Lcom/google/android/test/Test;.aDouble:[D // field@0005
+000b80: 2341 2600                              |006e: new-array v1, v4, [Ljava/lang/Object; // type@0026
+000b84: 2202 1400                              |0070: new-instance v2, Ljava/lang/Object; // type@0014
+000b88: 7010 1900 0200                         |0072: invoke-direct {v2}, Ljava/lang/Object;.<init>:()V // method@0019
+000b8e: 4d02 0105                              |0075: aput-object v2, v1, v5
+000b92: 5b81 0900                              |0077: iput-object v1, v8, Lcom/google/android/test/Test;.aObject:[Ljava/lang/Object; // field@0009
+000b96: 1231                                   |0079: const/4 v1, #int 3 // #3
+000b98: 7020 0d00 1800                         |007a: invoke-direct {v8, v1}, Lcom/google/android/test/Test;.doit:(I)V // method@000d
+000b9e: 5a86 1200                              |007d: iput-wide v6, v8, Lcom/google/android/test/Test;.mL:J // field@0012
+000ba2: 7020 0a00 8800                         |007f: invoke-direct {v8, v8}, Lcom/google/android/test/Test;.add:(Ljava/lang/Object;)Ljava/lang/Object; // method@000a
+000ba8: 0c01                                   |0082: move-result-object v1
+000baa: 5b81 1300                              |0083: iput-object v1, v8, Lcom/google/android/test/Test;.mO:Ljava/lang/Object; // field@0013
+000bae: 7110 0b00 0800                         |0085: invoke-static {v8}, Lcom/google/android/test/Test;.adds:(Ljava/lang/Object;)Ljava/lang/Object; // method@000b
+000bb4: 0c01                                   |0088: move-result-object v1
+000bb6: 6901 1e00                              |0089: sput-object v1, Lcom/google/android/test/Test;.sO:Ljava/lang/Object; // field@001e
+000bba: 7010 0c00 0800                         |008b: invoke-direct {v8}, Lcom/google/android/test/Test;.copies:()V // method@000c
+000bc0: 7010 1600 0800                         |008e: invoke-direct {v8}, Lcom/google/android/test/Test;.seta:()V // method@0016
+000bc6: 7010 0e00 0800                         |0091: invoke-direct {v8}, Lcom/google/android/test/Test;.geta:()Z // method@000e
+000bcc: 0a01                                   |0094: move-result v1
+000bce: 3801 0900                              |0095: if-eqz v1, 009e // +0009
+000bd2: 6201 2000                              |0097: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0020
+000bd6: 1a02 7600                              |0099: const-string v2, "ok then" // string@0076
+000bda: 6e20 1700 2100                         |009b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0017
+000be0: 0e00                                   |009e: return-void
+000be2: 0d00                                   |009f: move-exception v0
+000be4: 1251                                   |00a0: const/4 v1, #int 5 // #5
+000be6: 5981 1100                              |00a1: iput v1, v8, Lcom/google/android/test/Test;.mI:I // field@0011
+000bea: 5a86 1200                              |00a3: iput-wide v6, v8, Lcom/google/android/test/Test;.mL:J // field@0012
+000bee: 28da                                   |00a5: goto 007f // -0026
+000bf0: 0d01                                   |00a6: move-exception v1
+000bf2: 5a86 1200                              |00a7: iput-wide v6, v8, Lcom/google/android/test/Test;.mL:J // field@0012
+000bf6: 2701                                   |00a9: throw v1
+000bf8: 0003 0400 0400 0000 0100 0000 0200 ... |00aa: array-data (12 units)
+000c10: 0003 0100 0200 0000 0102               |00b6: array-data (5 units)
+000c1a: 0000                                   |00bb: nop // spacer
+000c1c: 0003 0200 0200 0000 6100 6200          |00bc: array-data (6 units)
+000c28: 0003 0400 0200 0000 0100 0000 0200 ... |00c2: array-data (8 units)
+000c38: 0003 0800 0200 0000 0100 0000 0000 ... |00ca: array-data (12 units)
+000c50: 0003 0400 0200 0000 0000 803f 0000 ... |00d6: array-data (8 units)
+000c60: 0003 0800 0200 0000 0000 0000 0000 ... |00de: array-data (12 units)
+      catches       : 2
+        0x007a - 0x007d
+          Ljava/lang/Exception; -> 0x009f
+          <any> -> 0x00a6
+        0x00a1 - 0x00a3
+          <any> -> 0x00a6
+      positions     : 
+        0x0004 line=43
+        0x0007 line=18
+        0x000a line=19
+        0x000e line=20
+        0x0013 line=21
+        0x0017 line=22
+        0x001c line=23
+        0x0023 line=24
+        0x0028 line=25
+        0x002f line=26
+        0x0032 line=27
+        0x003a line=31
+        0x0040 line=32
+        0x0047 line=33
+        0x004e line=34
+        0x0052 line=35
+        0x0059 line=36
+        0x0060 line=37
+        0x0067 line=38
+        0x006e line=39
+        0x0079 line=45
+        0x007d line=49
+        0x007f line=51
+        0x0085 line=52
+        0x008b line=53
+        0x008e line=54
+        0x0091 line=55
+        0x0097 line=56
+        0x009e line=57
+        0x009f line=46
+        0x00a0 line=47
+        0x00a3 line=49
+        0x00a6 line=48
+        0x00a7 line=49
+        0x00a9 line=50
+        0x00aa line=27
+        0x00b6 line=32
+        0x00bb line=33
+        0x00c2 line=35
+        0x00ca line=36
+        0x00d6 line=37
+        0x00de line=38
+      locals        : 
+        0x00a0 - 0x00a6 reg=0 e Ljava/lang/Exception; 
+        0x0000 - 0x00ea reg=8 this Lcom/google/android/test/Test; 
+
+    #2              : (in Lcom/google/android/test/Test;)
+      name          : 'add'
+      type          : '(Ljava/lang/Object;)Ljava/lang/Object;'
+      access        : 0x20002 (PRIVATE DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 13
+      ins           : 2
+      outs          : 0
+      insns size    : 239 16-bit code units
+000c94:                                        |[000c94] com.google.android.test.Test.add:(Ljava/lang/Object;)Ljava/lang/Object;
+000ca4: 150a 8040                              |0000: const/high16 v10, #int 1082130432 // #4080
+000ca8: 1908 1040                              |0002: const-wide/high16 v8, #long 4616189618054758400 // #4010
+000cac: 1d0b                                   |0004: monitor-enter v11
+000cae: 5bbc 1300                              |0005: iput-object v12, v11, Lcom/google/android/test/Test;.mO:Ljava/lang/Object; // field@0013
+000cb2: 55b0 0d00                              |0007: iget-boolean v0, v11, Lcom/google/android/test/Test;.mBool:Z // field@000d
+000cb6: de00 0000                              |0009: or-int/lit8 v0, v0, #int 0 // #00
+000cba: 5cb0 0d00                              |000b: iput-boolean v0, v11, Lcom/google/android/test/Test;.mBool:Z // field@000d
+000cbe: 56b0 0c00                              |000d: iget-byte v0, v11, Lcom/google/android/test/Test;.mB:B // field@000c
+000cc2: d800 001f                              |000f: add-int/lit8 v0, v0, #int 31 // #1f
+000cc6: 8d00                                   |0011: int-to-byte v0, v0
+000cc8: 5db0 0c00                              |0012: iput-byte v0, v11, Lcom/google/android/test/Test;.mB:B // field@000c
+000ccc: 57b0 0e00                              |0014: iget-char v0, v11, Lcom/google/android/test/Test;.mC:C // field@000e
+000cd0: 1401 ffff 0000                         |0016: const v1, #float 0.000000 // #0000ffff
+000cd6: b010                                   |0019: add-int/2addr v0, v1
+000cd8: 8e00                                   |001a: int-to-char v0, v0
+000cda: 5eb0 0e00                              |001b: iput-char v0, v11, Lcom/google/android/test/Test;.mC:C // field@000e
+000cde: 58b0 1500                              |001d: iget-short v0, v11, Lcom/google/android/test/Test;.mS:S // field@0015
+000ce2: d000 3412                              |001f: add-int/lit16 v0, v0, #int 4660 // #1234
+000ce6: 8f00                                   |0021: int-to-short v0, v0
+000ce8: 5fb0 1500                              |0022: iput-short v0, v11, Lcom/google/android/test/Test;.mS:S // field@0015
+000cec: 52b0 1100                              |0024: iget v0, v11, Lcom/google/android/test/Test;.mI:I // field@0011
+000cf0: 1401 7856 3412                         |0026: const v1, #float 0.000000 // #12345678
+000cf6: b010                                   |0029: add-int/2addr v0, v1
+000cf8: 59b0 1100                              |002a: iput v0, v11, Lcom/google/android/test/Test;.mI:I // field@0011
+000cfc: 52b0 1100                              |002c: iget v0, v11, Lcom/google/android/test/Test;.mI:I // field@0011
+000d00: 1501 f11f                              |002e: const/high16 v1, #int 535887872 // #1ff1
+000d04: b010                                   |0030: add-int/2addr v0, v1
+000d06: 59b0 1100                              |0031: iput v0, v11, Lcom/google/android/test/Test;.mI:I // field@0011
+000d0a: 53b0 1200                              |0033: iget-wide v0, v11, Lcom/google/android/test/Test;.mL:J // field@0012
+000d0e: 1802 ffff cdab 7956 3412               |0035: const-wide v2, #double 0.000000 // #12345679abcdffff
+000d18: bb20                                   |003a: add-long/2addr v0, v2
+000d1a: 5ab0 1200                              |003b: iput-wide v0, v11, Lcom/google/android/test/Test;.mL:J // field@0012
+000d1e: 53b0 1200                              |003d: iget-wide v0, v11, Lcom/google/android/test/Test;.mL:J // field@0012
+000d22: 1902 f11f                              |003f: const-wide/high16 v2, #long 2301620884563034112 // #1ff1
+000d26: bb20                                   |0041: add-long/2addr v0, v2
+000d28: 5ab0 1200                              |0042: iput-wide v0, v11, Lcom/google/android/test/Test;.mL:J // field@0012
+000d2c: 52b0 1000                              |0044: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000d30: 1401 00e4 4046                         |0046: const v1, #float 12345.000000 // #4640e400
+000d36: 52b2 1000                              |0049: iget v2, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000d3a: 1503 803f                              |004b: const/high16 v3, #int 1065353216 // #3f80
+000d3e: c732                                   |004d: sub-float/2addr v2, v3
+000d40: c621                                   |004e: add-float/2addr v1, v2
+000d42: 52b2 1000                              |004f: iget v2, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000d46: c8a2                                   |0051: mul-float/2addr v2, v10
+000d48: 1503 c03f                              |0052: const/high16 v3, #int 1069547520 // #3fc0
+000d4c: c932                                   |0054: div-float/2addr v2, v3
+000d4e: c621                                   |0055: add-float/2addr v1, v2
+000d50: c610                                   |0056: add-float/2addr v0, v1
+000d52: 59b0 1000                              |0057: iput v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000d56: 53b0 0f00                              |0059: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000d5a: 1802 0000 0000 801c c840               |005b: const-wide v2, #double 12345.000000 // #40c81c8000000000
+000d64: 53b4 0f00                              |0060: iget-wide v4, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000d68: 1906 f03f                              |0062: const-wide/high16 v6, #long 4607182418800017408 // #3ff0
+000d6c: cc64                                   |0064: sub-double/2addr v4, v6
+000d6e: cb42                                   |0065: add-double/2addr v2, v4
+000d70: 53b4 0f00                              |0066: iget-wide v4, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000d74: cd84                                   |0068: mul-double/2addr v4, v8
+000d76: 1906 f83f                              |0069: const-wide/high16 v6, #long 4609434218613702656 // #3ff8
+000d7a: ce64                                   |006b: div-double/2addr v4, v6
+000d7c: cb42                                   |006c: add-double/2addr v2, v4
+000d7e: cb20                                   |006d: add-double/2addr v0, v2
+000d80: 5ab0 0f00                              |006e: iput-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000d84: 52b0 1000                              |0070: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000d88: 1201                                   |0072: const/4 v1, #int 0 // #0
+000d8a: 2d00 0001                              |0073: cmpl-float v0, v0, v1
+000d8e: 3800 2900                              |0075: if-eqz v0, 009e // +0029
+000d92: 52b0 1000                              |0077: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000d96: 1401 9a99 993e                         |0079: const v1, #float 0.300000 // #3e99999a
+000d9c: 2d00 0001                              |007c: cmpl-float v0, v0, v1
+000da0: 3900 2000                              |007e: if-nez v0, 009e // +0020
+000da4: 52b0 1000                              |0080: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000da8: 2d00 000a                              |0082: cmpl-float v0, v0, v10
+000dac: 3c00 1a00                              |0084: if-gtz v0, 009e // +001a
+000db0: 52b0 1000                              |0086: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000db4: 1501 c040                              |0088: const/high16 v1, #int 1086324736 // #40c0
+000db8: 2e00 0001                              |008a: cmpg-float v0, v0, v1
+000dbc: 3a00 1200                              |008c: if-ltz v0, 009e // +0012
+000dc0: 52b0 1000                              |008e: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000dc4: 1501 b0c1                              |0090: const/high16 v1, #int -1045430272 // #c1b0
+000dc8: 2e00 0001                              |0092: cmpg-float v0, v0, v1
+000dcc: 3d00 0a00                              |0094: if-lez v0, 009e // +000a
+000dd0: 52b0 1000                              |0096: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000dd4: 1501 b041                              |0098: const/high16 v1, #int 1102053376 // #41b0
+000dd8: 2d00 0001                              |009a: cmpl-float v0, v0, v1
+000ddc: 3a00 0700                              |009c: if-ltz v0, 00a3 // +0007
+000de0: 53b0 0f00                              |009e: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000de4: 8c00                                   |00a0: double-to-float v0, v0
+000de6: 59b0 1000                              |00a1: iput v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000dea: 53b0 0f00                              |00a3: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000dee: 1602 0000                              |00a5: const-wide/16 v2, #int 0 // #0
+000df2: 2f00 0002                              |00a7: cmpl-double v0, v0, v2
+000df6: 3800 2b00                              |00a9: if-eqz v0, 00d4 // +002b
+000dfa: 53b0 0f00                              |00ab: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000dfe: 1802 3333 3333 3333 d33f               |00ad: const-wide v2, #double 0.300000 // #3fd3333333333333
+000e08: 2f00 0002                              |00b2: cmpl-double v0, v0, v2
+000e0c: 3900 2000                              |00b4: if-nez v0, 00d4 // +0020
+000e10: 53b0 0f00                              |00b6: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000e14: 2f00 0008                              |00b8: cmpl-double v0, v0, v8
+000e18: 3c00 1a00                              |00ba: if-gtz v0, 00d4 // +001a
+000e1c: 53b0 0f00                              |00bc: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000e20: 1902 1840                              |00be: const-wide/high16 v2, #long 4618441417868443648 // #4018
+000e24: 3000 0002                              |00c0: cmpg-double v0, v0, v2
+000e28: 3a00 1200                              |00c2: if-ltz v0, 00d4 // +0012
+000e2c: 53b0 0f00                              |00c4: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000e30: 1902 36c0                              |00c6: const-wide/high16 v2, #long -4596486369685012480 // #c036
+000e34: 3000 0002                              |00c8: cmpg-double v0, v0, v2
+000e38: 3d00 0a00                              |00ca: if-lez v0, 00d4 // +000a
+000e3c: 53b0 0f00                              |00cc: iget-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000e40: 1902 3640                              |00ce: const-wide/high16 v2, #long 4626885667169763328 // #4036
+000e44: 2f00 0002                              |00d0: cmpl-double v0, v0, v2
+000e48: 3a00 1200                              |00d2: if-ltz v0, 00e4 // +0012
+000e4c: 52b0 1000                              |00d4: iget v0, v11, Lcom/google/android/test/Test;.mF:F // field@0010
+000e50: 8900                                   |00d6: float-to-double v0, v0
+000e52: 5ab0 0f00                              |00d7: iput-wide v0, v11, Lcom/google/android/test/Test;.mD:D // field@000f
+000e56: 6300 1800                              |00d9: sget-boolean v0, Lcom/google/android/test/Test;.sBool:Z // field@0018
+000e5a: 3900 0f00                              |00db: if-nez v0, 00ea // +000f
+000e5e: 55b0 0d00                              |00dd: iget-boolean v0, v11, Lcom/google/android/test/Test;.mBool:Z // field@000d
+000e62: 3900 0b00                              |00df: if-nez v0, 00ea // +000b
+000e66: 1200                                   |00e1: const/4 v0, #int 0 // #0
+000e68: 5cb0 0d00                              |00e2: iput-boolean v0, v11, Lcom/google/android/test/Test;.mBool:Z // field@000d
+000e6c: 390c 0400                              |00e4: if-nez v12, 00e8 // +0004
+000e70: 54bc 1300                              |00e6: iget-object v12, v11, Lcom/google/android/test/Test;.mO:Ljava/lang/Object; // field@0013
+000e74: 1e0b                                   |00e8: monitor-exit v11
+000e76: 110c                                   |00e9: return-object v12
+000e78: 1210                                   |00ea: const/4 v0, #int 1 // #1
+000e7a: 28f7                                   |00eb: goto 00e2 // -0009
+000e7c: 0d00                                   |00ec: move-exception v0
+000e7e: 1e0b                                   |00ed: monitor-exit v11
+000e80: 2700                                   |00ee: throw v0
+      catches       : 1
+        0x0005 - 0x00e8
+          <any> -> 0x00ec
+      positions     : 
+        0x0004 line=179
+        0x0007 line=180
+        0x000d line=181
+        0x0014 line=182
+        0x001d line=183
+        0x0024 line=184
+        0x002c line=185
+        0x0033 line=186
+        0x003d line=187
+        0x0044 line=188
+        0x0059 line=189
+        0x0070 line=190
+        0x009e line=191
+        0x00a3 line=193
+        0x00d4 line=194
+        0x00d9 line=195
+        0x00e4 line=197
+        0x00ea line=195
+        0x00ec line=179
+      locals        : 
+        0x0000 - 0x00e8 reg=12 o Ljava/lang/Object; 
+        0x0000 - 0x00ef reg=11 this Lcom/google/android/test/Test; 
+        0x00ea - 0x00ef reg=12 o Ljava/lang/Object; 
+
+    #3              : (in Lcom/google/android/test/Test;)
+      name          : 'adds'
+      type          : '(Ljava/lang/Object;)Ljava/lang/Object;'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 9
+      ins           : 1
+      outs          : 0
+      insns size    : 118 16-bit code units
+000e90:                                        |[000e90] com.google.android.test.Test.adds:(Ljava/lang/Object;)Ljava/lang/Object;
+000ea0: 6908 1e00                              |0000: sput-object v8, Lcom/google/android/test/Test;.sO:Ljava/lang/Object; // field@001e
+000ea4: 6300 1800                              |0002: sget-boolean v0, Lcom/google/android/test/Test;.sBool:Z // field@0018
+000ea8: de00 0000                              |0004: or-int/lit8 v0, v0, #int 0 // #00
+000eac: 6a00 1800                              |0006: sput-boolean v0, Lcom/google/android/test/Test;.sBool:Z // field@0018
+000eb0: 6400 1700                              |0008: sget-byte v0, Lcom/google/android/test/Test;.sB:B // field@0017
+000eb4: d800 001f                              |000a: add-int/lit8 v0, v0, #int 31 // #1f
+000eb8: 8d00                                   |000c: int-to-byte v0, v0
+000eba: 6b00 1700                              |000d: sput-byte v0, Lcom/google/android/test/Test;.sB:B // field@0017
+000ebe: 6500 1900                              |000f: sget-char v0, Lcom/google/android/test/Test;.sC:C // field@0019
+000ec2: 1401 ffff 0000                         |0011: const v1, #float 0.000000 // #0000ffff
+000ec8: b010                                   |0014: add-int/2addr v0, v1
+000eca: 8e00                                   |0015: int-to-char v0, v0
+000ecc: 6c00 1900                              |0016: sput-char v0, Lcom/google/android/test/Test;.sC:C // field@0019
+000ed0: 6600 1f00                              |0018: sget-short v0, Lcom/google/android/test/Test;.sS:S // field@001f
+000ed4: d000 3412                              |001a: add-int/lit16 v0, v0, #int 4660 // #1234
+000ed8: 8f00                                   |001c: int-to-short v0, v0
+000eda: 6d00 1f00                              |001d: sput-short v0, Lcom/google/android/test/Test;.sS:S // field@001f
+000ede: 6000 1c00                              |001f: sget v0, Lcom/google/android/test/Test;.sI:I // field@001c
+000ee2: 1401 7856 3412                         |0021: const v1, #float 0.000000 // #12345678
+000ee8: b010                                   |0024: add-int/2addr v0, v1
+000eea: 6700 1c00                              |0025: sput v0, Lcom/google/android/test/Test;.sI:I // field@001c
+000eee: 6000 1c00                              |0027: sget v0, Lcom/google/android/test/Test;.sI:I // field@001c
+000ef2: 1501 f11f                              |0029: const/high16 v1, #int 535887872 // #1ff1
+000ef6: b010                                   |002b: add-int/2addr v0, v1
+000ef8: 6700 1c00                              |002c: sput v0, Lcom/google/android/test/Test;.sI:I // field@001c
+000efc: 6100 1d00                              |002e: sget-wide v0, Lcom/google/android/test/Test;.sL:J // field@001d
+000f00: 1802 ffff cdab 7956 3412               |0030: const-wide v2, #double 0.000000 // #12345679abcdffff
+000f0a: bb20                                   |0035: add-long/2addr v0, v2
+000f0c: 6800 1d00                              |0036: sput-wide v0, Lcom/google/android/test/Test;.sL:J // field@001d
+000f10: 6100 1d00                              |0038: sget-wide v0, Lcom/google/android/test/Test;.sL:J // field@001d
+000f14: 1902 f11f                              |003a: const-wide/high16 v2, #long 2301620884563034112 // #1ff1
+000f18: bb20                                   |003c: add-long/2addr v0, v2
+000f1a: 6800 1d00                              |003d: sput-wide v0, Lcom/google/android/test/Test;.sL:J // field@001d
+000f1e: 6000 1b00                              |003f: sget v0, Lcom/google/android/test/Test;.sF:F // field@001b
+000f22: 1401 00e4 4046                         |0041: const v1, #float 12345.000000 // #4640e400
+000f28: 6002 1b00                              |0044: sget v2, Lcom/google/android/test/Test;.sF:F // field@001b
+000f2c: 7f22                                   |0046: neg-float v2, v2
+000f2e: 1503 803f                              |0047: const/high16 v3, #int 1065353216 // #3f80
+000f32: c732                                   |0049: sub-float/2addr v2, v3
+000f34: c621                                   |004a: add-float/2addr v1, v2
+000f36: 6002 1b00                              |004b: sget v2, Lcom/google/android/test/Test;.sF:F // field@001b
+000f3a: 1503 8040                              |004d: const/high16 v3, #int 1082130432 // #4080
+000f3e: c832                                   |004f: mul-float/2addr v2, v3
+000f40: 1503 c03f                              |0050: const/high16 v3, #int 1069547520 // #3fc0
+000f44: c932                                   |0052: div-float/2addr v2, v3
+000f46: c621                                   |0053: add-float/2addr v1, v2
+000f48: c610                                   |0054: add-float/2addr v0, v1
+000f4a: 6700 1b00                              |0055: sput v0, Lcom/google/android/test/Test;.sF:F // field@001b
+000f4e: 6100 1a00                              |0057: sget-wide v0, Lcom/google/android/test/Test;.sD:D // field@001a
+000f52: 1802 0000 0000 801c c840               |0059: const-wide v2, #double 12345.000000 // #40c81c8000000000
+000f5c: 6104 1a00                              |005e: sget-wide v4, Lcom/google/android/test/Test;.sD:D // field@001a
+000f60: 8044                                   |0060: neg-double v4, v4
+000f62: 1906 f03f                              |0061: const-wide/high16 v6, #long 4607182418800017408 // #3ff0
+000f66: cc64                                   |0063: sub-double/2addr v4, v6
+000f68: cb42                                   |0064: add-double/2addr v2, v4
+000f6a: 6104 1a00                              |0065: sget-wide v4, Lcom/google/android/test/Test;.sD:D // field@001a
+000f6e: 1906 1040                              |0067: const-wide/high16 v6, #long 4616189618054758400 // #4010
+000f72: cd64                                   |0069: mul-double/2addr v4, v6
+000f74: 1906 f83f                              |006a: const-wide/high16 v6, #long 4609434218613702656 // #3ff8
+000f78: ce64                                   |006c: div-double/2addr v4, v6
+000f7a: cb42                                   |006d: add-double/2addr v2, v4
+000f7c: cb20                                   |006e: add-double/2addr v0, v2
+000f7e: 6800 1a00                              |006f: sput-wide v0, Lcom/google/android/test/Test;.sD:D // field@001a
+000f82: 3908 0400                              |0071: if-nez v8, 0075 // +0004
+000f86: 6208 1e00                              |0073: sget-object v8, Lcom/google/android/test/Test;.sO:Ljava/lang/Object; // field@001e
+000f8a: 1108                                   |0075: return-object v8
+      catches       : (none)
+      positions     : 
+        0x0000 line=201
+        0x0002 line=202
+        0x0008 line=203
+        0x000f line=204
+        0x0018 line=205
+        0x001f line=206
+        0x0027 line=207
+        0x002e line=208
+        0x0038 line=209
+        0x003f line=210
+        0x0057 line=211
+        0x0071 line=212
+      locals        : 
+        0x0000 - 0x0075 reg=8 o Ljava/lang/Object; 
+
+    #4              : (in Lcom/google/android/test/Test;)
+      name          : 'copies'
+      type          : '()V'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 19
+      ins           : 1
+      outs          : 12
+      insns size    : 171 16-bit code units
+000f8c:                                        |[000f8c] com.google.android.test.Test.copies:()V
+000f9c: 0800 1200                              |0000: move-object/from16 v0, v18
+000fa0: 5302 1200                              |0002: iget-wide v2, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+000fa4: 7d22                                   |0004: neg-long v2, v2
+000fa6: 6104 1d00                              |0005: sget-wide v4, Lcom/google/android/test/Test;.sL:J // field@001d
+000faa: 6106 1d00                              |0007: sget-wide v6, Lcom/google/android/test/Test;.sL:J // field@001d
+000fae: bd64                                   |0009: mul-long/2addr v4, v6
+000fb0: 0800 1200                              |000a: move-object/from16 v0, v18
+000fb4: 5306 1200                              |000c: iget-wide v6, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+000fb8: be64                                   |000e: div-long/2addr v4, v6
+000fba: bc42                                   |000f: sub-long/2addr v2, v4
+000fbc: 0800 1200                              |0010: move-object/from16 v0, v18
+000fc0: 5304 1200                              |0012: iget-wide v4, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+000fc4: 1606 ffff                              |0014: const-wide/16 v6, #int -1 // #ffff
+000fc8: c264                                   |0016: xor-long/2addr v4, v6
+000fca: bc42                                   |0017: sub-long/2addr v2, v4
+000fcc: 0800 1200                              |0018: move-object/from16 v0, v18
+000fd0: 5304 1200                              |001a: iget-wide v4, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+000fd4: 1606 0400                              |001c: const-wide/16 v6, #int 4 // #4
+000fd8: bf64                                   |001e: rem-long/2addr v4, v6
+000fda: a210 0204                              |001f: xor-long v16, v2, v4
+000fde: 0800 1200                              |0021: move-object/from16 v0, v18
+000fe2: 5302 0f00                              |0023: iget-wide v2, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+000fe6: 6004 1b00                              |0025: sget v4, Lcom/google/android/test/Test;.sF:F // field@001b
+000fea: 8944                                   |0027: float-to-double v4, v4
+000fec: cd42                                   |0028: mul-double/2addr v2, v4
+000fee: 0800 1200                              |0029: move-object/from16 v0, v18
+000ff2: 5304 0f00                              |002b: iget-wide v4, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+000ff6: ce42                                   |002d: div-double/2addr v2, v4
+000ff8: 6104 1a00                              |002e: sget-wide v4, Lcom/google/android/test/Test;.sD:D // field@001a
+000ffc: 0800 1200                              |0030: move-object/from16 v0, v18
+001000: 5306 0f00                              |0032: iget-wide v6, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+001004: cd64                                   |0034: mul-double/2addr v4, v6
+001006: ac0e 0204                              |0035: sub-double v14, v2, v4
+00100a: 6302 1800                              |0037: sget-boolean v2, Lcom/google/android/test/Test;.sBool:Z // field@0018
+00100e: 0800 1200                              |0039: move-object/from16 v0, v18
+001012: 5c02 0d00                              |003b: iput-boolean v2, v0, Lcom/google/android/test/Test;.mBool:Z // field@000d
+001016: 6402 1700                              |003d: sget-byte v2, Lcom/google/android/test/Test;.sB:B // field@0017
+00101a: 0800 1200                              |003f: move-object/from16 v0, v18
+00101e: 5d02 0c00                              |0041: iput-byte v2, v0, Lcom/google/android/test/Test;.mB:B // field@000c
+001022: 6502 1900                              |0043: sget-char v2, Lcom/google/android/test/Test;.sC:C // field@0019
+001026: 0800 1200                              |0045: move-object/from16 v0, v18
+00102a: 5e02 0e00                              |0047: iput-char v2, v0, Lcom/google/android/test/Test;.mC:C // field@000e
+00102e: 6602 1f00                              |0049: sget-short v2, Lcom/google/android/test/Test;.sS:S // field@001f
+001032: 0800 1200                              |004b: move-object/from16 v0, v18
+001036: 5f02 1500                              |004d: iput-short v2, v0, Lcom/google/android/test/Test;.mS:S // field@0015
+00103a: 6002 1c00                              |004f: sget v2, Lcom/google/android/test/Test;.sI:I // field@001c
+00103e: 0800 1200                              |0051: move-object/from16 v0, v18
+001042: 5203 1100                              |0053: iget v3, v0, Lcom/google/android/test/Test;.mI:I // field@0011
+001046: b432                                   |0055: rem-int/2addr v2, v3
+001048: 0800 1200                              |0056: move-object/from16 v0, v18
+00104c: 5902 1100                              |0058: iput v2, v0, Lcom/google/android/test/Test;.mI:I // field@0011
+001050: 6102 1d00                              |005a: sget-wide v2, Lcom/google/android/test/Test;.sL:J // field@001d
+001054: 1604 ffff                              |005c: const-wide/16 v4, #int -1 // #ffff
+001058: a204 0410                              |005e: xor-long v4, v4, v16
+00105c: bb42                                   |0060: add-long/2addr v2, v4
+00105e: 0800 1200                              |0061: move-object/from16 v0, v18
+001062: 5a02 1200                              |0063: iput-wide v2, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+001066: 6002 1b00                              |0065: sget v2, Lcom/google/android/test/Test;.sF:F // field@001b
+00106a: 0800 1200                              |0067: move-object/from16 v0, v18
+00106e: 5902 1000                              |0069: iput v2, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+001072: 6102 1a00                              |006b: sget-wide v2, Lcom/google/android/test/Test;.sD:D // field@001a
+001076: cbe2                                   |006d: add-double/2addr v2, v14
+001078: 0800 1200                              |006e: move-object/from16 v0, v18
+00107c: 5a02 0f00                              |0070: iput-wide v2, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+001080: 6202 1e00                              |0072: sget-object v2, Lcom/google/android/test/Test;.sO:Ljava/lang/Object; // field@001e
+001084: 0800 1200                              |0074: move-object/from16 v0, v18
+001088: 5b02 1300                              |0076: iput-object v2, v0, Lcom/google/android/test/Test;.mO:Ljava/lang/Object; // field@0013
+00108c: 6202 1600                              |0078: sget-object v2, Lcom/google/android/test/Test;.sArray:[I // field@0016
+001090: 0800 1200                              |007a: move-object/from16 v0, v18
+001094: 5b02 0b00                              |007c: iput-object v2, v0, Lcom/google/android/test/Test;.mArray:[I // field@000b
+001098: 0800 1200                              |007e: move-object/from16 v0, v18
+00109c: 5603 0c00                              |0080: iget-byte v3, v0, Lcom/google/android/test/Test;.mB:B // field@000c
+0010a0: 0800 1200                              |0082: move-object/from16 v0, v18
+0010a4: 5704 0e00                              |0084: iget-char v4, v0, Lcom/google/android/test/Test;.mC:C // field@000e
+0010a8: 0800 1200                              |0086: move-object/from16 v0, v18
+0010ac: 5805 1500                              |0088: iget-short v5, v0, Lcom/google/android/test/Test;.mS:S // field@0015
+0010b0: 0800 1200                              |008a: move-object/from16 v0, v18
+0010b4: 5206 1100                              |008c: iget v6, v0, Lcom/google/android/test/Test;.mI:I // field@0011
+0010b8: 0800 1200                              |008e: move-object/from16 v0, v18
+0010bc: 5307 1200                              |0090: iget-wide v7, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+0010c0: 0800 1200                              |0092: move-object/from16 v0, v18
+0010c4: 5209 1000                              |0094: iget v9, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+0010c8: 0800 1200                              |0096: move-object/from16 v0, v18
+0010cc: 530a 0f00                              |0098: iget-wide v10, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+0010d0: 0800 1200                              |009a: move-object/from16 v0, v18
+0010d4: 540c 1300                              |009c: iget-object v12, v0, Lcom/google/android/test/Test;.mO:Ljava/lang/Object; // field@0013
+0010d8: 0800 1200                              |009e: move-object/from16 v0, v18
+0010dc: 540d 0b00                              |00a0: iget-object v13, v0, Lcom/google/android/test/Test;.mArray:[I // field@000b
+0010e0: 0802 1200                              |00a2: move-object/from16 v2, v18
+0010e4: 760c 1100 0200                         |00a4: invoke-direct/range {v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/test/Test;.params:(BCSIJFDLjava/lang/Object;[I)J // method@0011
+0010ea: 0b02                                   |00a7: move-result-wide v2
+0010ec: 6802 1d00                              |00a8: sput-wide v2, Lcom/google/android/test/Test;.sL:J // field@001d
+0010f0: 0e00                                   |00aa: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=216
+        0x0021 line=217
+        0x0037 line=218
+        0x003d line=219
+        0x0043 line=220
+        0x0049 line=221
+        0x004f line=222
+        0x005a line=223
+        0x0065 line=224
+        0x006b line=225
+        0x0072 line=226
+        0x0078 line=227
+        0x007e line=228
+        0x00aa line=229
+      locals        : 
+        0x0037 - 0x00ab reg=14 d D 
+        0x0021 - 0x00ab reg=16 x J 
+        0x0000 - 0x00ab reg=18 this Lcom/google/android/test/Test; 
+
+    #5              : (in Lcom/google/android/test/Test;)
+      name          : 'doit'
+      type          : '(I)V'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 3
+      ins           : 2
+      outs          : 3
+      insns size    : 78 16-bit code units
+0010f4:                                        |[0010f4] com.google.android.test.Test.doit:(I)V
+001104: 3d02 0700                              |0000: if-lez v2, 0007 // +0007
+001108: d800 02fd                              |0002: add-int/lit8 v0, v2, #int -3 // #fd
+00110c: 7020 0d00 0100                         |0004: invoke-direct {v1, v0}, Lcom/google/android/test/Test;.doit:(I)V // method@000d
+001112: 2b02 3500 0000                         |0007: packed-switch v2, 0000003c // +00000035
+001118: 2200 1300                              |000a: new-instance v0, Ljava/lang/Exception; // type@0013
+00111c: 7010 1800 0000                         |000c: invoke-direct {v0}, Ljava/lang/Exception;.<init>:()V // method@0018
+001122: 2700                                   |000f: throw v0
+001124: df00 02ff                              |0010: xor-int/lit8 v0, v2, #int -1 // #ff
+001128: 7020 1000 0100                         |0012: invoke-direct {v1, v0}, Lcom/google/android/test/Test;.p:(I)V // method@0010
+00112e: 5410 1400                              |0015: iget-object v0, v1, Lcom/google/android/test/Test;.mRunner:Ljava/lang/Runnable; // field@0014
+001132: 3800 0700                              |0017: if-eqz v0, 001e // +0007
+001136: 5410 1400                              |0019: iget-object v0, v1, Lcom/google/android/test/Test;.mRunner:Ljava/lang/Runnable; // field@0014
+00113a: 7210 1b00 0000                         |001b: invoke-interface {v0}, Ljava/lang/Runnable;.run:()V // method@001b
+001140: 2c02 2600 0000                         |001e: sparse-switch v2, 00000044 // +00000026
+001146: 0e00                                   |0021: return-void
+001148: 3d02 0700                              |0022: if-lez v2, 0029 // +0007
+00114c: 0120                                   |0024: move v0, v2
+00114e: 7030 1200 2100                         |0025: invoke-direct {v1, v2, v0}, Lcom/google/android/test/Test;.q:(II)V // method@0012
+001154: 28ed                                   |0028: goto 0015 // -0013
+001156: 7b20                                   |0029: neg-int v0, v2
+001158: 28fb                                   |002a: goto 0025 // -0005
+00115a: 7020 1000 2100                         |002b: invoke-direct {v1, v2}, Lcom/google/android/test/Test;.p:(I)V // method@0010
+001160: 5410 1400                              |002e: iget-object v0, v1, Lcom/google/android/test/Test;.mRunner:Ljava/lang/Runnable; // field@0014
+001164: 3900 f1ff                              |0030: if-nez v0, 0021 // -000f
+001168: 5b11 1400                              |0032: iput-object v1, v1, Lcom/google/android/test/Test;.mRunner:Ljava/lang/Runnable; // field@0014
+00116c: 28ed                                   |0034: goto 0021 // -0013
+00116e: d800 02ff                              |0035: add-int/lit8 v0, v2, #int -1 // #ff
+001172: 7030 1200 2100                         |0037: invoke-direct {v1, v2, v0}, Lcom/google/android/test/Test;.q:(II)V // method@0012
+001178: 28f4                                   |003a: goto 002e // -000c
+00117a: 0000                                   |003b: nop // spacer
+00117c: 0001 0200 0000 0000 0900 0000 1b00 ... |003c: packed-switch-data (8 units)
+00118c: 0002 0200 2dfb ffff 0ba2 0700 0d00 ... |0044: sparse-switch-data (10 units)
+      catches       : (none)
+      positions     : 
+        0x0000 line=98
+        0x0002 line=99
+        0x0007 line=101
+        0x000a line=104
+        0x0010 line=102
+        0x0015 line=106
+        0x0019 line=107
+        0x001e line=109
+        0x0021 line=117
+        0x0022 line=103
+        0x002b line=110
+        0x002e line=114
+        0x0032 line=115
+        0x0035 line=111
+        0x003b line=101
+        0x0044 line=109
+      locals        : 
+        0x0000 - 0x004e reg=1 this Lcom/google/android/test/Test; 
+        0x0000 - 0x004e reg=2 x I 
+
+    #6              : (in Lcom/google/android/test/Test;)
+      name          : 'geta'
+      type          : '()Z'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 8
+      ins           : 1
+      outs          : 0
+      insns size    : 73 16-bit code units
+0011a0:                                        |[0011a0] com.google.android.test.Test.geta:()Z
+0011b0: 1226                                   |0000: const/4 v6, #int 2 // #2
+0011b2: 1210                                   |0001: const/4 v0, #int 1 // #1
+0011b4: 5471 0200                              |0002: iget-object v1, v7, Lcom/google/android/test/Test;.aBool:[Z // field@0002
+0011b8: 4701 0106                              |0004: aget-boolean v1, v1, v6
+0011bc: 3801 0300                              |0006: if-eqz v1, 0009 // +0003
+0011c0: 0f00                                   |0008: return v0
+0011c2: 5471 0300                              |0009: iget-object v1, v7, Lcom/google/android/test/Test;.aByte:[B // field@0003
+0011c6: 4801 0106                              |000b: aget-byte v1, v1, v6
+0011ca: 3201 fbff                              |000d: if-eq v1, v0, 0008 // -0005
+0011ce: 5471 0400                              |000f: iget-object v1, v7, Lcom/google/android/test/Test;.aChar:[C // field@0004
+0011d2: 4901 0106                              |0011: aget-char v1, v1, v6
+0011d6: 1302 6400                              |0013: const/16 v2, #int 100 // #64
+0011da: 3221 f3ff                              |0015: if-eq v1, v2, 0008 // -000d
+0011de: 5471 0a00                              |0017: iget-object v1, v7, Lcom/google/android/test/Test;.aShort:[S // field@000a
+0011e2: 4a01 0106                              |0019: aget-short v1, v1, v6
+0011e6: 3201 edff                              |001b: if-eq v1, v0, 0008 // -0013
+0011ea: 5471 0700                              |001d: iget-object v1, v7, Lcom/google/android/test/Test;.aInt:[I // field@0007
+0011ee: 4401 0106                              |001f: aget v1, v1, v6
+0011f2: 3201 e7ff                              |0021: if-eq v1, v0, 0008 // -0019
+0011f6: 5471 0800                              |0023: iget-object v1, v7, Lcom/google/android/test/Test;.aLong:[J // field@0008
+0011fa: 4502 0106                              |0025: aget-wide v2, v1, v6
+0011fe: 1604 0100                              |0027: const-wide/16 v4, #int 1 // #1
+001202: 3101 0204                              |0029: cmp-long v1, v2, v4
+001206: 3801 ddff                              |002b: if-eqz v1, 0008 // -0023
+00120a: 5471 0600                              |002d: iget-object v1, v7, Lcom/google/android/test/Test;.aFloat:[F // field@0006
+00120e: 4401 0106                              |002f: aget v1, v1, v6
+001212: 1502 803f                              |0031: const/high16 v2, #int 1065353216 // #3f80
+001216: 2d01 0102                              |0033: cmpl-float v1, v1, v2
+00121a: 3801 d3ff                              |0035: if-eqz v1, 0008 // -002d
+00121e: 5471 0500                              |0037: iget-object v1, v7, Lcom/google/android/test/Test;.aDouble:[D // field@0005
+001222: 4502 0106                              |0039: aget-wide v2, v1, v6
+001226: 1904 f03f                              |003b: const-wide/high16 v4, #long 4607182418800017408 // #3ff0
+00122a: 2f01 0204                              |003d: cmpl-double v1, v2, v4
+00122e: 3801 c9ff                              |003f: if-eqz v1, 0008 // -0037
+001232: 5471 0900                              |0041: iget-object v1, v7, Lcom/google/android/test/Test;.aObject:[Ljava/lang/Object; // field@0009
+001236: 4601 0106                              |0043: aget-object v1, v1, v6
+00123a: 3271 c3ff                              |0045: if-eq v1, v7, 0008 // -003d
+00123e: 1200                                   |0047: const/4 v0, #int 0 // #0
+001240: 28c0                                   |0048: goto 0008 // -0040
+      catches       : (none)
+      positions     : 
+        0x0002 line=72
+        0x0008 line=81
+        0x0009 line=73
+        0x000f line=74
+        0x0017 line=75
+        0x001d line=76
+        0x0023 line=77
+        0x002d line=78
+        0x0037 line=79
+        0x0041 line=80
+        0x0047 line=81
+      locals        : 
+        0x0000 - 0x0049 reg=7 this Lcom/google/android/test/Test; 
+
+    #7              : (in Lcom/google/android/test/Test;)
+      name          : 'p'
+      type          : '(I)V'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 6
+      ins           : 2
+      outs          : 0
+      insns size    : 19 16-bit code units
+001244:                                        |[001244] com.google.android.test.Test.p:(I)V
+001254: 0151                                   |0000: move v1, v5
+001256: 1200                                   |0001: const/4 v0, #int 0 // #0
+001258: 5442 0b00                              |0002: iget-object v2, v4, Lcom/google/android/test/Test;.mArray:[I // field@000b
+00125c: 2122                                   |0004: array-length v2, v2
+00125e: 3420 0300                              |0005: if-lt v0, v2, 0008 // +0003
+001262: 0e00                                   |0007: return-void
+001264: 5442 0b00                              |0008: iget-object v2, v4, Lcom/google/android/test/Test;.mArray:[I // field@000b
+001268: 5243 1100                              |000a: iget v3, v4, Lcom/google/android/test/Test;.mI:I // field@0011
+00126c: 9303 0103                              |000c: div-int v3, v1, v3
+001270: 4b03 0200                              |000e: aput v3, v2, v0
+001274: d800 0001                              |0010: add-int/lit8 v0, v0, #int 1 // #01
+001278: 28f0                                   |0012: goto 0002 // -0010
+      catches       : (none)
+      positions     : 
+        0x0000 line=120
+        0x0001 line=121
+        0x0007 line=124
+        0x0008 line=122
+        0x0010 line=121
+      locals        : 
+        0x0002 - 0x0013 reg=0 i I 
+        0x0001 - 0x0013 reg=1 y I 
+        0x0000 - 0x0013 reg=4 this Lcom/google/android/test/Test; 
+        0x0000 - 0x0013 reg=5 x I 
+
+    #8              : (in Lcom/google/android/test/Test;)
+      name          : 'params'
+      type          : '(BCSIJFDLjava/lang/Object;[I)J'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 38
+      ins           : 12
+      outs          : 2
+      insns size    : 318 16-bit code units
+00127c:                                        |[00127c] com.google.android.test.Test.params:(BCSIJFDLjava/lang/Object;[I)J
+00128c: 0800 2400                              |0000: move-object/from16 v0, v36
+001290: 2000 1500                              |0002: instance-of v0, v0, Ljava/lang/Runnable; // type@0015
+001294: 0215 0000                              |0004: move/from16 v21, v0
+001298: 3815 0c00                              |0006: if-eqz v21, 0012 // +000c
+00129c: 0815 2400                              |0008: move-object/from16 v21, v36
+0012a0: 1f15 1500                              |000a: check-cast v21, Ljava/lang/Runnable; // type@0015
+0012a4: 0800 1500                              |000c: move-object/from16 v0, v21
+0012a8: 0801 1a00                              |000e: move-object/from16 v1, v26
+0012ac: 5b10 1400                              |0010: iput-object v0, v1, Lcom/google/android/test/Test;.mRunner:Ljava/lang/Runnable; // field@0014
+0012b0: 3825 0a00                              |0012: if-eqz v37, 001c // +000a
+0012b4: 3824 0800                              |0014: if-eqz v36, 001c // +0008
+0012b8: 7402 1a00 2400                         |0016: invoke-virtual/range {v36, v37}, Ljava/lang/Object;.equals:(Ljava/lang/Object;)Z // method@001a
+0012be: 0a15                                   |0019: move-result v21
+0012c0: 3915 3800                              |001a: if-nez v21, 0052 // +0038
+0012c4: 1315 0200                              |001c: const/16 v21, #int 2 // #2
+0012c8: 0200 1500                              |001e: move/from16 v0, v21
+0012cc: 2304 2400                              |0020: new-array v4, v0, [I // type@0024
+0012d0: 2604 0801 0000                         |0022: fill-array-data v4, 0000012a // +00000108
+0012d6: 0800 1a00                              |0025: move-object/from16 v0, v26
+0012da: 5b04 0700                              |0027: iput-object v4, v0, Lcom/google/android/test/Test;.aInt:[I // field@0007
+0012de: 1315 0200                              |0029: const/16 v21, #int 2 // #2
+0012e2: 0200 1500                              |002b: move/from16 v0, v21
+0012e6: 2305 2500                              |002d: new-array v5, v0, [J // type@0025
+0012ea: 2605 0301 0000                         |002f: fill-array-data v5, 00000132 // +00000103
+0012f0: 0800 1a00                              |0032: move-object/from16 v0, v26
+0012f4: 5b05 0800                              |0034: iput-object v5, v0, Lcom/google/android/test/Test;.aLong:[J // field@0008
+0012f8: 9015 1b1c                              |0036: add-int v21, v27, v28
+0012fc: 9015 151d                              |0038: add-int v21, v21, v29
+001300: 9015 151e                              |003a: add-int v21, v21, v30
+001304: 0200 1500                              |003c: move/from16 v0, v21
+001308: 8100                                   |003e: int-to-long v0, v0
+00130a: 0516 0000                              |003f: move-wide/from16 v22, v0
+00130e: 9b16 161f                              |0041: add-long v22, v22, v31
+001312: 0200 2100                              |0043: move/from16 v0, v33
+001316: 8800                                   |0045: float-to-long v0, v0
+001318: 0518 0000                              |0046: move-wide/from16 v24, v0
+00131c: 9b16 1618                              |0048: add-long v22, v22, v24
+001320: 0500 2200                              |004a: move-wide/from16 v0, v34
+001324: 8b00                                   |004c: double-to-long v0, v0
+001326: 0518 0000                              |004d: move-wide/from16 v24, v0
+00132a: 9b16 1618                              |004f: add-long v22, v22, v24
+00132e: 1016                                   |0051: return-wide v22
+001330: 0200 1e00                              |0052: move/from16 v0, v30
+001334: 8200                                   |0054: int-to-float v0, v0
+001336: 0221 0000                              |0055: move/from16 v33, v0
+00133a: 0200 1e00                              |0057: move/from16 v0, v30
+00133e: 8300                                   |0059: int-to-double v0, v0
+001340: 0522 0000                              |005a: move-wide/from16 v34, v0
+001344: 0800 1a00                              |005c: move-object/from16 v0, v26
+001348: 5300 1200                              |005e: iget-wide v0, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+00134c: 0516 0000                              |0060: move-wide/from16 v22, v0
+001350: 0500 1600                              |0062: move-wide/from16 v0, v22
+001354: 8400                                   |0064: long-to-int v0, v0
+001356: 0215 0000                              |0065: move/from16 v21, v0
+00135a: 0200 1500                              |0067: move/from16 v0, v21
+00135e: 0801 1a00                              |0069: move-object/from16 v1, v26
+001362: 5910 1100                              |006b: iput v0, v1, Lcom/google/android/test/Test;.mI:I // field@0011
+001366: 0800 1a00                              |006d: move-object/from16 v0, v26
+00136a: 5300 1200                              |006f: iget-wide v0, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+00136e: 0516 0000                              |0071: move-wide/from16 v22, v0
+001372: 0500 1600                              |0073: move-wide/from16 v0, v22
+001376: 7d00                                   |0075: neg-long v0, v0
+001378: 0516 0000                              |0076: move-wide/from16 v22, v0
+00137c: 0500 1600                              |0078: move-wide/from16 v0, v22
+001380: 8500                                   |007a: long-to-float v0, v0
+001382: 0221 0000                              |007b: move/from16 v33, v0
+001386: 0800 1a00                              |007d: move-object/from16 v0, v26
+00138a: 5300 1200                              |007f: iget-wide v0, v0, Lcom/google/android/test/Test;.mL:J // field@0012
+00138e: 0516 0000                              |0081: move-wide/from16 v22, v0
+001392: 1618 ffff                              |0083: const-wide/16 v24, #int -1 // #ffff
+001396: a216 1618                              |0085: xor-long v22, v22, v24
+00139a: 0500 1600                              |0087: move-wide/from16 v0, v22
+00139e: 8600                                   |0089: long-to-double v0, v0
+0013a0: 0522 0000                              |008a: move-wide/from16 v34, v0
+0013a4: 0200 2100                              |008c: move/from16 v0, v33
+0013a8: 8700                                   |008e: float-to-int v0, v0
+0013aa: 021e 0000                              |008f: move/from16 v30, v0
+0013ae: 0500 2200                              |0091: move-wide/from16 v0, v34
+0013b2: 8a00                                   |0093: double-to-int v0, v0
+0013b4: 0215 0000                              |0094: move/from16 v21, v0
+0013b8: 0200 1500                              |0096: move/from16 v0, v21
+0013bc: 0801 1a00                              |0098: move-object/from16 v1, v26
+0013c0: 5910 1100                              |009a: iput v0, v1, Lcom/google/android/test/Test;.mI:I // field@0011
+0013c4: 0800 1a00                              |009c: move-object/from16 v0, v26
+0013c8: 5200 1000                              |009e: iget v0, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+0013cc: 0215 0000                              |00a0: move/from16 v21, v0
+0013d0: 6016 1b00                              |00a2: sget v22, Lcom/google/android/test/Test;.sF:F // field@001b
+0013d4: a610 1516                              |00a4: add-float v16, v21, v22
+0013d8: 0800 1a00                              |00a6: move-object/from16 v0, v26
+0013dc: 5200 1000                              |00a8: iget v0, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+0013e0: 0215 0000                              |00aa: move/from16 v21, v0
+0013e4: 6016 1b00                              |00ac: sget v22, Lcom/google/android/test/Test;.sF:F // field@001b
+0013e8: a711 1516                              |00ae: sub-float v17, v21, v22
+0013ec: 0800 1a00                              |00b0: move-object/from16 v0, v26
+0013f0: 5200 1000                              |00b2: iget v0, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+0013f4: 0215 0000                              |00b4: move/from16 v21, v0
+0013f8: 6016 1b00                              |00b6: sget v22, Lcom/google/android/test/Test;.sF:F // field@001b
+0013fc: a912 1516                              |00b8: div-float v18, v21, v22
+001400: 0800 1a00                              |00ba: move-object/from16 v0, v26
+001404: 5200 1000                              |00bc: iget v0, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+001408: 0215 0000                              |00be: move/from16 v21, v0
+00140c: 6016 1b00                              |00c0: sget v22, Lcom/google/android/test/Test;.sF:F // field@001b
+001410: a813 1516                              |00c2: mul-float v19, v21, v22
+001414: 0800 1a00                              |00c4: move-object/from16 v0, v26
+001418: 5200 1000                              |00c6: iget v0, v0, Lcom/google/android/test/Test;.mF:F // field@0010
+00141c: 0215 0000                              |00c8: move/from16 v21, v0
+001420: 6016 1b00                              |00ca: sget v22, Lcom/google/android/test/Test;.sF:F // field@001b
+001424: aa14 1516                              |00cc: rem-float v20, v21, v22
+001428: 0800 1a00                              |00ce: move-object/from16 v0, v26
+00142c: 5300 0f00                              |00d0: iget-wide v0, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+001430: 0516 0000                              |00d2: move-wide/from16 v22, v0
+001434: 6118 1a00                              |00d4: sget-wide v24, Lcom/google/android/test/Test;.sD:D // field@001a
+001438: ab06 1618                              |00d6: add-double v6, v22, v24
+00143c: 0800 1a00                              |00d8: move-object/from16 v0, v26
+001440: 5300 0f00                              |00da: iget-wide v0, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+001444: 0516 0000                              |00dc: move-wide/from16 v22, v0
+001448: 6118 1a00                              |00de: sget-wide v24, Lcom/google/android/test/Test;.sD:D // field@001a
+00144c: ac08 1618                              |00e0: sub-double v8, v22, v24
+001450: 0800 1a00                              |00e2: move-object/from16 v0, v26
+001454: 5300 0f00                              |00e4: iget-wide v0, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+001458: 0516 0000                              |00e6: move-wide/from16 v22, v0
+00145c: 6118 1a00                              |00e8: sget-wide v24, Lcom/google/android/test/Test;.sD:D // field@001a
+001460: ae0a 1618                              |00ea: div-double v10, v22, v24
+001464: 0800 1a00                              |00ec: move-object/from16 v0, v26
+001468: 5300 0f00                              |00ee: iget-wide v0, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+00146c: 0516 0000                              |00f0: move-wide/from16 v22, v0
+001470: 6118 1a00                              |00f2: sget-wide v24, Lcom/google/android/test/Test;.sD:D // field@001a
+001474: ad0c 1618                              |00f4: mul-double v12, v22, v24
+001478: 0800 1a00                              |00f6: move-object/from16 v0, v26
+00147c: 5300 0f00                              |00f8: iget-wide v0, v0, Lcom/google/android/test/Test;.mD:D // field@000f
+001480: 0516 0000                              |00fa: move-wide/from16 v22, v0
+001484: 6118 1a00                              |00fc: sget-wide v24, Lcom/google/android/test/Test;.sD:D // field@001a
+001488: af0e 1618                              |00fe: rem-double v14, v22, v24
+00148c: 0200 1000                              |0100: move/from16 v0, v16
+001490: 7f00                                   |0102: neg-float v0, v0
+001492: 0215 0000                              |0103: move/from16 v21, v0
+001496: a615 1511                              |0105: add-float v21, v21, v17
+00149a: a816 1213                              |0107: mul-float v22, v18, v19
+00149e: a916 1614                              |0109: div-float v22, v22, v20
+0014a2: aa16 1610                              |010b: rem-float v22, v22, v16
+0014a6: a715 1516                              |010d: sub-float v21, v21, v22
+0014aa: 0200 1500                              |010f: move/from16 v0, v21
+0014ae: 0801 1a00                              |0111: move-object/from16 v1, v26
+0014b2: 5910 1000                              |0113: iput v0, v1, Lcom/google/android/test/Test;.mF:F // field@0010
+0014b6: 8060                                   |0115: neg-double v0, v6
+0014b8: 0516 0000                              |0116: move-wide/from16 v22, v0
+0014bc: ab16 1608                              |0118: add-double v22, v22, v8
+0014c0: ad18 0a0c                              |011a: mul-double v24, v10, v12
+0014c4: ae18 180e                              |011c: div-double v24, v24, v14
+0014c8: af18 1806                              |011e: rem-double v24, v24, v6
+0014cc: ac16 1618                              |0120: sub-double v22, v22, v24
+0014d0: 0500 1600                              |0122: move-wide/from16 v0, v22
+0014d4: 0802 1a00                              |0124: move-object/from16 v2, v26
+0014d8: 5a20 0f00                              |0126: iput-wide v0, v2, Lcom/google/android/test/Test;.mD:D // field@000f
+0014dc: 2900 eafe                              |0128: goto/16 0012 // -0116
+0014e0: 0003 0400 0200 0000 0100 0000 0100 ... |012a: array-data (8 units)
+0014f0: 0003 0800 0200 0000 0100 0000 0000 ... |0132: array-data (12 units)
+      catches       : (none)
+      positions     : 
+        0x0000 line=232
+        0x000a line=233
+        0x0012 line=235
+        0x001c line=256
+        0x0025 line=257
+        0x0029 line=258
+        0x0032 line=259
+        0x0036 line=260
+        0x0052 line=236
+        0x0057 line=237
+        0x005c line=238
+        0x006d line=239
+        0x007d line=240
+        0x008c line=241
+        0x0091 line=242
+        0x009c line=243
+        0x00a6 line=244
+        0x00b0 line=245
+        0x00ba line=246
+        0x00c4 line=247
+        0x00ce line=248
+        0x00d8 line=249
+        0x00e2 line=250
+        0x00ec line=251
+        0x00f6 line=252
+        0x0100 line=253
+        0x0115 line=254
+        0x012a line=256
+        0x0132 line=258
+      locals        : 
+        0x0025 - 0x0052 reg=4 aa [I 
+        0x0032 - 0x0052 reg=5 bb [J 
+        0x00d8 - 0x013e reg=6 d1 D 
+        0x00e2 - 0x013e reg=8 d2 D 
+        0x00ec - 0x013e reg=10 d3 D 
+        0x00f6 - 0x013e reg=12 d4 D 
+        0x0100 - 0x013e reg=14 d5 D 
+        0x00a6 - 0x013e reg=16 f1 F 
+        0x00b0 - 0x013e reg=17 f2 F 
+        0x00ba - 0x013e reg=18 f3 F 
+        0x00c4 - 0x013e reg=19 f4 F 
+        0x00ce - 0x013e reg=20 f5 F 
+        0x0000 - 0x013e reg=26 this Lcom/google/android/test/Test; 
+        0x0000 - 0x013e reg=27 b B 
+        0x0000 - 0x013e reg=28 c C 
+        0x0000 - 0x013e reg=29 s S 
+        0x0000 - 0x013e reg=30 i I 
+        0x0000 - 0x013e reg=31 l J 
+        0x0000 - 0x013e reg=33 f F 
+        0x0000 - 0x013e reg=34 d D 
+        0x0000 - 0x013e reg=36 o Ljava/lang/Object; 
+        0x0000 - 0x013e reg=37 a [I 
+
+    #9              : (in Lcom/google/android/test/Test;)
+      name          : 'q'
+      type          : '(II)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 10
+      ins           : 3
+      outs          : 4
+      insns size    : 85 16-bit code units
+001508:                                        |[001508] com.google.android.test.Test.q:(II)V
+001518: 1301 0a00                              |0000: const/16 v1, #int 10 // #a
+00151c: 1236                                   |0002: const/4 v6, #int 3 // #3
+00151e: 3218 0400                              |0003: if-eq v8, v1, 0007 // +0004
+001522: 3568 1000                              |0005: if-ge v8, v6, 0015 // +0010
+001526: 6200 1600                              |0007: sget-object v0, Lcom/google/android/test/Test;.sArray:[I // field@0016
+00152a: 1221                                   |0009: const/4 v1, #int 2 // #2
+00152c: 5272 1100                              |000a: iget v2, v7, Lcom/google/android/test/Test;.mI:I // field@0011
+001530: 7120 1300 2800                         |000c: invoke-static {v8, v2}, Lcom/google/android/test/Test;.r:(II)I // method@0013
+001536: 0a02                                   |000f: move-result v2
+001538: b192                                   |0010: sub-int/2addr v2, v9
+00153a: b982                                   |0011: shr-int/2addr v2, v8
+00153c: 4b02 0001                              |0012: aput v2, v0, v1
+001540: 0e00                                   |0014: return-void
+001542: 3618 1600                              |0015: if-gt v8, v1, 002b // +0016
+001546: 1300 9cff                              |0017: const/16 v0, #int -100 // #ff9c
+00154a: 3208 1200                              |0019: if-eq v8, v0, 002b // +0012
+00154e: 6200 1600                              |001b: sget-object v0, Lcom/google/android/test/Test;.sArray:[I // field@0016
+001552: 6102 1d00                              |001d: sget-wide v2, Lcom/google/android/test/Test;.sL:J // field@001d
+001556: 5374 1200                              |001f: iget-wide v4, v7, Lcom/google/android/test/Test;.mL:J // field@0012
+00155a: 7140 1500 3254                         |0021: invoke-static {v2, v3, v4, v5}, Lcom/google/android/test/Test;.s:(JJ)J // method@0015
+001560: 0b02                                   |0024: move-result-wide v2
+001562: 8421                                   |0025: long-to-int v1, v2
+001564: b291                                   |0026: mul-int/2addr v1, v9
+001566: ba81                                   |0027: ushr-int/2addr v1, v8
+001568: 4b01 0006                              |0028: aput v1, v0, v6
+00156c: 28ea                                   |002a: goto 0014 // -0016
+00156e: 1250                                   |002b: const/4 v0, #int 5 // #5
+001570: 3508 0400                              |002c: if-ge v8, v0, 0030 // +0004
+001574: 3218 0e00                              |002e: if-eq v8, v1, 003c // +000e
+001578: 6200 1600                              |0030: sget-object v0, Lcom/google/android/test/Test;.sArray:[I // field@0016
+00157c: 7120 1300 8900                         |0032: invoke-static {v9, v8}, Lcom/google/android/test/Test;.r:(II)I // method@0013
+001582: 0a01                                   |0035: move-result v1
+001584: 9802 0809                              |0036: shl-int v2, v8, v9
+001588: b721                                   |0038: xor-int/2addr v1, v2
+00158a: 4b01 0006                              |0039: aput v1, v0, v6
+00158e: 28d9                                   |003b: goto 0014 // -0027
+001590: 3398 0a00                              |003c: if-ne v8, v9, 0046 // +000a
+001594: d800 0902                              |003e: add-int/lit8 v0, v9, #int 2 // #02
+001598: 3708 0600                              |0040: if-le v8, v0, 0046 // +0006
+00159c: 3b08 0400                              |0042: if-gez v8, 0046 // +0004
+0015a0: 3c08 d0ff                              |0044: if-gtz v8, 0014 // -0030
+0015a4: 6200 1600                              |0046: sget-object v0, Lcom/google/android/test/Test;.sArray:[I // field@0016
+0015a8: df01 09ff                              |0048: xor-int/lit8 v1, v9, #int -1 // #ff
+0015ac: 9401 0801                              |004a: rem-int v1, v8, v1
+0015b0: b081                                   |004c: add-int/2addr v1, v8
+0015b2: 9202 0909                              |004d: mul-int v2, v9, v9
+0015b6: b382                                   |004f: div-int/2addr v2, v8
+0015b8: b121                                   |0050: sub-int/2addr v1, v2
+0015ba: b791                                   |0051: xor-int/2addr v1, v9
+0015bc: 4b01 0006                              |0052: aput v1, v0, v6
+0015c0: 28c0                                   |0054: goto 0014 // -0040
+      catches       : (none)
+      positions     : 
+        0x0003 line=127
+        0x0007 line=128
+        0x0014 line=136
+        0x0015 line=129
+        0x001b line=130
+        0x002b line=131
+        0x0030 line=132
+        0x003c line=133
+        0x0046 line=134
+      locals        : 
+        0x0000 - 0x0055 reg=7 this Lcom/google/android/test/Test; 
+        0x0000 - 0x0055 reg=8 x I 
+        0x0000 - 0x0055 reg=9 y I 
+
+    #10              : (in Lcom/google/android/test/Test;)
+      name          : 'r'
+      type          : '(II)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 15
+      ins           : 2
+      outs          : 0
+      insns size    : 93 16-bit code units
+0015c4:                                        |[0015c4] com.google.android.test.Test.r:(II)I
+0015d4: e00d 0d01                              |0000: shl-int/lit8 v13, v13, #int 1 // #01
+0015d8: e10d 0d03                              |0002: shr-int/lit8 v13, v13, #int 3 // #03
+0015dc: e20d 0d04                              |0004: ushr-int/lit8 v13, v13, #int 4 // #04
+0015e0: b8ed                                   |0006: shl-int/2addr v13, v14
+0015e2: b9ed                                   |0007: shr-int/2addr v13, v14
+0015e4: baed                                   |0008: ushr-int/2addr v13, v14
+0015e6: df09 0eff                              |0009: xor-int/lit8 v9, v14, #int -1 // #ff
+0015ea: 9000 0e09                              |000b: add-int v0, v14, v9
+0015ee: 9101 0e09                              |000d: sub-int v1, v14, v9
+0015f2: 9202 0e09                              |000f: mul-int v2, v14, v9
+0015f6: 9303 0e09                              |0011: div-int v3, v14, v9
+0015fa: 9704 0e09                              |0013: xor-int v4, v14, v9
+0015fe: 9505 0e09                              |0015: and-int v5, v14, v9
+001602: 9806 0e09                              |0017: shl-int v6, v14, v9
+001606: 9907 0e09                              |0019: shr-int v7, v14, v9
+00160a: 9a08 0e09                              |001b: ushr-int v8, v14, v9
+00160e: d5da ff00                              |001d: and-int/lit16 v10, v13, #int 255 // #00ff
+001612: df0b 0d12                              |001f: xor-int/lit8 v11, v13, #int 18 // #12
+001616: df0b 0bff                              |0021: xor-int/lit8 v11, v11, #int -1 // #ff
+00161a: 960d 0a0b                              |0023: or-int v13, v10, v11
+00161e: df0a 00ff                              |0025: xor-int/lit8 v10, v0, #int -1 // #ff
+001622: b01a                                   |0027: add-int/2addr v10, v1
+001624: 920b 0203                              |0028: mul-int v11, v2, v3
+001628: b34b                                   |002a: div-int/2addr v11, v4
+00162a: b1ba                                   |002b: sub-int/2addr v10, v11
+00162c: b65a                                   |002c: or-int/2addr v10, v5
+00162e: df0b 05ff                              |002d: xor-int/lit8 v11, v5, #int -1 // #ff
+001632: 920c 0607                              |002f: mul-int v12, v6, v7
+001636: b48c                                   |0031: rem-int/2addr v12, v8
+001638: b0cb                                   |0032: add-int/2addr v11, v12
+00163a: b6ba                                   |0033: or-int/2addr v10, v11
+00163c: b1ad                                   |0034: sub-int/2addr v13, v10
+00163e: 7bda                                   |0035: neg-int v10, v13
+001640: d80a 0a01                              |0036: add-int/lit8 v10, v10, #int 1 // #01
+001644: da0b 0d03                              |0038: mul-int/lit8 v11, v13, #int 3 // #03
+001648: db0b 0b02                              |003a: div-int/lit8 v11, v11, #int 2 // #02
+00164c: b1ba                                   |003c: sub-int/2addr v10, v11
+00164e: b1ea                                   |003d: sub-int/2addr v10, v14
+001650: d5db ff00                              |003e: and-int/lit16 v11, v13, #int 255 // #00ff
+001654: b0ba                                   |0040: add-int/2addr v10, v11
+001656: d4db ff00                              |0041: rem-int/lit16 v11, v13, #int 255 // #00ff
+00165a: b0ba                                   |0043: add-int/2addr v10, v11
+00165c: d0db 01ff                              |0044: add-int/lit16 v11, v13, #int -255 // #ff01
+001660: b0ba                                   |0046: add-int/2addr v10, v11
+001662: d2db ff00                              |0047: mul-int/lit16 v11, v13, #int 255 // #00ff
+001666: b0ba                                   |0049: add-int/2addr v10, v11
+001668: d3db ff00                              |004a: div-int/lit16 v11, v13, #int 255 // #00ff
+00166c: b0ba                                   |004c: add-int/2addr v10, v11
+00166e: d6db ff00                              |004d: or-int/lit16 v11, v13, #int 255 // #00ff
+001672: b0ba                                   |004f: add-int/2addr v10, v11
+001674: d7db ff00                              |0050: xor-int/lit16 v11, v13, #int 255 // #00ff
+001678: b0ba                                   |0052: add-int/2addr v10, v11
+00167a: dd0b 0d01                              |0053: and-int/lit8 v11, v13, #int 1 // #01
+00167e: b0ba                                   |0055: add-int/2addr v10, v11
+001680: dc0b 0d01                              |0056: rem-int/lit8 v11, v13, #int 1 // #01
+001684: b0ba                                   |0058: add-int/2addr v10, v11
+001686: d80b 0dff                              |0059: add-int/lit8 v11, v13, #int -1 // #ff
+00168a: b0ba                                   |005b: add-int/2addr v10, v11
+00168c: 0f0a                                   |005c: return v10
+      catches       : (none)
+      positions     : 
+        0x0000 line=139
+        0x0006 line=140
+        0x0009 line=141
+        0x000b line=142
+        0x000d line=143
+        0x000f line=144
+        0x0011 line=145
+        0x0013 line=146
+        0x0015 line=147
+        0x0017 line=148
+        0x0019 line=149
+        0x001b line=150
+        0x001d line=151
+        0x0025 line=152
+        0x0035 line=153
+        0x0047 line=154
+        0x0049 line=153
+        0x004a line=154
+        0x004c line=153
+        0x004d line=154
+        0x004f line=153
+        0x0050 line=154
+        0x0052 line=153
+        0x0053 line=155
+        0x0055 line=153
+        0x0056 line=155
+        0x0058 line=153
+        0x0059 line=155
+        0x005b line=153
+      locals        : 
+        0x000d - 0x005d reg=0 t1 I 
+        0x000f - 0x005d reg=1 t2 I 
+        0x0011 - 0x005d reg=2 t3 I 
+        0x0013 - 0x005d reg=3 t4 I 
+        0x0015 - 0x005d reg=4 t5 I 
+        0x0017 - 0x005d reg=5 t6 I 
+        0x0019 - 0x005d reg=6 t7 I 
+        0x001b - 0x005d reg=7 t8 I 
+        0x001d - 0x005d reg=8 t9 I 
+        0x000b - 0x005d reg=9 z I 
+        0x0000 - 0x005d reg=13 x I 
+        0x0000 - 0x005d reg=14 y I 
+
+    #11              : (in Lcom/google/android/test/Test;)
+      name          : 's'
+      type          : '(JJ)J'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 32
+      ins           : 4
+      outs          : 0
+      insns size    : 194 16-bit code units
+001690:                                        |[001690] com.google.android.test.Test.s:(JJ)J
+0016a0: 1316 0100                              |0000: const/16 v22, #int 1 // #1
+0016a4: a31c 1c16                              |0002: shl-long v28, v28, v22
+0016a8: 1316 0300                              |0004: const/16 v22, #int 3 // #3
+0016ac: a41c 1c16                              |0006: shr-long v28, v28, v22
+0016b0: 1316 0400                              |0008: const/16 v22, #int 4 // #4
+0016b4: a51c 1c16                              |000a: ushr-long v28, v28, v22
+0016b8: 0500 1e00                              |000c: move-wide/from16 v0, v30
+0016bc: 8400                                   |000e: long-to-int v0, v0
+0016be: 0216 0000                              |000f: move/from16 v22, v0
+0016c2: a31c 1c16                              |0011: shl-long v28, v28, v22
+0016c6: 0500 1e00                              |0013: move-wide/from16 v0, v30
+0016ca: 8400                                   |0015: long-to-int v0, v0
+0016cc: 0216 0000                              |0016: move/from16 v22, v0
+0016d0: a41c 1c16                              |0018: shr-long v28, v28, v22
+0016d4: 0500 1e00                              |001a: move-wide/from16 v0, v30
+0016d8: 8400                                   |001c: long-to-int v0, v0
+0016da: 0216 0000                              |001d: move/from16 v22, v0
+0016de: a51c 1c16                              |001f: ushr-long v28, v28, v22
+0016e2: 1616 ffff                              |0021: const-wide/16 v22, #int -1 // #ffff
+0016e6: a214 1e16                              |0023: xor-long v20, v30, v22
+0016ea: 9b02 1e14                              |0025: add-long v2, v30, v20
+0016ee: 9c04 1e14                              |0027: sub-long v4, v30, v20
+0016f2: 9d06 1e14                              |0029: mul-long v6, v30, v20
+0016f6: 9e08 1e14                              |002b: div-long v8, v30, v20
+0016fa: a20a 1e14                              |002d: xor-long v10, v30, v20
+0016fe: a00c 1e14                              |002f: and-long v12, v30, v20
+001702: 0500 1400                              |0031: move-wide/from16 v0, v20
+001706: 8400                                   |0033: long-to-int v0, v0
+001708: 0216 0000                              |0034: move/from16 v22, v0
+00170c: a30e 1e16                              |0036: shl-long v14, v30, v22
+001710: 0500 1400                              |0038: move-wide/from16 v0, v20
+001714: 8400                                   |003a: long-to-int v0, v0
+001716: 0216 0000                              |003b: move/from16 v22, v0
+00171a: a410 1e16                              |003d: shr-long v16, v30, v22
+00171e: 0500 1400                              |003f: move-wide/from16 v0, v20
+001722: 8400                                   |0041: long-to-int v0, v0
+001724: 0216 0000                              |0042: move/from16 v22, v0
+001728: a512 1e16                              |0044: ushr-long v18, v30, v22
+00172c: 1616 ff00                              |0046: const-wide/16 v22, #int 255 // #ff
+001730: a016 161c                              |0048: and-long v22, v22, v28
+001734: 1618 1200                              |004a: const-wide/16 v24, #int 18 // #12
+001738: a218 181c                              |004c: xor-long v24, v24, v28
+00173c: 161a ffff                              |004e: const-wide/16 v26, #int -1 // #ffff
+001740: a218 181a                              |0050: xor-long v24, v24, v26
+001744: a11c 1618                              |0052: or-long v28, v22, v24
+001748: 1616 ffff                              |0054: const-wide/16 v22, #int -1 // #ffff
+00174c: a216 1602                              |0056: xor-long v22, v22, v2
+001750: 9b16 1604                              |0058: add-long v22, v22, v4
+001754: 9d18 0608                              |005a: mul-long v24, v6, v8
+001758: 9e18 180a                              |005c: div-long v24, v24, v10
+00175c: 9c16 1618                              |005e: sub-long v22, v22, v24
+001760: a116 160c                              |0060: or-long v22, v22, v12
+001764: 1618 ffff                              |0062: const-wide/16 v24, #int -1 // #ffff
+001768: a218 180c                              |0064: xor-long v24, v24, v12
+00176c: 9d1a 0e10                              |0066: mul-long v26, v14, v16
+001770: 9f1a 1a12                              |0068: rem-long v26, v26, v18
+001774: 9b18 181a                              |006a: add-long v24, v24, v26
+001778: a116 1618                              |006c: or-long v22, v22, v24
+00177c: 9c1c 1c16                              |006e: sub-long v28, v28, v22
+001780: 0500 1c00                              |0070: move-wide/from16 v0, v28
+001784: 7d00                                   |0072: neg-long v0, v0
+001786: 0516 0000                              |0073: move-wide/from16 v22, v0
+00178a: 1618 0100                              |0075: const-wide/16 v24, #int 1 // #1
+00178e: 9b16 1618                              |0077: add-long v22, v22, v24
+001792: 1618 0300                              |0079: const-wide/16 v24, #int 3 // #3
+001796: 9d18 181c                              |007b: mul-long v24, v24, v28
+00179a: 161a 0200                              |007d: const-wide/16 v26, #int 2 // #2
+00179e: 9e18 181a                              |007f: div-long v24, v24, v26
+0017a2: 9c16 1618                              |0081: sub-long v22, v22, v24
+0017a6: 9c16 161e                              |0083: sub-long v22, v22, v30
+0017aa: 1618 ff00                              |0085: const-wide/16 v24, #int 255 // #ff
+0017ae: a018 181c                              |0087: and-long v24, v24, v28
+0017b2: 9b16 1618                              |0089: add-long v22, v22, v24
+0017b6: 1618 ff00                              |008b: const-wide/16 v24, #int 255 // #ff
+0017ba: 9f18 1c18                              |008d: rem-long v24, v28, v24
+0017be: 9b16 1618                              |008f: add-long v22, v22, v24
+0017c2: 1618 ff00                              |0091: const-wide/16 v24, #int 255 // #ff
+0017c6: 9c18 1c18                              |0093: sub-long v24, v28, v24
+0017ca: 9b16 1618                              |0095: add-long v22, v22, v24
+0017ce: 1618 ff00                              |0097: const-wide/16 v24, #int 255 // #ff
+0017d2: 9d18 181c                              |0099: mul-long v24, v24, v28
+0017d6: 9b16 1618                              |009b: add-long v22, v22, v24
+0017da: 1618 ff00                              |009d: const-wide/16 v24, #int 255 // #ff
+0017de: 9e18 1c18                              |009f: div-long v24, v28, v24
+0017e2: 9b16 1618                              |00a1: add-long v22, v22, v24
+0017e6: 1618 ff00                              |00a3: const-wide/16 v24, #int 255 // #ff
+0017ea: a118 181c                              |00a5: or-long v24, v24, v28
+0017ee: 9b16 1618                              |00a7: add-long v22, v22, v24
+0017f2: 1618 ff00                              |00a9: const-wide/16 v24, #int 255 // #ff
+0017f6: a218 181c                              |00ab: xor-long v24, v24, v28
+0017fa: 9b16 1618                              |00ad: add-long v22, v22, v24
+0017fe: 1618 0100                              |00af: const-wide/16 v24, #int 1 // #1
+001802: a018 181c                              |00b1: and-long v24, v24, v28
+001806: 9b16 1618                              |00b3: add-long v22, v22, v24
+00180a: 1618 0100                              |00b5: const-wide/16 v24, #int 1 // #1
+00180e: 9f18 1c18                              |00b7: rem-long v24, v28, v24
+001812: 9b16 1618                              |00b9: add-long v22, v22, v24
+001816: 1618 0100                              |00bb: const-wide/16 v24, #int 1 // #1
+00181a: 9c18 1c18                              |00bd: sub-long v24, v28, v24
+00181e: 9b16 1618                              |00bf: add-long v22, v22, v24
+001822: 1016                                   |00c1: return-wide v22
+      catches       : (none)
+      positions     : 
+        0x0000 line=159
+        0x000c line=160
+        0x0021 line=161
+        0x0025 line=162
+        0x0027 line=163
+        0x0029 line=164
+        0x002b line=165
+        0x002d line=166
+        0x002f line=167
+        0x0031 line=168
+        0x0038 line=169
+        0x003f line=170
+        0x0046 line=171
+        0x0054 line=172
+        0x0070 line=173
+        0x0097 line=174
+        0x009b line=173
+        0x009d line=174
+        0x00a1 line=173
+        0x00a3 line=174
+        0x00a7 line=173
+        0x00a9 line=174
+        0x00ad line=173
+        0x00af line=175
+        0x00b3 line=173
+        0x00b5 line=175
+        0x00b9 line=173
+        0x00bb line=175
+        0x00bf line=173
+      locals        : 
+        0x0027 - 0x00c2 reg=2 t1 J 
+        0x0029 - 0x00c2 reg=4 t2 J 
+        0x002b - 0x00c2 reg=6 t3 J 
+        0x002d - 0x00c2 reg=8 t4 J 
+        0x002f - 0x00c2 reg=10 t5 J 
+        0x0031 - 0x00c2 reg=12 t6 J 
+        0x0038 - 0x00c2 reg=14 t7 J 
+        0x003f - 0x00c2 reg=16 t8 J 
+        0x0046 - 0x00c2 reg=18 t9 J 
+        0x0025 - 0x00c2 reg=20 z J 
+        0x0000 - 0x00c2 reg=28 x J 
+        0x0000 - 0x00c2 reg=30 y J 
+
+    #12              : (in Lcom/google/android/test/Test;)
+      name          : 'seta'
+      type          : '()V'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 6
+      ins           : 1
+      outs          : 0
+      insns size    : 48 16-bit code units
+001824:                                        |[001824] com.google.android.test.Test.seta:()V
+001834: 1211                                   |0000: const/4 v1, #int 1 // #1
+001836: 1224                                   |0001: const/4 v4, #int 2 // #2
+001838: 5450 0200                              |0002: iget-object v0, v5, Lcom/google/android/test/Test;.aBool:[Z // field@0002
+00183c: 4e01 0004                              |0004: aput-boolean v1, v0, v4
+001840: 5450 0300                              |0006: iget-object v0, v5, Lcom/google/android/test/Test;.aByte:[B // field@0003
+001844: 4f01 0004                              |0008: aput-byte v1, v0, v4
+001848: 5450 0400                              |000a: iget-object v0, v5, Lcom/google/android/test/Test;.aChar:[C // field@0004
+00184c: 5004 0004                              |000c: aput-char v4, v0, v4
+001850: 5450 0a00                              |000e: iget-object v0, v5, Lcom/google/android/test/Test;.aShort:[S // field@000a
+001854: 1301 8600                              |0010: const/16 v1, #int 134 // #86
+001858: 5101 0004                              |0012: aput-short v1, v0, v4
+00185c: 5450 0700                              |0014: iget-object v0, v5, Lcom/google/android/test/Test;.aInt:[I // field@0007
+001860: 12f1                                   |0016: const/4 v1, #int -1 // #ff
+001862: 4b01 0004                              |0017: aput v1, v0, v4
+001866: 5450 0800                              |0019: iget-object v0, v5, Lcom/google/android/test/Test;.aLong:[J // field@0008
+00186a: 1602 ffff                              |001b: const-wide/16 v2, #int -1 // #ffff
+00186e: 4c02 0004                              |001d: aput-wide v2, v0, v4
+001872: 5450 0600                              |001f: iget-object v0, v5, Lcom/google/android/test/Test;.aFloat:[F // field@0006
+001876: 1501 8841                              |0021: const/high16 v1, #int 1099431936 // #4188
+00187a: 4b01 0004                              |0023: aput v1, v0, v4
+00187e: 5450 0500                              |0025: iget-object v0, v5, Lcom/google/android/test/Test;.aDouble:[D // field@0005
+001882: 1902 3240                              |0027: const-wide/high16 v2, #long 4625759767262920704 // #4032
+001886: 4c02 0004                              |0029: aput-wide v2, v0, v4
+00188a: 5450 0900                              |002b: iget-object v0, v5, Lcom/google/android/test/Test;.aObject:[Ljava/lang/Object; // field@0009
+00188e: 4d05 0004                              |002d: aput-object v5, v0, v4
+001892: 0e00                                   |002f: return-void
+      catches       : (none)
+      positions     : 
+        0x0002 line=60
+        0x0006 line=61
+        0x000a line=62
+        0x000e line=63
+        0x0014 line=64
+        0x0019 line=65
+        0x001f line=66
+        0x0025 line=67
+        0x002b line=68
+        0x002f line=69
+      locals        : 
+        0x0000 - 0x0030 reg=5 this Lcom/google/android/test/Test; 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/test/Test;)
+      name          : 'onStart'
+      type          : '()V'
+      access        : 0x0004 (PROTECTED)
+      code          -
+      registers     : 2
+      ins           : 1
+      outs          : 1
+      insns size    : 7 16-bit code units
+001894:                                        |[001894] com.google.android.test.Test.onStart:()V
+0018a4: 6f10 0300 0100                         |0000: invoke-super {v1}, Landroid/app/Activity;.onStart:()V // method@0003
+0018aa: 1200                                   |0003: const/4 v0, #int 0 // #0
+0018ac: 5b10 0b00                              |0004: iput-object v0, v1, Lcom/google/android/test/Test;.mArray:[I // field@000b
+0018b0: 0e00                                   |0006: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=86
+        0x0003 line=87
+        0x0006 line=88
+      locals        : 
+        0x0000 - 0x0007 reg=1 this Lcom/google/android/test/Test; 
+
+    #1              : (in Lcom/google/android/test/Test;)
+      name          : 'run'
+      type          : '()V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 3
+      ins           : 1
+      outs          : 0
+      insns size    : 9 16-bit code units
+0018b4:                                        |[0018b4] com.google.android.test.Test.run:()V
+0018c4: 1301 6400                              |0000: const/16 v1, #int 100 // #64
+0018c8: 2310 2400                              |0002: new-array v0, v1, [I // type@0024
+0018cc: 5b20 0b00                              |0004: iput-object v0, v2, Lcom/google/android/test/Test;.mArray:[I // field@000b
+0018d0: 6900 1600                              |0006: sput-object v0, Lcom/google/android/test/Test;.sArray:[I // field@0016
+0018d4: 0e00                                   |0008: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=92
+        0x0004 line=93
+        0x0006 line=94
+        0x0008 line=95
+      locals        : 
+        0x0004 - 0x0009 reg=0 x [I 
+        0x0000 - 0x0009 reg=2 this Lcom/google/android/test/Test; 
+
+  source_file_idx   : 49 (Test.java)
+
diff --git a/test/dexdump/bytecodes.xml b/test/dexdump/bytecodes.xml
new file mode 100755
index 0000000..0581677
--- /dev/null
+++ b/test/dexdump/bytecodes.xml
@@ -0,0 +1,163 @@
+<api>
+<package name="android.annotation"
+>
+<class name="SuppressLint"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<implements name="java.lang.annotation.Annotation">
+</implements>
+<method name="value"
+ return="java.lang.String[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+</class>
+<class name="TargetApi"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<implements name="java.lang.annotation.Annotation">
+</implements>
+<method name="value"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+<package name="com.google.android.test"
+>
+<class name="BuildConfig"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<field name="DEBUG"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ visibility="public"
+>
+</field>
+<constructor name="BuildConfig"
+ type="com.google.android.test.BuildConfig"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+</class>
+<class name="R.attr"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<constructor name="R.attr"
+ type="com.google.android.test.R.attr"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+</class>
+<class name="R.drawable"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<field name="icon"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ visibility="public"
+>
+</field>
+<constructor name="R.drawable"
+ type="com.google.android.test.R.drawable"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+</class>
+<class name="R"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<constructor name="R"
+ type="com.google.android.test.R"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+</class>
+<class name="Test"
+ extends="android.app.Activity"
+ abstract="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<implements name="java.lang.Runnable">
+</implements>
+<constructor name="Test"
+ type="com.google.android.test.Test"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+<method name="onStart"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="protected"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+</class>
+</package>
+</api>
diff --git a/test/dexdump/checkers.dex b/test/dexdump/checkers.dex
new file mode 100755
index 0000000..f8e93b4
--- /dev/null
+++ b/test/dexdump/checkers.dex
Binary files differ
diff --git a/test/dexdump/checkers.lst b/test/dexdump/checkers.lst
new file mode 100644
index 0000000..daef138
--- /dev/null
+++ b/test/dexdump/checkers.lst
@@ -0,0 +1,82 @@
+#checkers.dex
+0x0000149c 8 com.google.android.checkers.Checkers <init> ()V (none) -1
+0x000014b4 66 com.google.android.checkers.Checkers a (Z)V (none) -1
+0x00001508 8 com.google.android.checkers.Checkers onConfigurationChanged (Landroid/content/res/Configuration;)V (none) -1
+0x00001520 118 com.google.android.checkers.Checkers onCreate (Landroid/os/Bundle;)V (none) -1
+0x000015a8 432 com.google.android.checkers.Checkers onCreateOptionsMenu (Landroid/view/Menu;)Z (none) -1
+0x00001768 116 com.google.android.checkers.Checkers onKeyDown (ILandroid/view/KeyEvent;)Z (none) -1
+0x000017ec 316 com.google.android.checkers.Checkers onOptionsItemSelected (Landroid/view/MenuItem;)Z (none) -1
+0x00001938 42 com.google.android.checkers.Checkers onPause ()V (none) -1
+0x00001974 16 com.google.android.checkers.Checkers onStop ()V (none) -1
+0x00001994 88 com.google.android.checkers.Checkers onTrackballEvent (Landroid/view/MotionEvent;)Z (none) -1
+0x000019fc 1324 com.google.android.checkers.CheckersView <init> (Landroid/content/Context;Landroid/content/SharedPreferences;)V (none) -1
+0x00001f48 62 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V (none) -1
+0x00001f98 66 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences;Ljava/lang/String;[I)V (none) -1
+0x00001fec 126 com.google.android.checkers.CheckersView a (Landroid/graphics/Canvas;IIII)V (none) -1
+0x0000207c 162 com.google.android.checkers.CheckersView a (Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V (none) -1
+0x00002130 8 com.google.android.checkers.CheckersView a (Lcom/google/android/checkers/CheckersView;I)V (none) -1
+0x00002148 588 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences;)Z (none) -1
+0x000023d0 22 com.google.android.checkers.CheckersView a (Lcom/google/android/checkers/CheckersView;)Z (none) -1
+0x000023f8 1290 com.google.android.checkers.CheckersView a (ZIIII)Z (none) -1
+0x00002930 204 com.google.android.checkers.CheckersView b (FF)I (none) -1
+0x00002a20 36 com.google.android.checkers.CheckersView b (I)V (none) -1
+0x00002a60 198 com.google.android.checkers.CheckersView b (Landroid/graphics/Canvas;IIII)V (none) -1
+0x00002b38 524 com.google.android.checkers.CheckersView c (I)V (none) -1
+0x00002d54 176 com.google.android.checkers.CheckersView d ()V (none) -1
+0x00002e14 20 com.google.android.checkers.CheckersView e ()Z (none) -1
+0x00002e38 128 com.google.android.checkers.CheckersView a ()V (none) -1
+0x00002ec8 226 com.google.android.checkers.CheckersView a (FF)V (none) -1
+0x00002fd8 32 com.google.android.checkers.CheckersView a (IIII)V (none) -1
+0x00003008 340 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences$Editor;)V (none) -1
+0x00003178 34 com.google.android.checkers.CheckersView a (I)Z (none) -1
+0x000031ac 44 com.google.android.checkers.CheckersView a (Z)Z (none) -1
+0x000031f4 60 com.google.android.checkers.CheckersView b ()V (none) -1
+0x0000324c 138 com.google.android.checkers.CheckersView b (Z)Z (none) -1
+0x000032f4 16 com.google.android.checkers.CheckersView c ()I (none) -1
+0x00003320 68 com.google.android.checkers.CheckersView c (Z)Z (none) -1
+0x00003380 38 com.google.android.checkers.CheckersView d (Z)Z (none) -1
+0x000033c4 2528 com.google.android.checkers.CheckersView draw (Landroid/graphics/Canvas;)V (none) -1
+0x00003dd0 38 com.google.android.checkers.CheckersView e (Z)Z (none) -1
+0x00003e14 104 com.google.android.checkers.CheckersView onSizeChanged (IIII)V (none) -1
+0x00003e98 82 com.google.android.checkers.CheckersView onTouchEvent (Landroid/view/MotionEvent;)Z (none) -1
+0x00003efc 128 com.google.android.checkers.CheckersView setLevel (I)V (none) -1
+0x00003f98 2780 com.google.android.checkers.a <clinit> ()V (none) -1
+0x00004a84 188 com.google.android.checkers.a <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x00004b5c 28 com.google.android.checkers.a a (II)I (none) -1
+0x00004b88 2592 com.google.android.checkers.a a (IIIIIZ)I (none) -1
+0x000055b8 110 com.google.android.checkers.a a (IZ)I (none) -1
+0x00005638 196 com.google.android.checkers.a a (Z)I (none) -1
+0x0000570c 112 com.google.android.checkers.a a (ZII)I (none) -1
+0x0000578c 88 com.google.android.checkers.a a (ZIIIZ)I (none) -1
+0x000057f4 68 com.google.android.checkers.a a (ZIIZ)I (none) -1
+0x00005848 152 com.google.android.checkers.a a (IIII)V (none) -1
+0x000058f0 78 com.google.android.checkers.a a (IIIII)V (none) -1
+0x00005950 198 com.google.android.checkers.a a (IIIIIIII)V (none) -1
+0x00005a28 1750 com.google.android.checkers.a a (IZI)Z (none) -1
+0x00006110 92 com.google.android.checkers.a b (ZIIIZ)I (none) -1
+0x0000617c 112 com.google.android.checkers.a b (ZIIZ)I (none) -1
+0x000061fc 38 com.google.android.checkers.a b ()V (none) -1
+0x0000624c 736 com.google.android.checkers.a b (I)V (none) -1
+0x0000653c 198 com.google.android.checkers.a b (IIIIIIII)V (none) -1
+0x00006614 922 com.google.android.checkers.a b (IZI)Z (none) -1
+0x000069c0 108 com.google.android.checkers.a c (ZIIZ)I (none) -1
+0x00006a3c 16 com.google.android.checkers.a c ()V (none) -1
+0x00006a68 406 com.google.android.checkers.a c (IIIIIIII)V (none) -1
+0x00006c10 112 com.google.android.checkers.a d (ZIIZ)I (none) -1
+0x00006c90 16 com.google.android.checkers.a a (ZZ)I (none) -1
+0x00006cb0 90 com.google.android.checkers.a a ()V (none) -1
+0x00006d1c 8 com.google.android.checkers.a a (I)V (none) -1
+0x00006d34 74 com.google.android.checkers.a a (IIIIZ)V (none) -1
+0x00006d90 32 com.google.android.checkers.a b (ZZ)V (none) -1
+0x00006dcc 1052 com.google.android.checkers.a run ()V (none) -1
+0x000071f8 12 com.google.android.checkers.b <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x00007214 28 com.google.android.checkers.b onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x00007240 12 com.google.android.checkers.c <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x0000725c 2 com.google.android.checkers.c onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x00007270 12 com.google.android.checkers.d <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x0000728c 2 com.google.android.checkers.d onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x000072a0 12 com.google.android.checkers.e <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x000072bc 14 com.google.android.checkers.e onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x000072dc 12 com.google.android.checkers.f <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x000072f8 12 com.google.android.checkers.f onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x00007314 58 com.google.android.checkers.g a ([B)Z (none) -1
diff --git a/test/dexdump/checkers.txt b/test/dexdump/checkers.txt
new file mode 100755
index 0000000..5c8336f
--- /dev/null
+++ b/test/dexdump/checkers.txt
@@ -0,0 +1,7821 @@
+Processing 'checkers.dex'...
+Opened 'checkers.dex', DEX version '035'
+DEX file header:
+magic               : 'dex\n035\0'
+checksum            : 3ce07f0d
+signature           : 6aca...3cae
+file_size           : 35384
+header_size         : 112
+link_size           : 0
+link_off            : 0 (0x000000)
+string_ids_size     : 323
+string_ids_off      : 112 (0x000070)
+type_ids_size       : 58
+type_ids_off        : 1404 (0x00057c)
+proto_ids_size       : 88
+proto_ids_off        : 1636 (0x000664)
+field_ids_size      : 108
+field_ids_off       : 2692 (0x000a84)
+method_ids_size     : 177
+method_ids_off      : 3556 (0x000de4)
+class_defs_size     : 9
+class_defs_off      : 4972 (0x00136c)
+data_size           : 30124
+data_off            : 5260 (0x00148c)
+
+Class #0 header:
+class_idx           : 30
+access_flags        : 1 (0x0001)
+superclass_idx      : 4
+interfaces_off      : 0 (0x000000)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 34554 (0x0086fa)
+static_fields_size  : 0
+instance_fields_size: 1
+direct_methods_size : 2
+virtual_methods_size: 8
+
+Class #0            -
+  Class descriptor  : 'Lcom/google/android/checkers/Checkers;'
+  Access flags      : 0x0001 (PUBLIC)
+  Superclass        : 'Landroid/app/Activity;'
+  Interfaces        -
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'a'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x0002 (PRIVATE)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/Checkers;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 1
+      insns size    : 4 16-bit code units
+00148c:                                        |[00148c] com.google.android.checkers.Checkers.<init>:()V
+00149c: 7010 0000 0000                         |0000: invoke-direct {v0}, Landroid/app/Activity;.<init>:()V // method@0000
+0014a2: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #1              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'a'
+      type          : '(Z)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 4
+      ins           : 2
+      outs          : 2
+      insns size    : 33 16-bit code units
+0014a4:                                        |[0014a4] com.google.android.checkers.Checkers.a:(Z)V
+0014b4: 6e10 4100 0200                         |0000: invoke-virtual {v2}, Lcom/google/android/checkers/Checkers;.getWindow:()Landroid/view/Window; // method@0041
+0014ba: 0c00                                   |0003: move-result-object v0
+0014bc: 3803 1200                              |0004: if-eqz v3, 0016 // +0012
+0014c0: 1301 8004                              |0006: const/16 v1, #int 1152 // #480
+0014c4: 6e20 3a00 1000                         |0008: invoke-virtual {v0, v1}, Landroid/view/Window;.addFlags:(I)V // method@003a
+0014ca: 1301 0008                              |000b: const/16 v1, #int 2048 // #800
+0014ce: 6e20 3b00 1000                         |000d: invoke-virtual {v0, v1}, Landroid/view/Window;.clearFlags:(I)V // method@003b
+0014d4: 5420 0100                              |0010: iget-object v0, v2, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0014d8: 6e10 6f00 0000                         |0012: invoke-virtual {v0}, Lcom/google/android/checkers/CheckersView;.requestLayout:()V // method@006f
+0014de: 0e00                                   |0015: return-void
+0014e0: 1301 8008                              |0016: const/16 v1, #int 2176 // #880
+0014e4: 6e20 3a00 1000                         |0018: invoke-virtual {v0, v1}, Landroid/view/Window;.addFlags:(I)V // method@003a
+0014ea: 1301 0004                              |001b: const/16 v1, #int 1024 // #400
+0014ee: 6e20 3b00 1000                         |001d: invoke-virtual {v0, v1}, Landroid/view/Window;.clearFlags:(I)V // method@003b
+0014f4: 28f0                                   |0020: goto 0010 // -0010
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onConfigurationChanged'
+      type          : '(Landroid/content/res/Configuration;)V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 2
+      insns size    : 4 16-bit code units
+0014f8:                                        |[0014f8] com.google.android.checkers.Checkers.onConfigurationChanged:(Landroid/content/res/Configuration;)V
+001508: 6f20 0100 1000                         |0000: invoke-super {v0, v1}, Landroid/app/Activity;.onConfigurationChanged:(Landroid/content/res/Configuration;)V // method@0001
+00150e: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #1              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onCreate'
+      type          : '(Landroid/os/Bundle;)V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 8
+      ins           : 2
+      outs          : 3
+      insns size    : 59 16-bit code units
+001510:                                        |[001510] com.google.android.checkers.Checkers.onCreate:(Landroid/os/Bundle;)V
+001520: 1215                                   |0000: const/4 v5, #int 1 // #1
+001522: 1201                                   |0001: const/4 v1, #int 0 // #0
+001524: 6f20 0200 7600                         |0002: invoke-super {v6, v7}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0002
+00152a: 6e20 4a00 5600                         |0005: invoke-virtual {v6, v5}, Lcom/google/android/checkers/Checkers;.requestWindowFeature:(I)Z // method@004a
+001530: 2200 1f00                              |0008: new-instance v0, Lcom/google/android/checkers/CheckersView; // type@001f
+001534: 6e20 4000 1600                         |000a: invoke-virtual {v6, v1}, Lcom/google/android/checkers/Checkers;.getPreferences:(I)Landroid/content/SharedPreferences; // method@0040
+00153a: 0c02                                   |000d: move-result-object v2
+00153c: 7030 4d00 6002                         |000e: invoke-direct {v0, v6, v2}, Lcom/google/android/checkers/CheckersView;.<init>:(Landroid/content/Context;Landroid/content/SharedPreferences;)V // method@004d
+001542: 5b60 0100                              |0011: iput-object v0, v6, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001546: 1a03 b500                              |0013: const-string v3, "by Aart J.C. Bik" // string@00b5
+00154a: 0110                                   |0015: move v0, v1
+00154c: 0112                                   |0016: move v2, v1
+00154e: 6e10 a400 0300                         |0017: invoke-virtual {v3}, Ljava/lang/String;.length:()I // method@00a4
+001554: 0a04                                   |001a: move-result v4
+001556: 3440 1800                              |001b: if-lt v0, v4, 0033 // +0018
+00155a: 1300 c204                              |001d: const/16 v0, #int 1218 // #4c2
+00155e: 3202 0500                              |001f: if-eq v2, v0, 0024 // +0005
+001562: 7110 ac00 0500                         |0021: invoke-static {v5}, Ljava/lang/System;.exit:(I)V // method@00ac
+001568: 5460 0100                              |0024: iget-object v0, v6, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+00156c: 6e20 4b00 0600                         |0026: invoke-virtual {v6, v0}, Lcom/google/android/checkers/Checkers;.setContentView:(Landroid/view/View;)V // method@004b
+001572: 5460 0100                              |0029: iget-object v0, v6, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001576: 6e20 6500 1000                         |002b: invoke-virtual {v0, v1}, Lcom/google/android/checkers/CheckersView;.d:(Z)Z // method@0065
+00157c: 0a00                                   |002e: move-result v0
+00157e: 7020 3f00 0600                         |002f: invoke-direct {v6, v0}, Lcom/google/android/checkers/Checkers;.a:(Z)V // method@003f
+001584: 0e00                                   |0032: return-void
+001586: 6e20 a300 0300                         |0033: invoke-virtual {v3, v0}, Ljava/lang/String;.charAt:(I)C // method@00a3
+00158c: 0a04                                   |0036: move-result v4
+00158e: b042                                   |0037: add-int/2addr v2, v4
+001590: d800 0001                              |0038: add-int/lit8 v0, v0, #int 1 // #01
+001594: 28dd                                   |003a: goto 0017 // -0023
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #2              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onCreateOptionsMenu'
+      type          : '(Landroid/view/Menu;)Z'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 11
+      ins           : 2
+      outs          : 5
+      insns size    : 216 16-bit code units
+001598:                                        |[001598] com.google.android.checkers.Checkers.onCreateOptionsMenu:(Landroid/view/Menu;)Z
+0015a8: 1248                                   |0000: const/4 v8, #int 4 // #4
+0015aa: 1237                                   |0001: const/4 v7, #int 3 // #3
+0015ac: 1226                                   |0002: const/4 v6, #int 2 // #2
+0015ae: 1205                                   |0003: const/4 v5, #int 0 // #0
+0015b0: 1214                                   |0004: const/4 v4, #int 1 // #1
+0015b2: 6f20 0300 a900                         |0005: invoke-super {v9, v10}, Landroid/app/Activity;.onCreateOptionsMenu:(Landroid/view/Menu;)Z // method@0003
+0015b8: 1a00 7400                              |0008: const-string v0, "New Game" // string@0074
+0015bc: 7250 2b00 5a55                         |000a: invoke-interface {v10, v5, v5, v5, v0}, Landroid/view/Menu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@002b
+0015c2: 1a00 8200                              |000d: const-string v0, "Undo" // string@0082
+0015c6: 7250 2b00 5a44                         |000f: invoke-interface {v10, v5, v4, v4, v0}, Landroid/view/Menu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@002b
+0015cc: 1a00 8000                              |0012: const-string v0, "Switch Side" // string@0080
+0015d0: 7250 2b00 5a66                         |0014: invoke-interface {v10, v5, v6, v6, v0}, Landroid/view/Menu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@002b
+0015d6: 1a00 7800                              |0017: const-string v0, "Options" // string@0078
+0015da: 7250 2c00 5a77                         |0019: invoke-interface {v10, v5, v7, v7, v0}, Landroid/view/Menu;.addSubMenu:(IIILjava/lang/CharSequence;)Landroid/view/SubMenu; // method@002c
+0015e0: 0c00                                   |001c: move-result-object v0
+0015e2: 1a01 7100                              |001d: const-string v1, "Move Coach" // string@0071
+0015e6: 7251 3400 4055                         |001f: invoke-interface {v0, v4, v5, v5, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0015ec: 0c01                                   |0022: move-result-object v1
+0015ee: 7220 2f00 4100                         |0023: invoke-interface {v1, v4}, Landroid/view/MenuItem;.setCheckable:(Z)Landroid/view/MenuItem; // method@002f
+0015f4: 0c01                                   |0026: move-result-object v1
+0015f6: 5492 0100                              |0027: iget-object v2, v9, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0015fa: 6e20 5a00 5200                         |0029: invoke-virtual {v2, v5}, Lcom/google/android/checkers/CheckersView;.a:(Z)Z // method@005a
+001600: 0a02                                   |002c: move-result v2
+001602: 7220 3000 2100                         |002d: invoke-interface {v1, v2}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+001608: 1a01 7700                              |0030: const-string v1, "Optional Jumps" // string@0077
+00160c: 7251 3400 4044                         |0032: invoke-interface {v0, v4, v4, v4, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+001612: 0c01                                   |0035: move-result-object v1
+001614: 7220 2f00 4100                         |0036: invoke-interface {v1, v4}, Landroid/view/MenuItem;.setCheckable:(Z)Landroid/view/MenuItem; // method@002f
+00161a: 0c01                                   |0039: move-result-object v1
+00161c: 5492 0100                              |003a: iget-object v2, v9, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001620: 6e20 6000 5200                         |003c: invoke-virtual {v2, v5}, Lcom/google/android/checkers/CheckersView;.b:(Z)Z // method@0060
+001626: 0a02                                   |003f: move-result v2
+001628: 7220 3000 2100                         |0040: invoke-interface {v1, v2}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+00162e: 1a01 9800                              |0043: const-string v1, "View from White" // string@0098
+001632: 7251 3400 4066                         |0045: invoke-interface {v0, v4, v6, v6, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+001638: 0c01                                   |0048: move-result-object v1
+00163a: 7220 2f00 4100                         |0049: invoke-interface {v1, v4}, Landroid/view/MenuItem;.setCheckable:(Z)Landroid/view/MenuItem; // method@002f
+001640: 0c01                                   |004c: move-result-object v1
+001642: 5492 0100                              |004d: iget-object v2, v9, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001646: 6e20 6300 5200                         |004f: invoke-virtual {v2, v5}, Lcom/google/android/checkers/CheckersView;.c:(Z)Z // method@0063
+00164c: 0a02                                   |0052: move-result v2
+00164e: 7220 3000 2100                         |0053: invoke-interface {v1, v2}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+001654: 1a01 1800                              |0056: const-string v1, "Full Screen" // string@0018
+001658: 7251 3400 4077                         |0058: invoke-interface {v0, v4, v7, v7, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+00165e: 0c01                                   |005b: move-result-object v1
+001660: 7220 2f00 4100                         |005c: invoke-interface {v1, v4}, Landroid/view/MenuItem;.setCheckable:(Z)Landroid/view/MenuItem; // method@002f
+001666: 0c01                                   |005f: move-result-object v1
+001668: 5492 0100                              |0060: iget-object v2, v9, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+00166c: 6e20 6500 5200                         |0062: invoke-virtual {v2, v5}, Lcom/google/android/checkers/CheckersView;.d:(Z)Z // method@0065
+001672: 0a02                                   |0065: move-result v2
+001674: 7220 3000 2100                         |0066: invoke-interface {v1, v2}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+00167a: 1a01 7e00                              |0069: const-string v1, "Start Screen" // string@007e
+00167e: 7251 3400 4088                         |006b: invoke-interface {v0, v4, v8, v8, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+001684: 0c01                                   |006e: move-result-object v1
+001686: 7220 2f00 4100                         |006f: invoke-interface {v1, v4}, Landroid/view/MenuItem;.setCheckable:(Z)Landroid/view/MenuItem; // method@002f
+00168c: 0c01                                   |0072: move-result-object v1
+00168e: 5492 0100                              |0073: iget-object v2, v9, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001692: 6e20 6800 5200                         |0075: invoke-virtual {v2, v5}, Lcom/google/android/checkers/CheckersView;.e:(Z)Z // method@0068
+001698: 0a02                                   |0078: move-result v2
+00169a: 7220 3000 2100                         |0079: invoke-interface {v1, v2}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+0016a0: 1251                                   |007c: const/4 v1, #int 5 // #5
+0016a2: 1252                                   |007d: const/4 v2, #int 5 // #5
+0016a4: 1a03 0d00                              |007e: const-string v3, "Board Color" // string@000d
+0016a8: 7253 3400 4021                         |0080: invoke-interface {v0, v4, v1, v2, v3}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016ae: 1a00 5800                              |0083: const-string v0, "Level" // string@0058
+0016b2: 7250 2c00 5a88                         |0085: invoke-interface {v10, v5, v8, v8, v0}, Landroid/view/Menu;.addSubMenu:(IIILjava/lang/CharSequence;)Landroid/view/SubMenu; // method@002c
+0016b8: 0c00                                   |0088: move-result-object v0
+0016ba: 1a01 1700                              |0089: const-string v1, "Free Play" // string@0017
+0016be: 7251 3400 6055                         |008b: invoke-interface {v0, v6, v5, v5, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016c4: 1a01 7b00                              |008e: const-string v1, "Random (0s)" // string@007b
+0016c8: 7251 3400 6044                         |0090: invoke-interface {v0, v6, v4, v4, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016ce: 1a01 5900                              |0093: const-string v1, "Level 1 (fast)" // string@0059
+0016d2: 7251 3400 6066                         |0095: invoke-interface {v0, v6, v6, v6, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016d8: 1a01 5a00                              |0098: const-string v1, "Level 2 (1s)" // string@005a
+0016dc: 7251 3400 6077                         |009a: invoke-interface {v0, v6, v7, v7, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016e2: 1a01 5b00                              |009d: const-string v1, "Level 3 (5s)" // string@005b
+0016e6: 7251 3400 6088                         |009f: invoke-interface {v0, v6, v8, v8, v1}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016ec: 1251                                   |00a2: const/4 v1, #int 5 // #5
+0016ee: 1252                                   |00a3: const/4 v2, #int 5 // #5
+0016f0: 1a03 5c00                              |00a4: const-string v3, "Level 4 (10s)" // string@005c
+0016f4: 7253 3400 6021                         |00a6: invoke-interface {v0, v6, v1, v2, v3}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+0016fa: 1261                                   |00a9: const/4 v1, #int 6 // #6
+0016fc: 1262                                   |00aa: const/4 v2, #int 6 // #6
+0016fe: 1a03 5d00                              |00ab: const-string v3, "Level 5 (15s)" // string@005d
+001702: 7253 3400 6021                         |00ad: invoke-interface {v0, v6, v1, v2, v3}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+001708: 1271                                   |00b0: const/4 v1, #int 7 // #7
+00170a: 1272                                   |00b1: const/4 v2, #int 7 // #7
+00170c: 1a03 5e00                              |00b2: const-string v3, "Level 6 (30s)" // string@005e
+001710: 7253 3400 6021                         |00b4: invoke-interface {v0, v6, v1, v2, v3}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+001716: 1301 0800                              |00b7: const/16 v1, #int 8 // #8
+00171a: 1302 0800                              |00b9: const/16 v2, #int 8 // #8
+00171e: 1a03 5f00                              |00bb: const-string v3, "Level 7 (60s)" // string@005f
+001722: 7253 3400 6021                         |00bd: invoke-interface {v0, v6, v1, v2, v3}, Landroid/view/SubMenu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@0034
+001728: 7240 3600 6044                         |00c0: invoke-interface {v0, v6, v4, v4}, Landroid/view/SubMenu;.setGroupCheckable:(IZZ)V // method@0036
+00172e: 5491 0100                              |00c3: iget-object v1, v9, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001732: 6e10 6100 0100                         |00c5: invoke-virtual {v1}, Lcom/google/android/checkers/CheckersView;.c:()I // method@0061
+001738: 0a01                                   |00c8: move-result v1
+00173a: 7220 3500 1000                         |00c9: invoke-interface {v0, v1}, Landroid/view/SubMenu;.findItem:(I)Landroid/view/MenuItem; // method@0035
+001740: 0c00                                   |00cc: move-result-object v0
+001742: 7220 3000 4000                         |00cd: invoke-interface {v0, v4}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+001748: 1250                                   |00d0: const/4 v0, #int 5 // #5
+00174a: 1251                                   |00d1: const/4 v1, #int 5 // #5
+00174c: 1a02 9b00                              |00d2: const-string v2, "Website" // string@009b
+001750: 7252 2b00 5a10                         |00d4: invoke-interface {v10, v5, v0, v1, v2}, Landroid/view/Menu;.add:(IIILjava/lang/CharSequence;)Landroid/view/MenuItem; // method@002b
+001756: 0f04                                   |00d7: return v4
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #3              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onKeyDown'
+      type          : '(ILandroid/view/KeyEvent;)Z'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 8
+      ins           : 3
+      outs          : 3
+      insns size    : 58 16-bit code units
+001758:                                        |[001758] com.google.android.checkers.Checkers.onKeyDown:(ILandroid/view/KeyEvent;)Z
+001768: 1504 803f                              |0000: const/high16 v4, #int 1065353216 // #3f80
+00176c: 1503 80bf                              |0002: const/high16 v3, #int -1082130432 // #bf80
+001770: 1202                                   |0004: const/4 v2, #int 0 // #0
+001772: 1210                                   |0005: const/4 v0, #int 1 // #1
+001774: 2b06 2600 0000                         |0006: packed-switch v6, 0000002c // +00000026
+00177a: 6f30 0400 6507                         |0009: invoke-super {v5, v6, v7}, Landroid/app/Activity;.onKeyDown:(ILandroid/view/KeyEvent;)Z // method@0004
+001780: 0a00                                   |000c: move-result v0
+001782: 0f00                                   |000d: return v0
+001784: 5451 0100                              |000e: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001788: 6e10 5d00 0100                         |0010: invoke-virtual {v1}, Lcom/google/android/checkers/CheckersView;.b:()V // method@005d
+00178e: 28fa                                   |0013: goto 000d // -0006
+001790: 5451 0100                              |0014: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001794: 6e30 4f00 3102                         |0016: invoke-virtual {v1, v3, v2}, Lcom/google/android/checkers/CheckersView;.a:(FF)V // method@004f
+00179a: 28f4                                   |0019: goto 000d // -000c
+00179c: 5451 0100                              |001a: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0017a0: 6e30 4f00 4102                         |001c: invoke-virtual {v1, v4, v2}, Lcom/google/android/checkers/CheckersView;.a:(FF)V // method@004f
+0017a6: 28ee                                   |001f: goto 000d // -0012
+0017a8: 5451 0100                              |0020: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0017ac: 6e30 4f00 2103                         |0022: invoke-virtual {v1, v2, v3}, Lcom/google/android/checkers/CheckersView;.a:(FF)V // method@004f
+0017b2: 28e8                                   |0025: goto 000d // -0018
+0017b4: 5451 0100                              |0026: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0017b8: 6e30 4f00 2104                         |0028: invoke-virtual {v1, v2, v4}, Lcom/google/android/checkers/CheckersView;.a:(FF)V // method@004f
+0017be: 28e2                                   |002b: goto 000d // -001e
+0017c0: 0001 0500 1300 0000 1a00 0000 2000 ... |002c: packed-switch-data (14 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #4              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onOptionsItemSelected'
+      type          : '(Landroid/view/MenuItem;)Z'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 7
+      ins           : 2
+      outs          : 3
+      insns size    : 158 16-bit code units
+0017dc:                                        |[0017dc] com.google.android.checkers.Checkers.onOptionsItemSelected:(Landroid/view/MenuItem;)Z
+0017ec: 1254                                   |0000: const/4 v4, #int 5 // #5
+0017ee: 1223                                   |0001: const/4 v3, #int 2 // #2
+0017f0: 1210                                   |0002: const/4 v0, #int 1 // #1
+0017f2: 7210 2e00 0600                         |0003: invoke-interface {v6}, Landroid/view/MenuItem;.getItemId:()I // method@002e
+0017f8: 0a01                                   |0006: move-result v1
+0017fa: 7210 2d00 0600                         |0007: invoke-interface {v6}, Landroid/view/MenuItem;.getGroupId:()I // method@002d
+001800: 0a02                                   |000a: move-result v2
+001802: 2b02 8900 0000                         |000b: packed-switch v2, 00000094 // +00000089
+001808: 6f20 0500 6500                         |000e: invoke-super {v5, v6}, Landroid/app/Activity;.onOptionsItemSelected:(Landroid/view/MenuItem;)Z // method@0005
+00180e: 0a00                                   |0011: move-result v0
+001810: 0f00                                   |0012: return v0
+001812: 3901 0900                              |0013: if-nez v1, 001c // +0009
+001816: 5451 0100                              |0015: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+00181a: 12d2                                   |0017: const/4 v2, #int -3 // #fd
+00181c: 6e20 5700 2100                         |0018: invoke-virtual {v1, v2}, Lcom/google/android/checkers/CheckersView;.a:(I)Z // method@0057
+001822: 28f7                                   |001b: goto 0012 // -0009
+001824: 3301 0900                              |001c: if-ne v1, v0, 0025 // +0009
+001828: 5451 0100                              |001e: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+00182c: 12e2                                   |0020: const/4 v2, #int -2 // #fe
+00182e: 6e20 5700 2100                         |0021: invoke-virtual {v1, v2}, Lcom/google/android/checkers/CheckersView;.a:(I)Z // method@0057
+001834: 28ee                                   |0024: goto 0012 // -0012
+001836: 3331 0900                              |0025: if-ne v1, v3, 002e // +0009
+00183a: 5451 0100                              |0027: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+00183e: 12c2                                   |0029: const/4 v2, #int -4 // #fc
+001840: 6e20 5700 2100                         |002a: invoke-virtual {v1, v2}, Lcom/google/android/checkers/CheckersView;.a:(I)Z // method@0057
+001846: 28e5                                   |002d: goto 0012 // -001b
+001848: 3341 e0ff                              |002e: if-ne v1, v4, 000e // -0020
+00184c: 1a01 e300                              |0030: const-string v1, "http://www.aartbik.com/MISC/android.html" // string@00e3
+001850: 7110 2900 0100                         |0032: invoke-static {v1}, Landroid/net/Uri;.parse:(Ljava/lang/String;)Landroid/net/Uri; // method@0029
+001856: 0c01                                   |0035: move-result-object v1
+001858: 2202 0a00                              |0036: new-instance v2, Landroid/content/Intent; // type@000a
+00185c: 1a03 af00                              |0038: const-string v3, "android.intent.action.VIEW" // string@00af
+001860: 7030 1200 3201                         |003a: invoke-direct {v2, v3, v1}, Landroid/content/Intent;.<init>:(Ljava/lang/String;Landroid/net/Uri;)V // method@0012
+001866: 6e20 4c00 2500                         |003d: invoke-virtual {v5, v2}, Lcom/google/android/checkers/Checkers;.startActivity:(Landroid/content/Intent;)V // method@004c
+00186c: 28d2                                   |0040: goto 0012 // -002e
+00186e: 3901 0c00                              |0041: if-nez v1, 004d // +000c
+001872: 5451 0100                              |0043: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001876: 6e20 5a00 0100                         |0045: invoke-virtual {v1, v0}, Lcom/google/android/checkers/CheckersView;.a:(Z)Z // method@005a
+00187c: 0a01                                   |0048: move-result v1
+00187e: 7220 3000 1600                         |0049: invoke-interface {v6, v1}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+001884: 28c6                                   |004c: goto 0012 // -003a
+001886: 3301 0c00                              |004d: if-ne v1, v0, 0059 // +000c
+00188a: 5451 0100                              |004f: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+00188e: 6e20 6000 0100                         |0051: invoke-virtual {v1, v0}, Lcom/google/android/checkers/CheckersView;.b:(Z)Z // method@0060
+001894: 0a01                                   |0054: move-result v1
+001896: 7220 3000 1600                         |0055: invoke-interface {v6, v1}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+00189c: 28ba                                   |0058: goto 0012 // -0046
+00189e: 3331 0c00                              |0059: if-ne v1, v3, 0065 // +000c
+0018a2: 5451 0100                              |005b: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0018a6: 6e20 6300 0100                         |005d: invoke-virtual {v1, v0}, Lcom/google/android/checkers/CheckersView;.c:(Z)Z // method@0063
+0018ac: 0a01                                   |0060: move-result v1
+0018ae: 7220 3000 1600                         |0061: invoke-interface {v6, v1}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+0018b4: 28ae                                   |0064: goto 0012 // -0052
+0018b6: 1232                                   |0065: const/4 v2, #int 3 // #3
+0018b8: 3321 0f00                              |0066: if-ne v1, v2, 0075 // +000f
+0018bc: 5451 0100                              |0068: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0018c0: 6e20 6500 0100                         |006a: invoke-virtual {v1, v0}, Lcom/google/android/checkers/CheckersView;.d:(Z)Z // method@0065
+0018c6: 0a01                                   |006d: move-result v1
+0018c8: 7220 3000 1600                         |006e: invoke-interface {v6, v1}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+0018ce: 7020 3f00 1500                         |0071: invoke-direct {v5, v1}, Lcom/google/android/checkers/Checkers;.a:(Z)V // method@003f
+0018d4: 289e                                   |0074: goto 0012 // -0062
+0018d6: 1242                                   |0075: const/4 v2, #int 4 // #4
+0018d8: 3321 0c00                              |0076: if-ne v1, v2, 0082 // +000c
+0018dc: 5451 0100                              |0078: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0018e0: 6e20 6800 0100                         |007a: invoke-virtual {v1, v0}, Lcom/google/android/checkers/CheckersView;.e:(Z)Z // method@0068
+0018e6: 0a01                                   |007d: move-result v1
+0018e8: 7220 3000 1600                         |007e: invoke-interface {v6, v1}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+0018ee: 2891                                   |0081: goto 0012 // -006f
+0018f0: 3341 8cff                              |0082: if-ne v1, v4, 000e // -0074
+0018f4: 5451 0100                              |0084: iget-object v1, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0018f8: 6e10 4e00 0100                         |0086: invoke-virtual {v1}, Lcom/google/android/checkers/CheckersView;.a:()V // method@004e
+0018fe: 2889                                   |0089: goto 0012 // -0077
+001900: 5452 0100                              |008a: iget-object v2, v5, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001904: 6e20 7000 1200                         |008c: invoke-virtual {v2, v1}, Lcom/google/android/checkers/CheckersView;.setLevel:(I)V // method@0070
+00190a: 7220 3000 0600                         |008f: invoke-interface {v6, v0}, Landroid/view/MenuItem;.setChecked:(Z)Landroid/view/MenuItem; // method@0030
+001910: 2880                                   |0092: goto 0012 // -0080
+001912: 0000                                   |0093: nop // spacer
+001914: 0001 0300 0000 0000 0800 0000 3600 ... |0094: packed-switch-data (10 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #5              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onPause'
+      type          : '()V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 3
+      ins           : 1
+      outs          : 2
+      insns size    : 21 16-bit code units
+001928:                                        |[001928] com.google.android.checkers.Checkers.onPause:()V
+001938: 6f10 0600 0200                         |0000: invoke-super {v2}, Landroid/app/Activity;.onPause:()V // method@0006
+00193e: 1200                                   |0003: const/4 v0, #int 0 // #0
+001940: 6e20 4000 0200                         |0004: invoke-virtual {v2, v0}, Lcom/google/android/checkers/Checkers;.getPreferences:(I)Landroid/content/SharedPreferences; // method@0040
+001946: 0c00                                   |0007: move-result-object v0
+001948: 7210 1700 0000                         |0008: invoke-interface {v0}, Landroid/content/SharedPreferences;.edit:()Landroid/content/SharedPreferences$Editor; // method@0017
+00194e: 0c00                                   |000b: move-result-object v0
+001950: 5421 0100                              |000c: iget-object v1, v2, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+001954: 6e20 5100 0100                         |000e: invoke-virtual {v1, v0}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences$Editor;)V // method@0051
+00195a: 7210 1400 0000                         |0011: invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;.commit:()Z // method@0014
+001960: 0e00                                   |0014: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #6              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onStop'
+      type          : '()V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 2
+      ins           : 1
+      outs          : 1
+      insns size    : 8 16-bit code units
+001964:                                        |[001964] com.google.android.checkers.Checkers.onStop:()V
+001974: 6f10 0700 0100                         |0000: invoke-super {v1}, Landroid/app/Activity;.onStop:()V // method@0007
+00197a: 1200                                   |0003: const/4 v0, #int 0 // #0
+00197c: 7110 ac00 0000                         |0004: invoke-static {v0}, Ljava/lang/System;.exit:(I)V // method@00ac
+001982: 0e00                                   |0007: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #7              : (in Lcom/google/android/checkers/Checkers;)
+      name          : 'onTrackballEvent'
+      type          : '(Landroid/view/MotionEvent;)Z'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 6
+      ins           : 2
+      outs          : 3
+      insns size    : 44 16-bit code units
+001984:                                        |[001984] com.google.android.checkers.Checkers.onTrackballEvent:(Landroid/view/MotionEvent;)Z
+001994: 1210                                   |0000: const/4 v0, #int 1 // #1
+001996: 6e10 3100 0500                         |0001: invoke-virtual {v5}, Landroid/view/MotionEvent;.getAction:()I // method@0031
+00199c: 0a01                                   |0004: move-result v1
+00199e: 2b01 1d00 0000                         |0005: packed-switch v1, 00000022 // +0000001d
+0019a4: 6f20 0800 5400                         |0008: invoke-super {v4, v5}, Landroid/app/Activity;.onTrackballEvent:(Landroid/view/MotionEvent;)Z // method@0008
+0019aa: 0a00                                   |000b: move-result v0
+0019ac: 0f00                                   |000c: return v0
+0019ae: 5441 0100                              |000d: iget-object v1, v4, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0019b2: 6e10 5d00 0100                         |000f: invoke-virtual {v1}, Lcom/google/android/checkers/CheckersView;.b:()V // method@005d
+0019b8: 28fa                                   |0012: goto 000c // -0006
+0019ba: 5441 0100                              |0013: iget-object v1, v4, Lcom/google/android/checkers/Checkers;.a:Lcom/google/android/checkers/CheckersView; // field@0001
+0019be: 6e10 3200 0500                         |0015: invoke-virtual {v5}, Landroid/view/MotionEvent;.getX:()F // method@0032
+0019c4: 0a02                                   |0018: move-result v2
+0019c6: 6e10 3300 0500                         |0019: invoke-virtual {v5}, Landroid/view/MotionEvent;.getY:()F // method@0033
+0019cc: 0a03                                   |001c: move-result v3
+0019ce: 6e30 4f00 2103                         |001d: invoke-virtual {v1, v2, v3}, Lcom/google/android/checkers/CheckersView;.a:(FF)V // method@004f
+0019d4: 28ec                                   |0020: goto 000c // -0014
+0019d6: 0000                                   |0021: nop // spacer
+0019d8: 0001 0300 0000 0000 0800 0000 0300 ... |0022: packed-switch-data (10 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #1 header:
+class_idx           : 31
+access_flags        : 1 (0x0001)
+superclass_idx      : 27
+interfaces_off      : 0 (0x000000)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 34602 (0x00872a)
+static_fields_size  : 0
+instance_fields_size: 43
+direct_methods_size : 15
+virtual_methods_size: 16
+
+Class #1            -
+  Class descriptor  : 'Lcom/google/android/checkers/CheckersView;'
+  Access flags      : 0x0001 (PUBLIC)
+  Superclass        : 'Landroid/view/View;'
+  Interfaces        -
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'A'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #1              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'B'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #2              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'C'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #3              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'D'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #4              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'E'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #5              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'F'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #6              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'G'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #7              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'H'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #8              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'I'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #9              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'J'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #10              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'K'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #11              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'L'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #12              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'M'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #13              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'N'
+      type          : 'Ljava/lang/String;'
+      access        : 0x0002 (PRIVATE)
+    #14              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'O'
+      type          : 'F'
+      access        : 0x0002 (PRIVATE)
+    #15              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'P'
+      type          : 'F'
+      access        : 0x0002 (PRIVATE)
+    #16              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'Q'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #17              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : 'Landroid/content/Context;'
+      access        : 0x0002 (PRIVATE)
+    #18              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'b'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #19              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'c'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #20              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'd'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #21              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'e'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #22              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'f'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #23              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'g'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #24              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'h'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #25              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'i'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #26              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'j'
+      type          : 'Landroid/graphics/Paint;'
+      access        : 0x0002 (PRIVATE)
+    #27              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'k'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #28              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'l'
+      type          : 'F'
+      access        : 0x0002 (PRIVATE)
+    #29              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'm'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #30              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'n'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #31              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'o'
+      type          : 'Landroid/graphics/drawable/Drawable;'
+      access        : 0x0002 (PRIVATE)
+    #32              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'p'
+      type          : 'Lcom/google/android/checkers/a;'
+      access        : 0x0002 (PRIVATE)
+    #33              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'q'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #34              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'r'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #35              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 's'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #36              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 't'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #37              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'u'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #38              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'v'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #39              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'w'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #40              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'x'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #41              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'y'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #42              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'z'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : '<init>'
+      type          : '(Landroid/content/Context;Landroid/content/SharedPreferences;)V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 12
+      ins           : 3
+      outs          : 5
+      insns size    : 662 16-bit code units
+0019ec:                                        |[0019ec] com.google.android.checkers.CheckersView.<init>:(Landroid/content/Context;Landroid/content/SharedPreferences;)V
+0019fc: 1308 0800                              |0000: const/16 v8, #int 8 // #8
+001a00: 1217                                   |0002: const/4 v7, #int 1 // #1
+001a02: 1306 ff00                              |0003: const/16 v6, #int 255 // #ff
+001a06: 1205                                   |0005: const/4 v5, #int 0 // #0
+001a08: 1204                                   |0006: const/4 v4, #int 0 // #0
+001a0a: 7020 3700 a900                         |0007: invoke-direct {v9, v10}, Landroid/view/View;.<init>:(Landroid/content/Context;)V // method@0037
+001a10: 5b9a 1300                              |000a: iput-object v10, v9, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+001a14: 2200 1100                              |000c: new-instance v0, Landroid/graphics/Paint; // type@0011
+001a18: 7010 2100 0000                         |000e: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001a1e: 5b90 1400                              |0011: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+001a22: 5490 1400                              |0013: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+001a26: 6e20 2300 7000                         |0015: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001a2c: 5490 1400                              |0018: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+001a30: 6e54 2200 6044                         |001a: invoke-virtual {v0, v6, v4, v4, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001a36: 2200 1100                              |001d: new-instance v0, Landroid/graphics/Paint; // type@0011
+001a3a: 7010 2100 0000                         |001f: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001a40: 5b90 1500                              |0022: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+001a44: 5490 1500                              |0024: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+001a48: 6e20 2300 7000                         |0026: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001a4e: 5490 1500                              |0029: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+001a52: 6e56 2200 6066                         |002b: invoke-virtual {v0, v6, v6, v6, v6}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001a58: 2200 1100                              |002e: new-instance v0, Landroid/graphics/Paint; // type@0011
+001a5c: 7010 2100 0000                         |0030: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001a62: 5b90 1600                              |0033: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.d:Landroid/graphics/Paint; // field@0016
+001a66: 5490 1600                              |0035: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.d:Landroid/graphics/Paint; // field@0016
+001a6a: 6e20 2300 7000                         |0037: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001a70: 5490 1600                              |003a: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.d:Landroid/graphics/Paint; // field@0016
+001a74: 1301 fb00                              |003c: const/16 v1, #int 251 // #fb
+001a78: 1302 d700                              |003e: const/16 v2, #int 215 // #d7
+001a7c: 1303 ae00                              |0040: const/16 v3, #int 174 // #ae
+001a80: 6e53 2200 6021                         |0042: invoke-virtual {v0, v6, v1, v2, v3}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001a86: 2200 1100                              |0045: new-instance v0, Landroid/graphics/Paint; // type@0011
+001a8a: 7010 2100 0000                         |0047: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001a90: 5b90 1700                              |004a: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+001a94: 5490 1700                              |004c: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+001a98: 6e20 2300 7000                         |004e: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001a9e: 5490 1700                              |0051: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+001aa2: 6e54 2200 6044                         |0053: invoke-virtual {v0, v6, v4, v4, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001aa8: 2200 1100                              |0056: new-instance v0, Landroid/graphics/Paint; // type@0011
+001aac: 7010 2100 0000                         |0058: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001ab2: 5b90 1800                              |005b: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.f:Landroid/graphics/Paint; // field@0018
+001ab6: 5490 1800                              |005d: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.f:Landroid/graphics/Paint; // field@0018
+001aba: 6e20 2300 7000                         |005f: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001ac0: 5490 1800                              |0062: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.f:Landroid/graphics/Paint; // field@0018
+001ac4: 6e54 2200 6046                         |0064: invoke-virtual {v0, v6, v6, v4, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001aca: 2200 1100                              |0067: new-instance v0, Landroid/graphics/Paint; // type@0011
+001ace: 7010 2100 0000                         |0069: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001ad4: 5b90 1900                              |006c: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.g:Landroid/graphics/Paint; // field@0019
+001ad8: 5490 1900                              |006e: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.g:Landroid/graphics/Paint; // field@0019
+001adc: 6e20 2300 7000                         |0070: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001ae2: 5490 1900                              |0073: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.g:Landroid/graphics/Paint; // field@0019
+001ae6: 1301 a500                              |0075: const/16 v1, #int 165 // #a5
+001aea: 6e54 2200 6016                         |0077: invoke-virtual {v0, v6, v6, v1, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001af0: 2200 1100                              |007a: new-instance v0, Landroid/graphics/Paint; // type@0011
+001af4: 7010 2100 0000                         |007c: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001afa: 5b90 1a00                              |007f: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.h:Landroid/graphics/Paint; // field@001a
+001afe: 5490 1a00                              |0081: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.h:Landroid/graphics/Paint; // field@001a
+001b02: 6e20 2300 7000                         |0083: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001b08: 5490 1a00                              |0086: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.h:Landroid/graphics/Paint; // field@001a
+001b0c: 1301 c800                              |0088: const/16 v1, #int 200 // #c8
+001b10: 6e54 2200 6016                         |008a: invoke-virtual {v0, v6, v6, v1, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001b16: 5490 1a00                              |008d: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.h:Landroid/graphics/Paint; // field@001a
+001b1a: 1501 0040                              |008f: const/high16 v1, #int 1073741824 // #4000
+001b1e: 6e20 2400 1000                         |0091: invoke-virtual {v0, v1}, Landroid/graphics/Paint;.setStrokeWidth:(F)V // method@0024
+001b24: 2200 1100                              |0094: new-instance v0, Landroid/graphics/Paint; // type@0011
+001b28: 7010 2100 0000                         |0096: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001b2e: 5b90 1b00                              |0099: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.i:Landroid/graphics/Paint; // field@001b
+001b32: 5490 1b00                              |009b: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.i:Landroid/graphics/Paint; // field@001b
+001b36: 6e20 2300 7000                         |009d: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001b3c: 5490 1b00                              |00a0: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.i:Landroid/graphics/Paint; // field@001b
+001b40: 6e54 2200 6064                         |00a2: invoke-virtual {v0, v6, v4, v6, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001b46: 2200 1100                              |00a5: new-instance v0, Landroid/graphics/Paint; // type@0011
+001b4a: 7010 2100 0000                         |00a7: invoke-direct {v0}, Landroid/graphics/Paint;.<init>:()V // method@0021
+001b50: 5b90 1c00                              |00aa: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.j:Landroid/graphics/Paint; // field@001c
+001b54: 5490 1c00                              |00ac: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.j:Landroid/graphics/Paint; // field@001c
+001b58: 6e20 2300 7000                         |00ae: invoke-virtual {v0, v7}, Landroid/graphics/Paint;.setAntiAlias:(Z)V // method@0023
+001b5e: 5490 1c00                              |00b1: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.j:Landroid/graphics/Paint; // field@001c
+001b62: 6e54 2200 6044                         |00b3: invoke-virtual {v0, v6, v4, v4, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+001b68: 5490 1c00                              |00b6: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.j:Landroid/graphics/Paint; // field@001c
+001b6c: 6201 0000                              |00b8: sget-object v1, Landroid/graphics/Paint$Style;.STROKE:Landroid/graphics/Paint$Style; // field@0000
+001b70: 6e20 2500 1000                         |00ba: invoke-virtual {v0, v1}, Landroid/graphics/Paint;.setStyle:(Landroid/graphics/Paint$Style;)V // method@0025
+001b76: 5490 1c00                              |00bd: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.j:Landroid/graphics/Paint; // field@001c
+001b7a: 1501 a040                              |00bf: const/high16 v1, #int 1084227584 // #40a0
+001b7e: 6e20 2400 1000                         |00c1: invoke-virtual {v0, v1}, Landroid/graphics/Paint;.setStrokeWidth:(F)V // method@0024
+001b84: 1300 0c00                              |00c4: const/16 v0, #int 12 // #c
+001b88: 5990 1d00                              |00c6: iput v0, v9, Lcom/google/android/checkers/CheckersView;.k:I // field@001d
+001b8c: 1200                                   |00c8: const/4 v0, #int 0 // #0
+001b8e: 5990 1e00                              |00c9: iput v0, v9, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+001b92: 5994 1f00                              |00cb: iput v4, v9, Lcom/google/android/checkers/CheckersView;.m:I // field@001f
+001b96: 5994 2000                              |00cd: iput v4, v9, Lcom/google/android/checkers/CheckersView;.n:I // field@0020
+001b9a: 5490 1300                              |00cf: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+001b9e: 6e10 1100 0000                         |00d1: invoke-virtual {v0}, Landroid/content/Context;.getResources:()Landroid/content/res/Resources; // method@0011
+001ba4: 0c00                                   |00d4: move-result-object v0
+001ba6: 1501 027f                              |00d5: const/high16 v1, #int 2130837504 // #7f02
+001baa: 6e20 1a00 1000                         |00d7: invoke-virtual {v0, v1}, Landroid/content/res/Resources;.getDrawable:(I)Landroid/graphics/drawable/Drawable; // method@001a
+001bb0: 0c00                                   |00da: move-result-object v0
+001bb2: 5b90 2100                              |00db: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.o:Landroid/graphics/drawable/Drawable; // field@0021
+001bb6: 2380 3700                              |00dd: new-array v0, v8, [I // type@0037
+001bba: 5b90 0800                              |00df: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.G:[I // field@0008
+001bbe: 2380 3700                              |00e1: new-array v0, v8, [I // type@0037
+001bc2: 5b90 0900                              |00e3: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.H:[I // field@0009
+001bc6: 2380 3700                              |00e5: new-array v0, v8, [I // type@0037
+001bca: 5b90 0a00                              |00e7: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.I:[I // field@000a
+001bce: 2380 3700                              |00e9: new-array v0, v8, [I // type@0037
+001bd2: 5b90 0b00                              |00eb: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.J:[I // field@000b
+001bd6: 1300 0002                              |00ed: const/16 v0, #int 512 // #200
+001bda: 2300 3600                              |00ef: new-array v0, v0, [B // type@0036
+001bde: 6900 5900                              |00f1: sput-object v0, Lcom/google/android/checkers/g;.a:[B // field@0059
+001be2: 1300 8003                              |00f3: const/16 v0, #int 896 // #380
+001be6: 2300 3600                              |00f5: new-array v0, v0, [B // type@0036
+001bea: 6900 5a00                              |00f7: sput-object v0, Lcom/google/android/checkers/g;.b:[B // field@005a
+001bee: 1300 8003                              |00f9: const/16 v0, #int 896 // #380
+001bf2: 2300 3600                              |00fb: new-array v0, v0, [B // type@0036
+001bf6: 6900 5b00                              |00fd: sput-object v0, Lcom/google/android/checkers/g;.c:[B // field@005b
+001bfa: 1300 1003                              |00ff: const/16 v0, #int 784 // #310
+001bfe: 2300 3600                              |0101: new-array v0, v0, [B // type@0036
+001c02: 6900 5c00                              |0103: sput-object v0, Lcom/google/android/checkers/g;.d:[B // field@005c
+001c06: 1300 001f                              |0105: const/16 v0, #int 7936 // #1f00
+001c0a: 2300 3600                              |0107: new-array v0, v0, [B // type@0036
+001c0e: 6900 5d00                              |0109: sput-object v0, Lcom/google/android/checkers/g;.e:[B // field@005d
+001c12: 1300 001f                              |010b: const/16 v0, #int 7936 // #1f00
+001c16: 2300 3600                              |010d: new-array v0, v0, [B // type@0036
+001c1a: 6900 5e00                              |010f: sput-object v0, Lcom/google/android/checkers/g;.f:[B // field@005e
+001c1e: 1300 4036                              |0111: const/16 v0, #int 13888 // #3640
+001c22: 2300 3600                              |0113: new-array v0, v0, [B // type@0036
+001c26: 6900 5f00                              |0115: sput-object v0, Lcom/google/android/checkers/g;.g:[B // field@005f
+001c2a: 1300 4036                              |0117: const/16 v0, #int 13888 // #3640
+001c2e: 2300 3600                              |0119: new-array v0, v0, [B // type@0036
+001c32: 6900 6000                              |011b: sput-object v0, Lcom/google/android/checkers/g;.h:[B // field@0060
+001c36: 1300 0070                              |011d: const/16 v0, #int 28672 // #7000
+001c3a: 2300 3600                              |011f: new-array v0, v0, [B // type@0036
+001c3e: 6900 6100                              |0121: sput-object v0, Lcom/google/android/checkers/g;.i:[B // field@0061
+001c42: 1300 0070                              |0123: const/16 v0, #int 28672 // #7000
+001c46: 2300 3600                              |0125: new-array v0, v0, [B // type@0036
+001c4a: 6900 6200                              |0127: sput-object v0, Lcom/google/android/checkers/g;.j:[B // field@0062
+001c4e: 1300 0062                              |0129: const/16 v0, #int 25088 // #6200
+001c52: 2300 3600                              |012b: new-array v0, v0, [B // type@0036
+001c56: 6900 6300                              |012d: sput-object v0, Lcom/google/android/checkers/g;.k:[B // field@0063
+001c5a: 1300 0062                              |012f: const/16 v0, #int 25088 // #6200
+001c5e: 2300 3600                              |0131: new-array v0, v0, [B // type@0036
+001c62: 6900 6400                              |0133: sput-object v0, Lcom/google/android/checkers/g;.l:[B // field@0064
+001c66: 1300 402f                              |0135: const/16 v0, #int 12096 // #2f40
+001c6a: 2300 3600                              |0137: new-array v0, v0, [B // type@0036
+001c6e: 6900 6500                              |0139: sput-object v0, Lcom/google/android/checkers/g;.m:[B // field@0065
+001c72: 1300 402f                              |013b: const/16 v0, #int 12096 // #2f40
+001c76: 2300 3600                              |013d: new-array v0, v0, [B // type@0036
+001c7a: 6900 6600                              |013f: sput-object v0, Lcom/google/android/checkers/g;.n:[B // field@0066
+001c7e: 1300 5829                              |0141: const/16 v0, #int 10584 // #2958
+001c82: 2300 3600                              |0143: new-array v0, v0, [B // type@0036
+001c86: 6900 6700                              |0145: sput-object v0, Lcom/google/android/checkers/g;.o:[B // field@0067
+001c8a: 1300 5829                              |0147: const/16 v0, #int 10584 // #2958
+001c8e: 2300 3600                              |0149: new-array v0, v0, [B // type@0036
+001c92: 6900 6800                              |014b: sput-object v0, Lcom/google/android/checkers/g;.p:[B // field@0068
+001c96: 1400 00c1 0300                         |014d: const v0, #float 0.000000 // #0003c100
+001c9c: 2300 3600                              |0150: new-array v0, v0, [B // type@0036
+001ca0: 6900 6900                              |0152: sput-object v0, Lcom/google/android/checkers/g;.q:[B // field@0069
+001ca4: 6e10 1100 0a00                         |0154: invoke-virtual {v10}, Landroid/content/Context;.getResources:()Landroid/content/res/Resources; // method@0011
+001caa: 0c00                                   |0157: move-result-object v0
+001cac: 1501 037f                              |0158: const/high16 v1, #int 2130903040 // #7f03
+001cb0: 6e20 1b00 1000                         |015a: invoke-virtual {v0, v1}, Landroid/content/res/Resources;.openRawResource:(I)Ljava/io/InputStream; // method@001b
+001cb6: 0c00                                   |015d: move-result-object v0
+001cb8: 2201 2700                              |015e: new-instance v1, Ljava/io/BufferedInputStream; // type@0027
+001cbc: 1302 0020                              |0160: const/16 v2, #int 8192 // #2000
+001cc0: 7030 9a00 0102                         |0162: invoke-direct {v1, v0, v2}, Ljava/io/BufferedInputStream;.<init>:(Ljava/io/InputStream;I)V // method@009a
+001cc6: 6901 6b00                              |0165: sput-object v1, Lcom/google/android/checkers/g;.s:Ljava/io/BufferedInputStream; // field@006b
+001cca: 6200 5900                              |0167: sget-object v0, Lcom/google/android/checkers/g;.a:[B // field@0059
+001cce: 7110 9900 0000                         |0169: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001cd4: 6200 5a00                              |016c: sget-object v0, Lcom/google/android/checkers/g;.b:[B // field@005a
+001cd8: 7110 9900 0000                         |016e: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001cde: 6200 5b00                              |0171: sget-object v0, Lcom/google/android/checkers/g;.c:[B // field@005b
+001ce2: 7110 9900 0000                         |0173: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001ce8: 6200 5c00                              |0176: sget-object v0, Lcom/google/android/checkers/g;.d:[B // field@005c
+001cec: 7110 9900 0000                         |0178: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001cf2: 6200 5d00                              |017b: sget-object v0, Lcom/google/android/checkers/g;.e:[B // field@005d
+001cf6: 7110 9900 0000                         |017d: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001cfc: 6200 5e00                              |0180: sget-object v0, Lcom/google/android/checkers/g;.f:[B // field@005e
+001d00: 7110 9900 0000                         |0182: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d06: 6200 5f00                              |0185: sget-object v0, Lcom/google/android/checkers/g;.g:[B // field@005f
+001d0a: 7110 9900 0000                         |0187: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d10: 6200 6000                              |018a: sget-object v0, Lcom/google/android/checkers/g;.h:[B // field@0060
+001d14: 7110 9900 0000                         |018c: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d1a: 6200 6100                              |018f: sget-object v0, Lcom/google/android/checkers/g;.i:[B // field@0061
+001d1e: 7110 9900 0000                         |0191: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d24: 6200 6200                              |0194: sget-object v0, Lcom/google/android/checkers/g;.j:[B // field@0062
+001d28: 7110 9900 0000                         |0196: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d2e: 6200 6300                              |0199: sget-object v0, Lcom/google/android/checkers/g;.k:[B // field@0063
+001d32: 7110 9900 0000                         |019b: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d38: 6200 6400                              |019e: sget-object v0, Lcom/google/android/checkers/g;.l:[B // field@0064
+001d3c: 7110 9900 0000                         |01a0: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d42: 6200 6500                              |01a3: sget-object v0, Lcom/google/android/checkers/g;.m:[B // field@0065
+001d46: 7110 9900 0000                         |01a5: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d4c: 6200 6600                              |01a8: sget-object v0, Lcom/google/android/checkers/g;.n:[B // field@0066
+001d50: 7110 9900 0000                         |01aa: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d56: 6200 6700                              |01ad: sget-object v0, Lcom/google/android/checkers/g;.o:[B // field@0067
+001d5a: 7110 9900 0000                         |01af: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d60: 6200 6800                              |01b2: sget-object v0, Lcom/google/android/checkers/g;.p:[B // field@0068
+001d64: 7110 9900 0000                         |01b4: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d6a: 6200 6900                              |01b7: sget-object v0, Lcom/google/android/checkers/g;.q:[B // field@0069
+001d6e: 7110 9900 0000                         |01b9: invoke-static {v0}, Lcom/google/android/checkers/g;.a:([B)Z // method@0099
+001d74: 6200 6b00                              |01bc: sget-object v0, Lcom/google/android/checkers/g;.s:Ljava/io/BufferedInputStream; // field@006b
+001d78: 6e10 9b00 0000                         |01be: invoke-virtual {v0}, Ljava/io/BufferedInputStream;.close:()V // method@009b
+001d7e: 1200                                   |01c1: const/4 v0, #int 0 // #0
+001d80: 6900 6b00                              |01c2: sput-object v0, Lcom/google/android/checkers/g;.s:Ljava/io/BufferedInputStream; // field@006b
+001d84: 1210                                   |01c4: const/4 v0, #int 1 // #1
+001d86: 6a00 6a00                              |01c5: sput-boolean v0, Lcom/google/android/checkers/g;.r:Z // field@006a
+001d8a: 2200 2000                              |01c7: new-instance v0, Lcom/google/android/checkers/a; // type@0020
+001d8e: 7020 7200 9000                         |01c9: invoke-direct {v0, v9}, Lcom/google/android/checkers/a;.<init>:(Lcom/google/android/checkers/CheckersView;)V // method@0072
+001d94: 5b90 2200                              |01cc: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+001d98: 5b95 0f00                              |01ce: iput-object v5, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+001d9c: 7020 5800 b900                         |01d0: invoke-direct {v9, v11}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences;)Z // method@0058
+001da2: 0a00                                   |01d3: move-result v0
+001da4: 3800 8500                              |01d4: if-eqz v0, 0259 // +0085
+001da8: 7010 6700 0900                         |01d6: invoke-direct {v9}, Lcom/google/android/checkers/CheckersView;.e:()Z // method@0067
+001dae: 0a00                                   |01d9: move-result v0
+001db0: 3900 0600                              |01da: if-nez v0, 01e0 // +0006
+001db4: 1a00 1701                              |01dc: const-string v0, "restored game" // string@0117
+001db8: 5b90 0f00                              |01de: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+001dbc: 7010 6400 0900                         |01e0: invoke-direct {v9}, Lcom/google/android/checkers/CheckersView;.d:()V // method@0064
+001dc2: 1500 20c1                              |01e3: const/high16 v0, #int -1054867456 // #c120
+001dc6: 5990 1000                              |01e5: iput v0, v9, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+001dca: 1500 20c1                              |01e7: const/high16 v0, #int -1054867456 // #c120
+001dce: 5990 1100                              |01e9: iput v0, v9, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+001dd2: 5994 1200                              |01eb: iput v4, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+001dd6: 5590 0600                              |01ed: iget-boolean v0, v9, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+001dda: 3800 2e00                              |01ef: if-eqz v0, 021d // +002e
+001dde: 7010 6700 0900                         |01f1: invoke-direct {v9}, Lcom/google/android/checkers/CheckersView;.e:()Z // method@0067
+001de4: 0a00                                   |01f4: move-result v0
+001de6: 3800 2800                              |01f5: if-eqz v0, 021d // +0028
+001dea: 2200 0500                              |01f7: new-instance v0, Landroid/app/AlertDialog$Builder; // type@0005
+001dee: 5491 1300                              |01f9: iget-object v1, v9, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+001df2: 7020 0900 1000                         |01fb: invoke-direct {v0, v1}, Landroid/app/AlertDialog$Builder;.<init>:(Landroid/content/Context;)V // method@0009
+001df8: 1a01 1200                              |01fe: const-string v1, "Checkers for Android was written by Aart J.C. Bik.
+
+Use the touch screen or trackball to make a move. Press the MENU button for more options, such as making captures optional instead of mandatory.
+
+The application complies with the official American checkers rules, where black moves first, captures are mandatory, men only move and jump forward, and kings move and jump forward and backward (but not over a distance). Please note that many variants of checkers exist, and this game may not use the rules you are most familiar with.
+" // string@0012
+001dfc: 6e20 0c00 1000                         |0200: invoke-virtual {v0, v1}, Landroid/app/AlertDialog$Builder;.setMessage:(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder; // method@000c
+001e02: 0c00                                   |0203: move-result-object v0
+001e04: 1a01 2b00                              |0204: const-string v1, "KEEP SHOWING" // string@002b
+001e08: 2202 2300                              |0206: new-instance v2, Lcom/google/android/checkers/d; // type@0023
+001e0c: 7020 9300 9200                         |0208: invoke-direct {v2, v9}, Lcom/google/android/checkers/d;.<init>:(Lcom/google/android/checkers/CheckersView;)V // method@0093
+001e12: 6e30 0e00 1002                         |020b: invoke-virtual {v0, v1, v2}, Landroid/app/AlertDialog$Builder;.setPositiveButton:(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder; // method@000e
+001e18: 0c00                                   |020e: move-result-object v0
+001e1a: 1a01 7c00                              |020f: const-string v1, "STOP SHOWING" // string@007c
+001e1e: 2202 2400                              |0211: new-instance v2, Lcom/google/android/checkers/e; // type@0024
+001e22: 7020 9500 9200                         |0213: invoke-direct {v2, v9}, Lcom/google/android/checkers/e;.<init>:(Lcom/google/android/checkers/CheckersView;)V // method@0095
+001e28: 6e30 0d00 1002                         |0216: invoke-virtual {v0, v1, v2}, Landroid/app/AlertDialog$Builder;.setNegativeButton:(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder; // method@000d
+001e2e: 0c00                                   |0219: move-result-object v0
+001e30: 6e10 1000 0000                         |021a: invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;.show:()Landroid/app/AlertDialog; // method@0010
+001e36: 0e00                                   |021d: return-void
+001e38: 0d00                                   |021e: move-exception v0
+001e3a: 1a01 0800                              |021f: const-string v1, "BIK" // string@0008
+001e3e: 2202 3000                              |0221: new-instance v2, Ljava/lang/StringBuilder; // type@0030
+001e42: 1a03 b700                              |0223: const-string v3, "cannot read tb: " // string@00b7
+001e46: 7020 a600 3200                         |0225: invoke-direct {v2, v3}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+001e4c: 6e20 a800 0200                         |0228: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@00a8
+001e52: 0c00                                   |022b: move-result-object v0
+001e54: 6e10 aa00 0000                         |022c: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+001e5a: 0c00                                   |022f: move-result-object v0
+001e5c: 7120 2a00 0100                         |0230: invoke-static {v1, v0}, Landroid/util/Log;.d:(Ljava/lang/String;Ljava/lang/String;)I // method@002a
+001e62: 6905 5900                              |0233: sput-object v5, Lcom/google/android/checkers/g;.a:[B // field@0059
+001e66: 6905 5a00                              |0235: sput-object v5, Lcom/google/android/checkers/g;.b:[B // field@005a
+001e6a: 6905 5b00                              |0237: sput-object v5, Lcom/google/android/checkers/g;.c:[B // field@005b
+001e6e: 6905 5c00                              |0239: sput-object v5, Lcom/google/android/checkers/g;.d:[B // field@005c
+001e72: 6905 5d00                              |023b: sput-object v5, Lcom/google/android/checkers/g;.e:[B // field@005d
+001e76: 6905 5e00                              |023d: sput-object v5, Lcom/google/android/checkers/g;.f:[B // field@005e
+001e7a: 6905 5f00                              |023f: sput-object v5, Lcom/google/android/checkers/g;.g:[B // field@005f
+001e7e: 6905 6000                              |0241: sput-object v5, Lcom/google/android/checkers/g;.h:[B // field@0060
+001e82: 6905 6100                              |0243: sput-object v5, Lcom/google/android/checkers/g;.i:[B // field@0061
+001e86: 6905 6200                              |0245: sput-object v5, Lcom/google/android/checkers/g;.j:[B // field@0062
+001e8a: 6905 6300                              |0247: sput-object v5, Lcom/google/android/checkers/g;.k:[B // field@0063
+001e8e: 6905 6400                              |0249: sput-object v5, Lcom/google/android/checkers/g;.l:[B // field@0064
+001e92: 6905 6500                              |024b: sput-object v5, Lcom/google/android/checkers/g;.m:[B // field@0065
+001e96: 6905 6600                              |024d: sput-object v5, Lcom/google/android/checkers/g;.n:[B // field@0066
+001e9a: 6905 6700                              |024f: sput-object v5, Lcom/google/android/checkers/g;.o:[B // field@0067
+001e9e: 6905 6800                              |0251: sput-object v5, Lcom/google/android/checkers/g;.p:[B // field@0068
+001ea2: 6905 6900                              |0253: sput-object v5, Lcom/google/android/checkers/g;.q:[B // field@0069
+001ea6: 6a04 6a00                              |0255: sput-boolean v4, Lcom/google/android/checkers/g;.r:Z // field@006a
+001eaa: 2900 70ff                              |0257: goto/16 01c7 // -0090
+001eae: 5997 2300                              |0259: iput v7, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+001eb2: 5490 2200                              |025b: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+001eb6: 5200 3d00                              |025d: iget v0, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+001eba: 5990 2400                              |025f: iput v0, v9, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+001ebe: 5490 2200                              |0261: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+001ec2: 5200 3f00                              |0263: iget v0, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+001ec6: 5990 2500                              |0265: iput v0, v9, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+001eca: 5490 2200                              |0267: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+001ece: 5200 3e00                              |0269: iget v0, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+001ed2: 5990 2600                              |026b: iput v0, v9, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+001ed6: 5490 2200                              |026d: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+001eda: 5200 4000                              |026f: iget v0, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+001ede: 5990 2700                              |0271: iput v0, v9, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+001ee2: 5994 2800                              |0273: iput v4, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+001ee6: 5994 2900                              |0275: iput v4, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+001eea: 5994 2a00                              |0277: iput v4, v9, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+001eee: 5c94 2b00                              |0279: iput-boolean v4, v9, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+001ef2: 1230                                   |027b: const/4 v0, #int 3 // #3
+001ef4: 5990 2c00                              |027c: iput v0, v9, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+001ef8: 5c97 0200                              |027e: iput-boolean v7, v9, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+001efc: 5c94 0300                              |0280: iput-boolean v4, v9, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+001f00: 5c94 0400                              |0282: iput-boolean v4, v9, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+001f04: 5c94 0500                              |0284: iput-boolean v4, v9, Lcom/google/android/checkers/CheckersView;.D:Z // field@0005
+001f08: 5c97 0600                              |0286: iput-boolean v7, v9, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+001f0c: 5994 0700                              |0288: iput v4, v9, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+001f10: 5994 0c00                              |028a: iput v4, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+001f14: 5994 0d00                              |028c: iput v4, v9, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+001f18: 5490 2200                              |028e: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+001f1c: 5200 3c00                              |0290: iget v0, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+001f20: 5990 0e00                              |0292: iput v0, v9, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+001f24: 2900 4cff                              |0294: goto/16 01e0 // -00b4
+      catches       : 1
+        0x00ef - 0x01c7
+          Ljava/lang/Exception; -> 0x021e
+      positions     : 
+      locals        : 
+
+    #1              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 6
+      ins           : 3
+      outs          : 3
+      insns size    : 31 16-bit code units
+001f38:                                        |[001f38] com.google.android.checkers.CheckersView.a:(Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V
+001f48: 1200                                   |0000: const/4 v0, #int 0 // #0
+001f4a: 1301 0800                              |0001: const/16 v1, #int 8 // #8
+001f4e: 3410 0300                              |0003: if-lt v0, v1, 0006 // +0003
+001f52: 0e00                                   |0005: return-void
+001f54: 2201 3000                              |0006: new-instance v1, Ljava/lang/StringBuilder; // type@0030
+001f58: 7110 a500 0400                         |0008: invoke-static {v4}, Ljava/lang/String;.valueOf:(Ljava/lang/Object;)Ljava/lang/String; // method@00a5
+001f5e: 0c02                                   |000b: move-result-object v2
+001f60: 7020 a600 2100                         |000c: invoke-direct {v1, v2}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+001f66: 6e20 a700 0100                         |000f: invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+001f6c: 0c01                                   |0012: move-result-object v1
+001f6e: 6e10 aa00 0100                         |0013: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+001f74: 0c01                                   |0016: move-result-object v1
+001f76: 4402 0500                              |0017: aget v2, v5, v0
+001f7a: 7230 1600 1302                         |0019: invoke-interface {v3, v1, v2}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+001f80: d800 0001                              |001c: add-int/lit8 v0, v0, #int 1 // #01
+001f84: 28e3                                   |001e: goto 0001 // -001d
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #2              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Landroid/content/SharedPreferences;Ljava/lang/String;[I)V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 7
+      ins           : 3
+      outs          : 3
+      insns size    : 33 16-bit code units
+001f88:                                        |[001f88] com.google.android.checkers.CheckersView.a:(Landroid/content/SharedPreferences;Ljava/lang/String;[I)V
+001f98: 1201                                   |0000: const/4 v1, #int 0 // #0
+001f9a: 0110                                   |0001: move v0, v1
+001f9c: 1302 0800                              |0002: const/16 v2, #int 8 // #8
+001fa0: 3420 0300                              |0004: if-lt v0, v2, 0007 // +0003
+001fa4: 0e00                                   |0006: return-void
+001fa6: 2202 3000                              |0007: new-instance v2, Ljava/lang/StringBuilder; // type@0030
+001faa: 7110 a500 0500                         |0009: invoke-static {v5}, Ljava/lang/String;.valueOf:(Ljava/lang/Object;)Ljava/lang/String; // method@00a5
+001fb0: 0c03                                   |000c: move-result-object v3
+001fb2: 7020 a600 3200                         |000d: invoke-direct {v2, v3}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+001fb8: 6e20 a700 0200                         |0010: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+001fbe: 0c02                                   |0013: move-result-object v2
+001fc0: 6e10 aa00 0200                         |0014: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+001fc6: 0c02                                   |0017: move-result-object v2
+001fc8: 7230 1900 2401                         |0018: invoke-interface {v4, v2, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+001fce: 0a02                                   |001b: move-result v2
+001fd0: 4b02 0600                              |001c: aput v2, v6, v0
+001fd4: d800 0001                              |001e: add-int/lit8 v0, v0, #int 1 // #01
+001fd8: 28e2                                   |0020: goto 0002 // -001e
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #3              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Landroid/graphics/Canvas;IIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 13
+      ins           : 6
+      outs          : 6
+      insns size    : 63 16-bit code units
+001fdc:                                        |[001fdc] com.google.android.checkers.CheckersView.a:(Landroid/graphics/Canvas;IIII)V
+001fec: e201 0902                              |0000: ushr-int/lit8 v1, v9, #int 2 // #02
+001ff0: dd00 0903                              |0002: and-int/lit8 v0, v9, #int 3 // #03
+001ff4: da00 0002                              |0004: mul-int/lit8 v0, v0, #int 2 // #02
+001ff8: d800 0001                              |0006: add-int/lit8 v0, v0, #int 1 // #01
+001ffc: dd02 0101                              |0008: and-int/lit8 v2, v1, #int 1 // #01
+002000: 9103 0002                              |000a: sub-int v3, v0, v2
+002004: e200 0a02                              |000c: ushr-int/lit8 v0, v10, #int 2 // #02
+002008: dd02 0a03                              |000e: and-int/lit8 v2, v10, #int 3 // #03
+00200c: da02 0202                              |0010: mul-int/lit8 v2, v2, #int 2 // #02
+002010: d802 0201                              |0012: add-int/lit8 v2, v2, #int 1 // #01
+002014: dd04 0001                              |0014: and-int/lit8 v4, v0, #int 1 // #01
+002018: b142                                   |0016: sub-int/2addr v2, v4
+00201a: 5574 0400                              |0017: iget-boolean v4, v7, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+00201e: 3804 2100                              |0019: if-eqz v4, 003a // +0021
+002022: d901 0107                              |001b: rsub-int/lit8 v1, v1, #int 7 // #07
+002026: d903 0307                              |001d: rsub-int/lit8 v3, v3, #int 7 // #07
+00202a: d900 0007                              |001f: rsub-int/lit8 v0, v0, #int 7 // #07
+00202e: d902 0207                              |0021: rsub-int/lit8 v2, v2, #int 7 // #07
+002032: 0116                                   |0023: move v6, v1
+002034: 0131                                   |0024: move v1, v3
+002036: 0123                                   |0025: move v3, v2
+002038: 0162                                   |0026: move v2, v6
+00203a: b2b1                                   |0027: mul-int/2addr v1, v11
+00203c: b0c1                                   |0028: add-int/2addr v1, v12
+00203e: 8211                                   |0029: int-to-float v1, v1
+002040: b2b2                                   |002a: mul-int/2addr v2, v11
+002042: b0c2                                   |002b: add-int/2addr v2, v12
+002044: 8222                                   |002c: int-to-float v2, v2
+002046: b2b3                                   |002d: mul-int/2addr v3, v11
+002048: b0c3                                   |002e: add-int/2addr v3, v12
+00204a: 8233                                   |002f: int-to-float v3, v3
+00204c: b2b0                                   |0030: mul-int/2addr v0, v11
+00204e: b0c0                                   |0031: add-int/2addr v0, v12
+002050: 8204                                   |0032: int-to-float v4, v0
+002052: 5475 1a00                              |0033: iget-object v5, v7, Lcom/google/android/checkers/CheckersView;.h:Landroid/graphics/Paint; // field@001a
+002056: 0780                                   |0035: move-object v0, v8
+002058: 7406 1d00 0000                         |0036: invoke-virtual/range {v0, v1, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawLine:(FFFFLandroid/graphics/Paint;)V // method@001d
+00205e: 0e00                                   |0039: return-void
+002060: 0116                                   |003a: move v6, v1
+002062: 0131                                   |003b: move v1, v3
+002064: 0123                                   |003c: move v3, v2
+002066: 0162                                   |003d: move v2, v6
+002068: 28e9                                   |003e: goto 0027 // -0017
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #4              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 13
+      ins           : 8
+      outs          : 5
+      insns size    : 81 16-bit code units
+00206c:                                        |[00206c] com.google.android.checkers.CheckersView.a:(Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V
+00207c: 8260                                   |0000: int-to-float v0, v6
+00207e: 8271                                   |0001: int-to-float v1, v7
+002080: d802 08fe                              |0002: add-int/lit8 v2, v8, #int -2 // #fe
+002084: 8222                                   |0004: int-to-float v2, v2
+002086: 6e5a 1c00 0521                         |0005: invoke-virtual {v5, v0, v1, v2, v10}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+00208c: 8260                                   |0008: int-to-float v0, v6
+00208e: 8271                                   |0009: int-to-float v1, v7
+002090: d802 08fc                              |000a: add-int/lit8 v2, v8, #int -4 // #fc
+002094: 8222                                   |000c: int-to-float v2, v2
+002096: 6e5b 1c00 0521                         |000d: invoke-virtual {v5, v0, v1, v2, v11}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+00209c: 8260                                   |0010: int-to-float v0, v6
+00209e: 8271                                   |0011: int-to-float v1, v7
+0020a0: d802 08f9                              |0012: add-int/lit8 v2, v8, #int -7 // #f9
+0020a4: 8222                                   |0014: int-to-float v2, v2
+0020a6: 6e5a 1c00 0521                         |0015: invoke-virtual {v5, v0, v1, v2, v10}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0020ac: 8260                                   |0018: int-to-float v0, v6
+0020ae: 8271                                   |0019: int-to-float v1, v7
+0020b0: d802 08f7                              |001a: add-int/lit8 v2, v8, #int -9 // #f7
+0020b4: 8222                                   |001c: int-to-float v2, v2
+0020b6: 6e5b 1c00 0521                         |001d: invoke-virtual {v5, v0, v1, v2, v11}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0020bc: 380c 3000                              |0020: if-eqz v12, 0050 // +0030
+0020c0: e100 0802                              |0022: shr-int/lit8 v0, v8, #int 2 // #02
+0020c4: 9101 0600                              |0024: sub-int v1, v6, v0
+0020c8: 9100 0700                              |0026: sub-int v0, v7, v0
+0020cc: 8212                                   |0028: int-to-float v2, v1
+0020ce: 8203                                   |0029: int-to-float v3, v0
+0020d0: d804 08fe                              |002a: add-int/lit8 v4, v8, #int -2 // #fe
+0020d4: 8244                                   |002c: int-to-float v4, v4
+0020d6: 6e5a 1c00 2543                         |002d: invoke-virtual {v5, v2, v3, v4, v10}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0020dc: 8212                                   |0030: int-to-float v2, v1
+0020de: 8203                                   |0031: int-to-float v3, v0
+0020e0: d804 08fc                              |0032: add-int/lit8 v4, v8, #int -4 // #fc
+0020e4: 8244                                   |0034: int-to-float v4, v4
+0020e6: 6e5b 1c00 2543                         |0035: invoke-virtual {v5, v2, v3, v4, v11}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0020ec: 8212                                   |0038: int-to-float v2, v1
+0020ee: 8203                                   |0039: int-to-float v3, v0
+0020f0: d804 08f9                              |003a: add-int/lit8 v4, v8, #int -7 // #f9
+0020f4: 8244                                   |003c: int-to-float v4, v4
+0020f6: 6e5a 1c00 2543                         |003d: invoke-virtual {v5, v2, v3, v4, v10}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0020fc: 8212                                   |0040: int-to-float v2, v1
+0020fe: 8203                                   |0041: int-to-float v3, v0
+002100: d804 08f7                              |0042: add-int/lit8 v4, v8, #int -9 // #f7
+002104: 8244                                   |0044: int-to-float v4, v4
+002106: 6e5b 1c00 2543                         |0045: invoke-virtual {v5, v2, v3, v4, v11}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+00210c: 1a02 2a00                              |0048: const-string v2, "K" // string@002a
+002110: b191                                   |004a: sub-int/2addr v1, v9
+002112: 8211                                   |004b: int-to-float v1, v1
+002114: 8200                                   |004c: int-to-float v0, v0
+002116: 6e5a 2000 2501                         |004d: invoke-virtual {v5, v2, v1, v0, v10}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+00211c: 0e00                                   |0050: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #5              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Lcom/google/android/checkers/CheckersView;I)V'
+      access        : 0x1008 (STATIC SYNTHETIC)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 2
+      insns size    : 4 16-bit code units
+002120:                                        |[002120] com.google.android.checkers.CheckersView.a:(Lcom/google/android/checkers/CheckersView;I)V
+002130: 7020 5e00 1000                         |0000: invoke-direct {v0, v1}, Lcom/google/android/checkers/CheckersView;.b:(I)V // method@005e
+002136: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #6              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Landroid/content/SharedPreferences;)Z'
+      access        : 0x20012 (PRIVATE FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 12
+      ins           : 2
+      outs          : 6
+      insns size    : 294 16-bit code units
+002138:                                        |[002138] com.google.android.checkers.CheckersView.a:(Landroid/content/SharedPreferences;)Z
+002148: 1249                                   |0000: const/4 v9, #int 4 // #4
+00214a: 1232                                   |0001: const/4 v2, #int 3 // #3
+00214c: 1217                                   |0002: const/4 v7, #int 1 // #1
+00214e: 1206                                   |0003: const/4 v6, #int 0 // #0
+002150: 1d0a                                   |0004: monitor-enter v10
+002152: 380b 1b01                              |0005: if-eqz v11, 0120 // +011b
+002156: 1a00 d000                              |0007: const-string v0, "format" // string@00d0
+00215a: 1201                                   |0009: const/4 v1, #int 0 // #0
+00215c: 7230 1900 0b01                         |000a: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+002162: 0a00                                   |000d: move-result v0
+002164: 1301 2200                              |000e: const/16 v1, #int 34 // #22
+002168: 3210 0500                              |0010: if-eq v0, v1, 0015 // +0005
+00216c: 0160                                   |0012: move v0, v6
+00216e: 1e0a                                   |0013: monitor-exit v10
+002170: 0f00                                   |0014: return v0
+002172: 1a00 3101                              |0015: const-string v0, "state" // string@0131
+002176: 1211                                   |0017: const/4 v1, #int 1 // #1
+002178: 7230 1900 0b01                         |0018: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+00217e: 0a00                                   |001b: move-result v0
+002180: 59a0 2300                              |001c: iput v0, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002184: 1a00 3f01                              |001e: const-string v0, "wp" // string@013f
+002188: 1201                                   |0020: const/4 v1, #int 0 // #0
+00218a: 7230 1900 0b01                         |0021: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+002190: 0a00                                   |0024: move-result v0
+002192: 59a0 2400                              |0025: iput v0, v10, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+002196: 1a00 b400                              |0027: const-string v0, "bp" // string@00b4
+00219a: 1201                                   |0029: const/4 v1, #int 0 // #0
+00219c: 7230 1900 0b01                         |002a: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0021a2: 0a00                                   |002d: move-result v0
+0021a4: 59a0 2500                              |002e: iput v0, v10, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+0021a8: 1a00 3e01                              |0030: const-string v0, "wk" // string@013e
+0021ac: 1201                                   |0032: const/4 v1, #int 0 // #0
+0021ae: 7230 1900 0b01                         |0033: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0021b4: 0a00                                   |0036: move-result v0
+0021b6: 59a0 2600                              |0037: iput v0, v10, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+0021ba: 1a00 b300                              |0039: const-string v0, "bk" // string@00b3
+0021be: 1201                                   |003b: const/4 v1, #int 0 // #0
+0021c0: 7230 1900 0b01                         |003c: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0021c6: 0a00                                   |003f: move-result v0
+0021c8: 59a0 2700                              |0040: iput v0, v10, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+0021cc: 1a00 e800                              |0042: const-string v0, "l1" // string@00e8
+0021d0: 1201                                   |0044: const/4 v1, #int 0 // #0
+0021d2: 7230 1900 0b01                         |0045: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0021d8: 0a00                                   |0048: move-result v0
+0021da: 59a0 2800                              |0049: iput v0, v10, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+0021de: 1a00 e900                              |004b: const-string v0, "l2" // string@00e9
+0021e2: 1201                                   |004d: const/4 v1, #int 0 // #0
+0021e4: 7230 1900 0b01                         |004e: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0021ea: 0a00                                   |0051: move-result v0
+0021ec: 59a0 2900                              |0052: iput v0, v10, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+0021f0: 1a00 ef00                              |0054: const-string v0, "lm" // string@00ef
+0021f4: 1201                                   |0056: const/4 v1, #int 0 // #0
+0021f6: 7230 1900 0b01                         |0057: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0021fc: 0a00                                   |005a: move-result v0
+0021fe: 59a0 2a00                              |005b: iput v0, v10, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+002202: 1a00 b800                              |005d: const-string v0, "cap" // string@00b8
+002206: 1211                                   |005f: const/4 v1, #int 1 // #1
+002208: 7230 1800 0b01                         |0060: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getBoolean:(Ljava/lang/String;Z)Z // method@0018
+00220e: 0a00                                   |0063: move-result v0
+002210: 5ca0 2b00                              |0064: iput-boolean v0, v10, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+002214: 1a00 ee00                              |0066: const-string v0, "level" // string@00ee
+002218: 1231                                   |0068: const/4 v1, #int 3 // #3
+00221a: 7230 1900 0b01                         |0069: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+002220: 0a00                                   |006c: move-result v0
+002222: 59a0 2c00                              |006d: iput v0, v10, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+002226: 1a00 2d01                              |006f: const-string v0, "show" // string@012d
+00222a: 1211                                   |0071: const/4 v1, #int 1 // #1
+00222c: 7230 1800 0b01                         |0072: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getBoolean:(Ljava/lang/String;Z)Z // method@0018
+002232: 0a00                                   |0075: move-result v0
+002234: 5ca0 0200                              |0076: iput-boolean v0, v10, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+002238: 1a00 d100                              |0078: const-string v0, "free" // string@00d1
+00223c: 1201                                   |007a: const/4 v1, #int 0 // #0
+00223e: 7230 1800 0b01                         |007b: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getBoolean:(Ljava/lang/String;Z)Z // method@0018
+002244: 0a00                                   |007e: move-result v0
+002246: 5ca0 0300                              |007f: iput-boolean v0, v10, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+00224a: 1a00 1801                              |0081: const-string v0, "rot" // string@0118
+00224e: 1201                                   |0083: const/4 v1, #int 0 // #0
+002250: 7230 1800 0b01                         |0084: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getBoolean:(Ljava/lang/String;Z)Z // method@0018
+002256: 0a00                                   |0087: move-result v0
+002258: 5ca0 0400                              |0088: iput-boolean v0, v10, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+00225c: 1a00 d300                              |008a: const-string v0, "full" // string@00d3
+002260: 1201                                   |008c: const/4 v1, #int 0 // #0
+002262: 7230 1800 0b01                         |008d: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getBoolean:(Ljava/lang/String;Z)Z // method@0018
+002268: 0a00                                   |0090: move-result v0
+00226a: 5ca0 0500                              |0091: iput-boolean v0, v10, Lcom/google/android/checkers/CheckersView;.D:Z // field@0005
+00226e: 1a00 2f01                              |0093: const-string v0, "start" // string@012f
+002272: 1211                                   |0095: const/4 v1, #int 1 // #1
+002274: 7230 1800 0b01                         |0096: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getBoolean:(Ljava/lang/String;Z)Z // method@0018
+00227a: 0a00                                   |0099: move-result v0
+00227c: 5ca0 0600                              |009a: iput-boolean v0, v10, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+002280: 1a00 bd00                              |009c: const-string v0, "color" // string@00bd
+002284: 1201                                   |009e: const/4 v1, #int 0 // #0
+002286: 7230 1900 0b01                         |009f: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+00228c: 0a00                                   |00a2: move-result v0
+00228e: 59a0 0700                              |00a3: iput v0, v10, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+002292: 1a00 f300                              |00a5: const-string v0, "lwp" // string@00f3
+002296: 54a1 0800                              |00a7: iget-object v1, v10, Lcom/google/android/checkers/CheckersView;.G:[I // field@0008
+00229a: 7130 5300 0b01                         |00a9: invoke-static {v11, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences;Ljava/lang/String;[I)V // method@0053
+0022a0: 1a00 f200                              |00ac: const-string v0, "lwk" // string@00f2
+0022a4: 54a1 0900                              |00ae: iget-object v1, v10, Lcom/google/android/checkers/CheckersView;.H:[I // field@0009
+0022a8: 7130 5300 0b01                         |00b0: invoke-static {v11, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences;Ljava/lang/String;[I)V // method@0053
+0022ae: 1a00 eb00                              |00b3: const-string v0, "lbp" // string@00eb
+0022b2: 54a1 0a00                              |00b5: iget-object v1, v10, Lcom/google/android/checkers/CheckersView;.I:[I // field@000a
+0022b6: 7130 5300 0b01                         |00b7: invoke-static {v11, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences;Ljava/lang/String;[I)V // method@0053
+0022bc: 1a00 ea00                              |00ba: const-string v0, "lbk" // string@00ea
+0022c0: 54a1 0b00                              |00bc: iget-object v1, v10, Lcom/google/android/checkers/CheckersView;.J:[I // field@000b
+0022c4: 7130 5300 0b01                         |00be: invoke-static {v11, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences;Ljava/lang/String;[I)V // method@0053
+0022ca: 1a00 f100                              |00c1: const-string v0, "lp" // string@00f1
+0022ce: 1201                                   |00c3: const/4 v1, #int 0 // #0
+0022d0: 7230 1900 0b01                         |00c4: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0022d6: 0a00                                   |00c7: move-result v0
+0022d8: 59a0 0c00                              |00c8: iput v0, v10, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+0022dc: 1a00 ec00                              |00ca: const-string v0, "lc" // string@00ec
+0022e0: 1201                                   |00cc: const/4 v1, #int 0 // #0
+0022e2: 7230 1900 0b01                         |00cd: invoke-interface {v11, v0, v1}, Landroid/content/SharedPreferences;.getInt:(Ljava/lang/String;I)I // method@0019
+0022e8: 0a00                                   |00d0: move-result v0
+0022ea: 59a0 0d00                              |00d1: iput v0, v10, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+0022ee: 52a0 2c00                              |00d3: iget v0, v10, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+0022f2: 6e20 7000 0a00                         |00d5: invoke-virtual {v10, v0}, Lcom/google/android/checkers/CheckersView;.setLevel:(I)V // method@0070
+0022f8: 52a0 2300                              |00d8: iget v0, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0022fc: 3220 3d00                              |00da: if-eq v0, v2, 0117 // +003d
+002300: 52a0 2300                              |00dc: iget v0, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002304: 3290 3900                              |00de: if-eq v0, v9, 0117 // +0039
+002308: 52a0 2300                              |00e0: iget v0, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00230c: 1261                                   |00e2: const/4 v1, #int 6 // #6
+00230e: 3210 3400                              |00e3: if-eq v0, v1, 0117 // +0034
+002312: 0165                                   |00e5: move v5, v6
+002314: 54a8 2200                              |00e6: iget-object v8, v10, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002318: 1d08                                   |00e8: monitor-enter v8
+00231a: 54a0 2200                              |00e9: iget-object v0, v10, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00231e: 52a1 2400                              |00eb: iget v1, v10, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+002322: 52a2 2600                              |00ed: iget v2, v10, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+002326: 52a3 2500                              |00ef: iget v3, v10, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+00232a: 52a4 2700                              |00f1: iget v4, v10, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+00232e: 7406 8000 0000                         |00f3: invoke-virtual/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIIZ)V // method@0080
+002334: 54a0 2200                              |00f6: iget-object v0, v10, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002338: 55a1 0300                              |00f8: iget-boolean v1, v10, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+00233c: 6e30 7a00 5001                         |00fa: invoke-virtual {v0, v5, v1}, Lcom/google/android/checkers/a;.a:(ZZ)I // method@007a
+002342: 54a0 2200                              |00fd: iget-object v0, v10, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002346: 5200 3c00                              |00ff: iget v0, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+00234a: 59a0 0e00                              |0101: iput v0, v10, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+00234e: 1e08                                   |0103: monitor-exit v8
+002350: 52a0 2300                              |0104: iget v0, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002354: 3290 0700                              |0106: if-eq v0, v9, 010d // +0007
+002358: 52a0 2300                              |0108: iget v0, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00235c: 1221                                   |010a: const/4 v1, #int 2 // #2
+00235e: 3310 0900                              |010b: if-ne v0, v1, 0114 // +0009
+002362: 54a0 2200                              |010d: iget-object v0, v10, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002366: 55a1 0300                              |010f: iget-boolean v1, v10, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+00236a: 6e30 8700 5001                         |0111: invoke-virtual {v0, v5, v1}, Lcom/google/android/checkers/a;.b:(ZZ)V // method@0087
+002370: 0170                                   |0114: move v0, v7
+002372: 2900 fefe                              |0115: goto/16 0013 // -0102
+002376: 0175                                   |0117: move v5, v7
+002378: 28ce                                   |0118: goto 00e6 // -0032
+00237a: 0d00                                   |0119: move-exception v0
+00237c: 1e08                                   |011a: monitor-exit v8
+00237e: 2700                                   |011b: throw v0
+002380: 0d00                                   |011c: move-exception v0
+002382: 0160                                   |011d: move v0, v6
+002384: 2900 f5fe                              |011e: goto/16 0013 // -010b
+002388: 0160                                   |0120: move v0, v6
+00238a: 2900 f2fe                              |0121: goto/16 0013 // -010e
+00238e: 0d00                                   |0123: move-exception v0
+002390: 1e0a                                   |0124: monitor-exit v10
+002392: 2700                                   |0125: throw v0
+      catches       : 4
+        0x0007 - 0x000d
+          Ljava/lang/ClassCastException; -> 0x011c
+          <any> -> 0x0123
+        0x0015 - 0x00e9
+          Ljava/lang/ClassCastException; -> 0x011c
+          <any> -> 0x0123
+        0x00e9 - 0x0104
+          <any> -> 0x0119
+        0x0104 - 0x011c
+          Ljava/lang/ClassCastException; -> 0x011c
+          <any> -> 0x0123
+      positions     : 
+      locals        : 
+
+    #7              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Lcom/google/android/checkers/CheckersView;)Z'
+      access        : 0x1008 (STATIC SYNTHETIC)
+      code          -
+      registers     : 7
+      ins           : 1
+      outs          : 6
+      insns size    : 11 16-bit code units
+0023c0:                                        |[0023c0] com.google.android.checkers.CheckersView.a:(Lcom/google/android/checkers/CheckersView;)Z
+0023d0: 1201                                   |0000: const/4 v1, #int 0 // #0
+0023d2: 12f2                                   |0001: const/4 v2, #int -1 // #ff
+0023d4: 0760                                   |0002: move-object v0, v6
+0023d6: 0113                                   |0003: move v3, v1
+0023d8: 0114                                   |0004: move v4, v1
+0023da: 0115                                   |0005: move v5, v1
+0023dc: 7606 5b00 0000                         |0006: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(ZIIII)Z // method@005b
+0023e2: 0a00                                   |0009: move-result v0
+0023e4: 0f00                                   |000a: return v0
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #8              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(ZIIII)Z'
+      access        : 0x20012 (PRIVATE FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 15
+      ins           : 6
+      outs          : 6
+      insns size    : 645 16-bit code units
+0023e8:                                        |[0023e8] com.google.android.checkers.CheckersView.a:(ZIIII)Z
+0023f8: 1232                                   |0000: const/4 v2, #int 3 // #3
+0023fa: 12f1                                   |0001: const/4 v1, #int -1 // #ff
+0023fc: 1223                                   |0002: const/4 v3, #int 2 // #2
+0023fe: 1216                                   |0003: const/4 v6, #int 1 // #1
+002400: 1207                                   |0004: const/4 v7, #int 0 // #0
+002402: 1d09                                   |0005: monitor-enter v9
+002404: 380a 1b00                              |0006: if-eqz v10, 0021 // +001b
+002408: 5290 1200                              |0008: iget v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+00240c: 3d00 1700                              |000a: if-lez v0, 0021 // +0017
+002410: 5290 1200                              |000c: iget v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+002414: 3330 2b00                              |000e: if-ne v0, v3, 0039 // +002b
+002418: 12eb                                   |0010: const/4 v11, #int -2 // #fe
+00241a: 5290 2300                              |0011: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00241e: 3330 2800                              |0013: if-ne v0, v3, 003b // +0028
+002422: 0160                                   |0015: move v0, v6
+002424: 5990 2300                              |0016: iput v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002428: 5290 2c00                              |0018: iget v0, v9, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+00242c: 6e20 7000 0900                         |001a: invoke-virtual {v9, v0}, Lcom/google/android/checkers/CheckersView;.setLevel:(I)V // method@0070
+002432: 1200                                   |001d: const/4 v0, #int 0 // #0
+002434: 5990 1200                              |001e: iput v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+002438: 017a                                   |0020: move v10, v7
+00243a: 380a 8800                              |0021: if-eqz v10, 00a9 // +0088
+00243e: 7020 6200 b900                         |0023: invoke-direct {v9, v11}, Lcom/google/android/checkers/CheckersView;.c:(I)V // method@0062
+002444: 5290 2300                              |0026: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002448: 1252                                   |0028: const/4 v2, #int 5 // #5
+00244a: 3220 0d00                              |0029: if-eq v0, v2, 0036 // +000d
+00244e: 5290 2300                              |002b: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002452: 1262                                   |002d: const/4 v2, #int 6 // #6
+002454: 3220 0800                              |002e: if-eq v0, v2, 0036 // +0008
+002458: 390d 0d00                              |0030: if-nez v13, 003d // +000d
+00245c: 1a00 1301                              |0032: const-string v0, "random play" // string@0113
+002460: 5b90 0f00                              |0034: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+002464: 0160                                   |0036: move v0, v6
+002466: 1e09                                   |0037: monitor-exit v9
+002468: 0f00                                   |0038: return v0
+00246a: 011b                                   |0039: move v11, v1
+00246c: 28d7                                   |003a: goto 0011 // -0029
+00246e: 0120                                   |003b: move v0, v2
+002470: 28da                                   |003c: goto 0016 // -0026
+002472: 331d 0a00                              |003d: if-ne v13, v1, 0047 // +000a
+002476: 1a00 0801                              |003f: const-string v0, "only reply" // string@0108
+00247a: 5b90 0f00                              |0041: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+00247e: 28f3                                   |0043: goto 0036 // -000d
+002480: 0d00                                   |0044: move-exception v0
+002482: 1e09                                   |0045: monitor-exit v9
+002484: 2700                                   |0046: throw v0
+002486: 12e0                                   |0047: const/4 v0, #int -2 // #fe
+002488: 330d 0700                              |0048: if-ne v13, v0, 004f // +0007
+00248c: 1a00 0a01                              |004a: const-string v0, "opening" // string@010a
+002490: 5b90 0f00                              |004c: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+002494: 28e8                                   |004e: goto 0036 // -0018
+002496: 1300 0083                              |004f: const/16 v0, #int -32000 // #8300
+00249a: 360c 1800                              |0051: if-gt v12, v0, 0069 // +0018
+00249e: 2200 3000                              |0053: new-instance v0, Ljava/lang/StringBuilder; // type@0030
+0024a2: 1a01 f000                              |0055: const-string v1, "loss in #" // string@00f0
+0024a6: 7020 a600 1000                         |0057: invoke-direct {v0, v1}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+0024ac: d0c1 f47e                              |005a: add-int/lit16 v1, v12, #int 32500 // #7ef4
+0024b0: db01 0102                              |005c: div-int/lit8 v1, v1, #int 2 // #02
+0024b4: 6e20 a700 1000                         |005e: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+0024ba: 0c00                                   |0061: move-result-object v0
+0024bc: 6e10 aa00 0000                         |0062: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+0024c2: 0c00                                   |0065: move-result-object v0
+0024c4: 5b90 0f00                              |0066: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0024c8: 28ce                                   |0068: goto 0036 // -0032
+0024ca: 1300 007d                              |0069: const/16 v0, #int 32000 // #7d00
+0024ce: 340c 1800                              |006b: if-lt v12, v0, 0083 // +0018
+0024d2: 2200 3000                              |006d: new-instance v0, Ljava/lang/StringBuilder; // type@0030
+0024d6: 1a01 3d01                              |006f: const-string v1, "win in #" // string@013d
+0024da: 7020 a600 1000                         |0071: invoke-direct {v0, v1}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+0024e0: d1c1 f47e                              |0074: rsub-int v1, v12, #int 32500 // #7ef4
+0024e4: db01 0102                              |0076: div-int/lit8 v1, v1, #int 2 // #02
+0024e8: 6e20 a700 1000                         |0078: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+0024ee: 0c00                                   |007b: move-result-object v0
+0024f0: 6e10 aa00 0000                         |007c: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+0024f6: 0c00                                   |007f: move-result-object v0
+0024f8: 5b90 0f00                              |0080: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0024fc: 28b4                                   |0082: goto 0036 // -004c
+0024fe: 2200 3000                              |0083: new-instance v0, Ljava/lang/StringBuilder; // type@0030
+002502: 1a01 3901                              |0085: const-string v1, "v=" // string@0139
+002506: 7020 a600 1000                         |0087: invoke-direct {v0, v1}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+00250c: 6e20 a700 c000                         |008a: invoke-virtual {v0, v12}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+002512: 0c00                                   |008d: move-result-object v0
+002514: 1a01 0000                              |008e: const-string v1, " d=" // string@0000
+002518: 6e20 a900 1000                         |0090: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00a9
+00251e: 0c00                                   |0093: move-result-object v0
+002520: 6e20 a700 d000                         |0094: invoke-virtual {v0, v13}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+002526: 0c00                                   |0097: move-result-object v0
+002528: 1a01 0100                              |0098: const-string v1, " n=" // string@0001
+00252c: 6e20 a900 1000                         |009a: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00a9
+002532: 0c00                                   |009d: move-result-object v0
+002534: 6e20 a700 e000                         |009e: invoke-virtual {v0, v14}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+00253a: 0c00                                   |00a1: move-result-object v0
+00253c: 6e10 aa00 0000                         |00a2: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+002542: 0c00                                   |00a5: move-result-object v0
+002544: 5b90 0f00                              |00a6: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+002548: 288e                                   |00a8: goto 0036 // -0072
+00254a: 12d0                                   |00a9: const/4 v0, #int -3 // #fd
+00254c: 330b 3000                              |00aa: if-ne v11, v0, 00da // +0030
+002550: 2200 0500                              |00ac: new-instance v0, Landroid/app/AlertDialog$Builder; // type@0005
+002554: 5491 1300                              |00ae: iget-object v1, v9, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+002558: 7020 0900 1000                         |00b0: invoke-direct {v0, v1}, Landroid/app/AlertDialog$Builder;.<init>:(Landroid/content/Context;)V // method@0009
+00255e: 1a01 7f00                              |00b3: const-string v1, "Start a new game?" // string@007f
+002562: 6e20 0c00 1000                         |00b5: invoke-virtual {v0, v1}, Landroid/app/AlertDialog$Builder;.setMessage:(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder; // method@000c
+002568: 0c00                                   |00b8: move-result-object v0
+00256a: 1201                                   |00b9: const/4 v1, #int 0 // #0
+00256c: 6e20 0a00 1000                         |00ba: invoke-virtual {v0, v1}, Landroid/app/AlertDialog$Builder;.setCancelable:(Z)Landroid/app/AlertDialog$Builder; // method@000a
+002572: 0c00                                   |00bd: move-result-object v0
+002574: 1a01 9e00                              |00be: const-string v1, "Yes" // string@009e
+002578: 2202 2100                              |00c0: new-instance v2, Lcom/google/android/checkers/b; // type@0021
+00257c: 7020 8f00 9200                         |00c2: invoke-direct {v2, v9}, Lcom/google/android/checkers/b;.<init>:(Lcom/google/android/checkers/CheckersView;)V // method@008f
+002582: 6e30 0e00 1002                         |00c5: invoke-virtual {v0, v1, v2}, Landroid/app/AlertDialog$Builder;.setPositiveButton:(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder; // method@000e
+002588: 0c00                                   |00c8: move-result-object v0
+00258a: 1a01 7500                              |00c9: const-string v1, "No" // string@0075
+00258e: 2202 2200                              |00cb: new-instance v2, Lcom/google/android/checkers/c; // type@0022
+002592: 7020 9100 9200                         |00cd: invoke-direct {v2, v9}, Lcom/google/android/checkers/c;.<init>:(Lcom/google/android/checkers/CheckersView;)V // method@0091
+002598: 6e30 0d00 1002                         |00d0: invoke-virtual {v0, v1, v2}, Landroid/app/AlertDialog$Builder;.setNegativeButton:(Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder; // method@000d
+00259e: 0c00                                   |00d3: move-result-object v0
+0025a0: 6e10 1000 0000                         |00d4: invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;.show:()Landroid/app/AlertDialog; // method@0010
+0025a6: 0160                                   |00d7: move v0, v6
+0025a8: 2900 5fff                              |00d8: goto/16 0037 // -00a1
+0025ac: 331b 5b00                              |00da: if-ne v11, v1, 0135 // +005b
+0025b0: 5290 2300                              |00dc: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0025b4: 3230 0700                              |00de: if-eq v0, v3, 00e5 // +0007
+0025b8: 5290 2300                              |00e0: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0025bc: 1241                                   |00e2: const/4 v1, #int 4 // #4
+0025be: 3310 1100                              |00e3: if-ne v0, v1, 00f4 // +0011
+0025c2: 1210                                   |00e5: const/4 v0, #int 1 // #1
+0025c4: 5990 1200                              |00e6: iput v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+0025c8: 5490 2200                              |00e8: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+0025cc: 1211                                   |00ea: const/4 v1, #int 1 // #1
+0025ce: 5901 4100                              |00eb: iput v1, v0, Lcom/google/android/checkers/a;.h:I // field@0041
+0025d2: 1a00 3201                              |00ed: const-string v0, "stopping...." // string@0132
+0025d6: 5b90 0f00                              |00ef: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0025da: 0160                                   |00f1: move v0, v6
+0025dc: 2900 45ff                              |00f2: goto/16 0037 // -00bb
+0025e0: 1200                                   |00f4: const/4 v0, #int 0 // #0
+0025e2: 5990 1200                              |00f5: iput v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+0025e6: 5490 2200                              |00f7: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+0025ea: 6e10 7b00 0000                         |00f9: invoke-virtual {v0}, Lcom/google/android/checkers/a;.a:()V // method@007b
+0025f0: 1210                                   |00fc: const/4 v0, #int 1 // #1
+0025f2: 5990 2300                              |00fd: iput v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0025f6: 5490 2200                              |00ff: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+0025fa: 5200 3d00                              |0101: iget v0, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+0025fe: 5990 2400                              |0103: iput v0, v9, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+002602: 5490 2200                              |0105: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002606: 5200 3f00                              |0107: iget v0, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+00260a: 5990 2500                              |0109: iput v0, v9, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+00260e: 5490 2200                              |010b: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002612: 5200 3e00                              |010d: iget v0, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+002616: 5990 2600                              |010f: iput v0, v9, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+00261a: 5490 2200                              |0111: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00261e: 5200 4000                              |0113: iget v0, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+002622: 5990 2700                              |0115: iput v0, v9, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+002626: 1200                                   |0117: const/4 v0, #int 0 // #0
+002628: 5990 2800                              |0118: iput v0, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+00262c: 1200                                   |011a: const/4 v0, #int 0 // #0
+00262e: 5990 2900                              |011b: iput v0, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+002632: 1200                                   |011d: const/4 v0, #int 0 // #0
+002634: 5990 2a00                              |011e: iput v0, v9, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+002638: 1200                                   |0120: const/4 v0, #int 0 // #0
+00263a: 5c90 2b00                              |0121: iput-boolean v0, v9, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+00263e: 1200                                   |0123: const/4 v0, #int 0 // #0
+002640: 5990 0c00                              |0124: iput v0, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+002644: 1200                                   |0126: const/4 v0, #int 0 // #0
+002646: 5990 0d00                              |0127: iput v0, v9, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+00264a: 5490 2200                              |0129: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00264e: 5200 3c00                              |012b: iget v0, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+002652: 5990 0e00                              |012d: iput v0, v9, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+002656: 1200                                   |012f: const/4 v0, #int 0 // #0
+002658: 5b90 0f00                              |0130: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+00265c: 0160                                   |0132: move v0, v6
+00265e: 2900 04ff                              |0133: goto/16 0037 // -00fc
+002662: 12e0                                   |0135: const/4 v0, #int -2 // #fe
+002664: 330b b100                              |0136: if-ne v11, v0, 01e7 // +00b1
+002668: 1200                                   |0138: const/4 v0, #int 0 // #0
+00266a: 5990 2800                              |0139: iput v0, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+00266e: 1200                                   |013b: const/4 v0, #int 0 // #0
+002670: 5990 2900                              |013c: iput v0, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+002674: 1200                                   |013e: const/4 v0, #int 0 // #0
+002676: 5990 2a00                              |013f: iput v0, v9, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+00267a: 5290 2300                              |0141: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00267e: 3230 0700                              |0143: if-eq v0, v3, 014a // +0007
+002682: 5290 2300                              |0145: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002686: 1241                                   |0147: const/4 v1, #int 4 // #4
+002688: 3310 1100                              |0148: if-ne v0, v1, 0159 // +0011
+00268c: 1220                                   |014a: const/4 v0, #int 2 // #2
+00268e: 5990 1200                              |014b: iput v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+002692: 5490 2200                              |014d: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002696: 1211                                   |014f: const/4 v1, #int 1 // #1
+002698: 5901 4100                              |0150: iput v1, v0, Lcom/google/android/checkers/a;.h:I // field@0041
+00269c: 1a00 3201                              |0152: const-string v0, "stopping...." // string@0132
+0026a0: 5b90 0f00                              |0154: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0026a4: 0160                                   |0156: move v0, v6
+0026a6: 2900 e0fe                              |0157: goto/16 0037 // -0120
+0026aa: 1200                                   |0159: const/4 v0, #int 0 // #0
+0026ac: 5990 1200                              |015a: iput v0, v9, Lcom/google/android/checkers/CheckersView;.Q:I // field@0012
+0026b0: 5290 2300                              |015c: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0026b4: 3260 7600                              |015e: if-eq v0, v6, 01d4 // +0076
+0026b8: 5290 2300                              |0160: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0026bc: 1251                                   |0162: const/4 v1, #int 5 // #5
+0026be: 3210 7100                              |0163: if-eq v0, v1, 01d4 // +0071
+0026c2: 0175                                   |0165: move v5, v7
+0026c4: 5290 0d00                              |0166: iget v0, v9, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+0026c8: 3d00 7200                              |0168: if-lez v0, 01da // +0072
+0026cc: 5290 0d00                              |016a: iget v0, v9, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+0026d0: d800 00ff                              |016c: add-int/lit8 v0, v0, #int -1 // #ff
+0026d4: 5990 0d00                              |016e: iput v0, v9, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+0026d8: 5290 0c00                              |0170: iget v0, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+0026dc: 3d00 6400                              |0172: if-lez v0, 01d6 // +0064
+0026e0: 5290 0c00                              |0174: iget v0, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+0026e4: d800 00ff                              |0176: add-int/lit8 v0, v0, #int -1 // #ff
+0026e8: 5990 0c00                              |0178: iput v0, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+0026ec: 5294 0c00                              |017a: iget v4, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+0026f0: 5490 2200                              |017c: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+0026f4: 5491 0800                              |017e: iget-object v1, v9, Lcom/google/android/checkers/CheckersView;.G:[I // field@0008
+0026f8: 4401 0104                              |0180: aget v1, v1, v4
+0026fc: 5492 0900                              |0182: iget-object v2, v9, Lcom/google/android/checkers/CheckersView;.H:[I // field@0009
+002700: 4402 0204                              |0184: aget v2, v2, v4
+002704: 5493 0a00                              |0186: iget-object v3, v9, Lcom/google/android/checkers/CheckersView;.I:[I // field@000a
+002708: 4403 0304                              |0188: aget v3, v3, v4
+00270c: 5498 0b00                              |018a: iget-object v8, v9, Lcom/google/android/checkers/CheckersView;.J:[I // field@000b
+002710: 4404 0804                              |018c: aget v4, v8, v4
+002714: 7406 8000 0000                         |018e: invoke-virtual/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIIZ)V // method@0080
+00271a: 0160                                   |0191: move v0, v6
+00271c: 3800 4e00                              |0192: if-eqz v0, 01e0 // +004e
+002720: 3805 4800                              |0194: if-eqz v5, 01dc // +0048
+002724: 1230                                   |0196: const/4 v0, #int 3 // #3
+002726: 5990 2300                              |0197: iput v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00272a: 5490 2200                              |0199: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00272e: 5200 3d00                              |019b: iget v0, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+002732: 5990 2400                              |019d: iput v0, v9, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+002736: 5490 2200                              |019f: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00273a: 5200 3f00                              |01a1: iget v0, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+00273e: 5990 2500                              |01a3: iput v0, v9, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+002742: 5490 2200                              |01a5: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002746: 5200 3e00                              |01a7: iget v0, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+00274a: 5990 2600                              |01a9: iput v0, v9, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+00274e: 5490 2200                              |01ab: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002752: 5200 4000                              |01ad: iget v0, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+002756: 5990 2700                              |01af: iput v0, v9, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+00275a: 1200                                   |01b1: const/4 v0, #int 0 // #0
+00275c: 5990 2800                              |01b2: iput v0, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+002760: 1200                                   |01b4: const/4 v0, #int 0 // #0
+002762: 5990 2900                              |01b5: iput v0, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+002766: 1200                                   |01b7: const/4 v0, #int 0 // #0
+002768: 5990 2a00                              |01b8: iput v0, v9, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+00276c: 5490 2200                              |01ba: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002770: 5591 0300                              |01bc: iget-boolean v1, v9, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+002774: 6e30 7a00 5001                         |01be: invoke-virtual {v0, v5, v1}, Lcom/google/android/checkers/a;.a:(ZZ)I // method@007a
+00277a: 0a00                                   |01c1: move-result v0
+00277c: 3360 0300                              |01c2: if-ne v0, v6, 01c5 // +0003
+002780: 0167                                   |01c4: move v7, v6
+002782: 5c97 2b00                              |01c5: iput-boolean v7, v9, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+002786: 5490 2200                              |01c7: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00278a: 5200 3c00                              |01c9: iget v0, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+00278e: 5990 0e00                              |01cb: iput v0, v9, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+002792: 1a00 3701                              |01cd: const-string v0, "undid half-move" // string@0137
+002796: 5b90 0f00                              |01cf: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+00279a: 0160                                   |01d1: move v0, v6
+00279c: 2900 65fe                              |01d2: goto/16 0037 // -019b
+0027a0: 0165                                   |01d4: move v5, v6
+0027a2: 2891                                   |01d5: goto 0166 // -006f
+0027a4: 1270                                   |01d6: const/4 v0, #int 7 // #7
+0027a6: 5990 0c00                              |01d7: iput v0, v9, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+0027aa: 28a1                                   |01d9: goto 017a // -005f
+0027ac: 0170                                   |01da: move v0, v7
+0027ae: 28b7                                   |01db: goto 0192 // -0049
+0027b0: 1210                                   |01dc: const/4 v0, #int 1 // #1
+0027b2: 5990 2300                              |01dd: iput v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0027b6: 28ba                                   |01df: goto 0199 // -0046
+0027b8: 1a00 f900                              |01e0: const-string v0, "no more undo" // string@00f9
+0027bc: 5b90 0f00                              |01e2: iput-object v0, v9, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0027c0: 0160                                   |01e4: move v0, v6
+0027c2: 2900 52fe                              |01e5: goto/16 0037 // -01ae
+0027c6: 12c0                                   |01e7: const/4 v0, #int -4 // #fc
+0027c8: 330b 4c00                              |01e8: if-ne v11, v0, 0234 // +004c
+0027cc: 5290 2300                              |01ea: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0027d0: 3360 2300                              |01ec: if-ne v0, v6, 020f // +0023
+0027d4: 1220                                   |01ee: const/4 v0, #int 2 // #2
+0027d6: 5990 2300                              |01ef: iput v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+0027da: 5490 2200                              |01f1: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+0027de: 1201                                   |01f3: const/4 v1, #int 0 // #0
+0027e0: 5592 0300                              |01f4: iget-boolean v2, v9, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+0027e4: 6e30 8700 1002                         |01f6: invoke-virtual {v0, v1, v2}, Lcom/google/android/checkers/a;.b:(ZZ)V // method@0087
+0027ea: 5491 1300                              |01f9: iget-object v1, v9, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+0027ee: 5590 0400                              |01fb: iget-boolean v0, v9, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+0027f2: 3800 0f00                              |01fd: if-eqz v0, 020c // +000f
+0027f6: 1a00 bf00                              |01ff: const-string v0, "computer now plays black" // string@00bf
+0027fa: 1202                                   |0201: const/4 v2, #int 0 // #0
+0027fc: 7130 3c00 0102                         |0202: invoke-static {v1, v0, v2}, Landroid/widget/Toast;.makeText:(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; // method@003c
+002802: 0c00                                   |0205: move-result-object v0
+002804: 6e10 3d00 0000                         |0206: invoke-virtual {v0}, Landroid/widget/Toast;.show:()V // method@003d
+00280a: 0160                                   |0209: move v0, v6
+00280c: 2900 2dfe                              |020a: goto/16 0037 // -01d3
+002810: 1a00 c000                              |020c: const-string v0, "computer now plays black
+goto options to rotate board" // string@00c0
+002814: 28f3                                   |020e: goto 0201 // -000d
+002816: 5290 2300                              |020f: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00281a: 3320 6f00                              |0211: if-ne v0, v2, 0280 // +006f
+00281e: 1240                                   |0213: const/4 v0, #int 4 // #4
+002820: 5990 2300                              |0214: iput v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002824: 5490 2200                              |0216: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002828: 1211                                   |0218: const/4 v1, #int 1 // #1
+00282a: 5592 0300                              |0219: iget-boolean v2, v9, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+00282e: 6e30 8700 1002                         |021b: invoke-virtual {v0, v1, v2}, Lcom/google/android/checkers/a;.b:(ZZ)V // method@0087
+002834: 5491 1300                              |021e: iget-object v1, v9, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+002838: 5590 0400                              |0220: iget-boolean v0, v9, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+00283c: 3800 0f00                              |0222: if-eqz v0, 0231 // +000f
+002840: 1a00 c200                              |0224: const-string v0, "computer now plays white
+goto options to rotate board" // string@00c2
+002844: 1202                                   |0226: const/4 v2, #int 0 // #0
+002846: 7130 3c00 0102                         |0227: invoke-static {v1, v0, v2}, Landroid/widget/Toast;.makeText:(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; // method@003c
+00284c: 0c00                                   |022a: move-result-object v0
+00284e: 6e10 3d00 0000                         |022b: invoke-virtual {v0}, Landroid/widget/Toast;.show:()V // method@003d
+002854: 0160                                   |022e: move v0, v6
+002856: 2900 08fe                              |022f: goto/16 0037 // -01f8
+00285a: 1a00 c100                              |0231: const-string v0, "computer now plays white" // string@00c1
+00285e: 28f3                                   |0233: goto 0226 // -000d
+002860: 336b 4c00                              |0234: if-ne v11, v6, 0280 // +004c
+002864: 5290 2300                              |0236: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002868: 3260 0600                              |0238: if-eq v0, v6, 023e // +0006
+00286c: 5290 2300                              |023a: iget v0, v9, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002870: 3320 4400                              |023c: if-ne v0, v2, 0280 // +0044
+002874: 1200                                   |023e: const/4 v0, #int 0 // #0
+002876: 5990 2900                              |023f: iput v0, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+00287a: 1200                                   |0241: const/4 v0, #int 0 // #0
+00287c: 5990 2a00                              |0242: iput v0, v9, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+002880: 5490 2200                              |0244: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002884: 5204 3c00                              |0246: iget v4, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+002888: 5490 2200                              |0248: iget-object v0, v9, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00288c: 5405 3b00                              |024a: iget-object v5, v0, Lcom/google/android/checkers/a;.b:[I // field@003b
+002890: 0172                                   |024c: move v2, v7
+002892: 0170                                   |024d: move v0, v7
+002894: 0173                                   |024e: move v3, v7
+002896: 3442 0a00                              |024f: if-lt v2, v4, 0259 // +000a
+00289a: 3363 2500                              |0251: if-ne v3, v6, 0276 // +0025
+00289e: 7020 6200 1900                         |0253: invoke-direct {v9, v1}, Lcom/google/android/checkers/CheckersView;.c:(I)V // method@0062
+0028a4: 0160                                   |0256: move v0, v6
+0028a6: 2900 e0fd                              |0257: goto/16 0037 // -0220
+0028aa: 5297 2800                              |0259: iget v7, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+0028ae: 4408 0502                              |025b: aget v8, v5, v2
+0028b2: b587                                   |025d: and-int/2addr v7, v8
+0028b4: 5298 2800                              |025e: iget v8, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+0028b8: 3387 1300                              |0260: if-ne v7, v8, 0273 // +0013
+0028bc: 4401 0502                              |0262: aget v1, v5, v2
+0028c0: 3201 1f00                              |0264: if-eq v1, v0, 0283 // +001f
+0028c4: d801 0301                              |0266: add-int/lit8 v1, v3, #int 1 // #01
+0028c8: 4400 0502                              |0268: aget v0, v5, v2
+0028cc: 5293 2900                              |026a: iget v3, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+0028d0: 4407 0502                              |026c: aget v7, v5, v2
+0028d4: b673                                   |026e: or-int/2addr v3, v7
+0028d6: 5993 2900                              |026f: iput v3, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+0028da: 0113                                   |0271: move v3, v1
+0028dc: 0121                                   |0272: move v1, v2
+0028de: d802 0201                              |0273: add-int/lit8 v2, v2, #int 1 // #01
+0028e2: 28da                                   |0275: goto 024f // -0026
+0028e4: 5290 2900                              |0276: iget v0, v9, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+0028e8: 3900 0500                              |0278: if-nez v0, 027d // +0005
+0028ec: 1200                                   |027a: const/4 v0, #int 0 // #0
+0028ee: 5990 2800                              |027b: iput v0, v9, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+0028f2: 0160                                   |027d: move v0, v6
+0028f4: 2900 b9fd                              |027e: goto/16 0037 // -0247
+0028f8: 0170                                   |0280: move v0, v7
+0028fa: 2900 b6fd                              |0281: goto/16 0037 // -024a
+0028fe: 0131                                   |0283: move v1, v3
+002900: 28e4                                   |0284: goto 0268 // -001c
+      catches       : 3
+        0x0008 - 0x0036
+          <any> -> 0x0044
+        0x003f - 0x0043
+          <any> -> 0x0044
+        0x004a - 0x027d
+          <any> -> 0x0044
+      positions     : 
+      locals        : 
+
+    #9              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'b'
+      type          : '(FF)I'
+      access        : 0x20012 (PRIVATE FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 13
+      ins           : 3
+      outs          : 1
+      insns size    : 102 16-bit code units
+002920:                                        |[002920] com.google.android.checkers.CheckersView.b:(FF)I
+002930: 1309 0800                              |0000: const/16 v9, #int 8 // #8
+002934: 1201                                   |0002: const/4 v1, #int 0 // #0
+002936: 1210                                   |0003: const/4 v0, #int 1 // #1
+002938: 1d0a                                   |0004: monitor-enter v10
+00293a: 6e10 6a00 0a00                         |0005: invoke-virtual {v10}, Lcom/google/android/checkers/CheckersView;.getWidth:()I // method@006a
+002940: 0a02                                   |0008: move-result v2
+002942: 6e10 6900 0a00                         |0009: invoke-virtual {v10}, Lcom/google/android/checkers/CheckersView;.getHeight:()I // method@0069
+002948: 0a03                                   |000c: move-result v3
+00294a: 3532 1400                              |000d: if-ge v2, v3, 0021 // +0014
+00294e: e207 0203                              |000f: ushr-int/lit8 v7, v2, #int 3 // #03
+002952: 52a2 2300                              |0011: iget v2, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002956: 3202 0700                              |0013: if-eq v2, v0, 001a // +0007
+00295a: 52a2 2300                              |0015: iget v2, v10, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00295e: 1233                                   |0017: const/4 v3, #int 3 // #3
+002960: 3332 0600                              |0018: if-ne v2, v3, 001e // +0006
+002964: 0116                                   |001a: move v6, v1
+002966: 0103                                   |001b: move v3, v0
+002968: 3496 0700                              |001c: if-lt v6, v9, 0023 // +0007
+00296c: 0110                                   |001e: move v0, v1
+00296e: 1e0a                                   |001f: monitor-exit v10
+002970: 0f00                                   |0020: return v0
+002972: 0132                                   |0021: move v2, v3
+002974: 28ed                                   |0022: goto 000f // -0013
+002976: d902 0601                              |0023: rsub-int/lit8 v2, v6, #int 1 // #01
+00297a: dd02 0201                              |0025: and-int/lit8 v2, v2, #int 1 // #01
+00297e: 0124                                   |0027: move v4, v2
+002980: 0135                                   |0028: move v5, v3
+002982: 3494 0700                              |0029: if-lt v4, v9, 0030 // +0007
+002986: d802 0601                              |002b: add-int/lit8 v2, v6, #int 1 // #01
+00298a: 0126                                   |002d: move v6, v2
+00298c: 0153                                   |002e: move v3, v5
+00298e: 28ed                                   |002f: goto 001c // -0013
+002990: 55a2 0400                              |0030: iget-boolean v2, v10, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+002994: 3802 2800                              |0032: if-eqz v2, 005a // +0028
+002998: d902 0407                              |0034: rsub-int/lit8 v2, v4, #int 7 // #07
+00299c: 9203 0702                              |0036: mul-int v3, v7, v2
+0029a0: d902 0607                              |0038: rsub-int/lit8 v2, v6, #int 7 // #07
+0029a4: b272                                   |003a: mul-int/2addr v2, v7
+0029a6: 8238                                   |003b: int-to-float v8, v3
+0029a8: 2e08 080b                              |003c: cmpg-float v8, v8, v11
+0029ac: 3c08 2100                              |003e: if-gtz v8, 005f // +0021
+0029b0: b073                                   |0040: add-int/2addr v3, v7
+0029b2: 8233                                   |0041: int-to-float v3, v3
+0029b4: 2e03 0b03                              |0042: cmpg-float v3, v11, v3
+0029b8: 3b03 1b00                              |0044: if-gez v3, 005f // +001b
+0029bc: 8223                                   |0046: int-to-float v3, v2
+0029be: 2e03 030c                              |0047: cmpg-float v3, v3, v12
+0029c2: 3c03 1600                              |0049: if-gtz v3, 005f // +0016
+0029c6: b072                                   |004b: add-int/2addr v2, v7
+0029c8: 8222                                   |004c: int-to-float v2, v2
+0029ca: 2e02 0c02                              |004d: cmpg-float v2, v12, v2
+0029ce: 3b02 1000                              |004f: if-gez v2, 005f // +0010
+0029d2: 52a1 2800                              |0051: iget v1, v10, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+0029d6: b651                                   |0053: or-int/2addr v1, v5
+0029d8: 59a1 2800                              |0054: iput v1, v10, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+0029dc: 28c9                                   |0056: goto 001f // -0037
+0029de: 0d00                                   |0057: move-exception v0
+0029e0: 1e0a                                   |0058: monitor-exit v10
+0029e2: 2700                                   |0059: throw v0
+0029e4: 9203 0704                              |005a: mul-int v3, v7, v4
+0029e8: 9202 0706                              |005c: mul-int v2, v7, v6
+0029ec: 28dd                                   |005e: goto 003b // -0023
+0029ee: e003 0501                              |005f: shl-int/lit8 v3, v5, #int 1 // #01
+0029f2: d802 0402                              |0061: add-int/lit8 v2, v4, #int 2 // #02
+0029f6: 0124                                   |0063: move v4, v2
+0029f8: 0135                                   |0064: move v5, v3
+0029fa: 28c4                                   |0065: goto 0029 // -003c
+      catches       : 2
+        0x0005 - 0x0017
+          <any> -> 0x0057
+        0x0030 - 0x0056
+          <any> -> 0x0057
+      positions     : 
+      locals        : 
+
+    #10              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'b'
+      type          : '(I)V'
+      access        : 0x20012 (PRIVATE FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 3
+      ins           : 2
+      outs          : 1
+      insns size    : 18 16-bit code units
+002a10:                                        |[002a10] com.google.android.checkers.CheckersView.b:(I)V
+002a20: 1d01                                   |0000: monitor-enter v1
+002a22: 5210 0700                              |0001: iget v0, v1, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+002a26: 3220 0a00                              |0003: if-eq v0, v2, 000d // +000a
+002a2a: 5912 0700                              |0005: iput v2, v1, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+002a2e: 7010 6400 0100                         |0007: invoke-direct {v1}, Lcom/google/android/checkers/CheckersView;.d:()V // method@0064
+002a34: 6e10 6d00 0100                         |000a: invoke-virtual {v1}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+002a3a: 1e01                                   |000d: monitor-exit v1
+002a3c: 0e00                                   |000e: return-void
+002a3e: 0d00                                   |000f: move-exception v0
+002a40: 1e01                                   |0010: monitor-exit v1
+002a42: 2700                                   |0011: throw v0
+      catches       : 1
+        0x0001 - 0x000d
+          <any> -> 0x000f
+      positions     : 
+      locals        : 
+
+    #11              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'b'
+      type          : '(Landroid/graphics/Canvas;IIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 16
+      ins           : 6
+      outs          : 6
+      insns size    : 99 16-bit code units
+002a50:                                        |[002a50] com.google.android.checkers.CheckersView.b:(Landroid/graphics/Canvas;IIII)V
+002a60: df00 0cff                              |0000: xor-int/lit8 v0, v12, #int -1 // #ff
+002a64: b5d0                                   |0002: and-int/2addr v0, v13
+002a66: 3900 5e00                              |0003: if-nez v0, 0061 // +005e
+002a6a: 7110 9f00 0c00                         |0005: invoke-static {v12}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+002a70: 0a02                                   |0008: move-result v2
+002a72: d800 0cff                              |0009: add-int/lit8 v0, v12, #int -1 // #ff
+002a76: b5c0                                   |000b: and-int/2addr v0, v12
+002a78: 7110 9f00 0000                         |000c: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+002a7e: 0a03                                   |000f: move-result v3
+002a80: 07a0                                   |0010: move-object v0, v10
+002a82: 07b1                                   |0011: move-object v1, v11
+002a84: 01e4                                   |0012: move v4, v14
+002a86: 01f5                                   |0013: move v5, v15
+002a88: 7606 5400 0000                         |0014: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIII)V // method@0054
+002a8e: 0e00                                   |0017: return-void
+002a90: 7110 9f00 0800                         |0018: invoke-static {v8}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+002a96: 0a03                                   |001b: move-result v3
+002a98: e200 0302                              |001c: ushr-int/lit8 v0, v3, #int 2 // #02
+002a9c: dd00 0001                              |001e: and-int/lit8 v0, v0, #int 1 // #01
+002aa0: 3800 3600                              |0020: if-eqz v0, 0056 // +0036
+002aa4: d802 03fb                              |0022: add-int/lit8 v2, v3, #int -5 // #fb
+002aa8: d801 03fc                              |0024: add-int/lit8 v1, v3, #int -4 // #fc
+002aac: d800 0303                              |0026: add-int/lit8 v0, v3, #int 3 // #03
+002ab0: d803 0304                              |0028: add-int/lit8 v3, v3, #int 4 // #04
+002ab4: 0106                                   |002a: move v6, v0
+002ab6: 0117                                   |002b: move v7, v1
+002ab8: 1210                                   |002c: const/4 v0, #int 1 // #1
+002aba: b820                                   |002d: shl-int/2addr v0, v2
+002abc: 1211                                   |002e: const/4 v1, #int 1 // #1
+002abe: b831                                   |002f: shl-int/2addr v1, v3
+002ac0: b610                                   |0030: or-int/2addr v0, v1
+002ac2: 1211                                   |0031: const/4 v1, #int 1 // #1
+002ac4: b871                                   |0032: shl-int/2addr v1, v7
+002ac6: 1214                                   |0033: const/4 v4, #int 1 // #1
+002ac8: b864                                   |0034: shl-int/2addr v4, v6
+002aca: 9609 0104                              |0035: or-int v9, v1, v4
+002ace: 9501 000c                              |0037: and-int v1, v0, v12
+002ad2: 3301 0900                              |0039: if-ne v1, v0, 0042 // +0009
+002ad6: 07a0                                   |003b: move-object v0, v10
+002ad8: 07b1                                   |003c: move-object v1, v11
+002ada: 01e4                                   |003d: move v4, v14
+002adc: 01f5                                   |003e: move v5, v15
+002ade: 7606 5400 0000                         |003f: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIII)V // method@0054
+002ae4: 9500 090c                              |0042: and-int v0, v9, v12
+002ae8: 3390 0b00                              |0044: if-ne v0, v9, 004f // +000b
+002aec: 07a0                                   |0046: move-object v0, v10
+002aee: 07b1                                   |0047: move-object v1, v11
+002af0: 0172                                   |0048: move v2, v7
+002af2: 0163                                   |0049: move v3, v6
+002af4: 01e4                                   |004a: move v4, v14
+002af6: 01f5                                   |004b: move v5, v15
+002af8: 7606 5400 0000                         |004c: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIII)V // method@0054
+002afe: d800 08ff                              |004f: add-int/lit8 v0, v8, #int -1 // #ff
+002b02: b580                                   |0051: and-int/2addr v0, v8
+002b04: 0108                                   |0052: move v8, v0
+002b06: 3908 c5ff                              |0053: if-nez v8, 0018 // -003b
+002b0a: 28c2                                   |0055: goto 0017 // -003e
+002b0c: d802 03fc                              |0056: add-int/lit8 v2, v3, #int -4 // #fc
+002b10: d801 03fd                              |0058: add-int/lit8 v1, v3, #int -3 // #fd
+002b14: d800 0304                              |005a: add-int/lit8 v0, v3, #int 4 // #04
+002b18: d803 0305                              |005c: add-int/lit8 v3, v3, #int 5 // #05
+002b1c: 0106                                   |005e: move v6, v0
+002b1e: 0117                                   |005f: move v7, v1
+002b20: 28cc                                   |0060: goto 002c // -0034
+002b22: 0108                                   |0061: move v8, v0
+002b24: 28f1                                   |0062: goto 0053 // -000f
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #12              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'c'
+      type          : '(I)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 10
+      ins           : 2
+      outs          : 3
+      insns size    : 262 16-bit code units
+002b28:                                        |[002b28] com.google.android.checkers.CheckersView.c:(I)V
+002b38: 1237                                   |0000: const/4 v7, #int 3 // #3
+002b3a: 1226                                   |0001: const/4 v6, #int 2 // #2
+002b3c: 1212                                   |0002: const/4 v2, #int 1 // #1
+002b3e: 1201                                   |0003: const/4 v1, #int 0 // #0
+002b40: 5280 0c00                              |0004: iget v0, v8, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+002b44: 5483 0800                              |0006: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.G:[I // field@0008
+002b48: 5484 2200                              |0008: iget-object v4, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002b4c: 5244 3d00                              |000a: iget v4, v4, Lcom/google/android/checkers/a;.d:I // field@003d
+002b50: 4b04 0300                              |000c: aput v4, v3, v0
+002b54: 5483 0900                              |000e: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.H:[I // field@0009
+002b58: 5484 2200                              |0010: iget-object v4, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002b5c: 5244 3e00                              |0012: iget v4, v4, Lcom/google/android/checkers/a;.e:I // field@003e
+002b60: 4b04 0300                              |0014: aput v4, v3, v0
+002b64: 5483 0a00                              |0016: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.I:[I // field@000a
+002b68: 5484 2200                              |0018: iget-object v4, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002b6c: 5244 3f00                              |001a: iget v4, v4, Lcom/google/android/checkers/a;.f:I // field@003f
+002b70: 4b04 0300                              |001c: aput v4, v3, v0
+002b74: 5483 0b00                              |001e: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.J:[I // field@000b
+002b78: 5484 2200                              |0020: iget-object v4, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002b7c: 5244 4000                              |0022: iget v4, v4, Lcom/google/android/checkers/a;.g:I // field@0040
+002b80: 4b04 0300                              |0024: aput v4, v3, v0
+002b84: 5280 0c00                              |0026: iget v0, v8, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+002b88: 1273                                   |0028: const/4 v3, #int 7 // #7
+002b8a: 3530 6e00                              |0029: if-ge v0, v3, 0097 // +006e
+002b8e: 5280 0c00                              |002b: iget v0, v8, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+002b92: d800 0001                              |002d: add-int/lit8 v0, v0, #int 1 // #01
+002b96: 5980 0c00                              |002f: iput v0, v8, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+002b9a: 5280 0d00                              |0031: iget v0, v8, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+002b9e: 1303 0800                              |0033: const/16 v3, #int 8 // #8
+002ba2: 3530 0800                              |0035: if-ge v0, v3, 003d // +0008
+002ba6: 5280 0d00                              |0037: iget v0, v8, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+002baa: d800 0001                              |0039: add-int/lit8 v0, v0, #int 1 // #01
+002bae: 5980 0d00                              |003b: iput v0, v8, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+002bb2: 5280 2300                              |003d: iget v0, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002bb6: 3220 5b00                              |003f: if-eq v0, v2, 009a // +005b
+002bba: 5280 2300                              |0041: iget v0, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002bbe: 3260 5700                              |0043: if-eq v0, v6, 009a // +0057
+002bc2: 0110                                   |0045: move v0, v1
+002bc4: 5981 2800                              |0046: iput v1, v8, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+002bc8: 5981 2900                              |0048: iput v1, v8, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+002bcc: 5483 2200                              |004a: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002bd0: 5433 3b00                              |004c: iget-object v3, v3, Lcom/google/android/checkers/a;.b:[I // field@003b
+002bd4: 4403 0309                              |004e: aget v3, v3, v9
+002bd8: 5983 2a00                              |0050: iput v3, v8, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+002bdc: 1403 6666 663f                         |0052: const v3, #float 0.900000 // #3f666666
+002be2: 5983 1e00                              |0055: iput v3, v8, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+002be6: 3800 4500                              |0057: if-eqz v0, 009c // +0045
+002bea: 5483 2200                              |0059: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002bee: 5433 3a00                              |005b: iget-object v3, v3, Lcom/google/android/checkers/a;.a:[I // field@003a
+002bf2: 4403 0309                              |005d: aget v3, v3, v9
+002bf6: 5284 2400                              |005f: iget v4, v8, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+002bfa: 5285 2600                              |0061: iget v5, v8, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+002bfe: b654                                   |0063: or-int/2addr v4, v5
+002c00: b543                                   |0064: and-int/2addr v3, v4
+002c02: 5983 1f00                              |0065: iput v3, v8, Lcom/google/android/checkers/CheckersView;.m:I // field@001f
+002c06: 5981 2000                              |0067: iput v1, v8, Lcom/google/android/checkers/CheckersView;.n:I // field@0020
+002c0a: 5483 2200                              |0069: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c0e: 6e20 7c00 9300                         |006b: invoke-virtual {v3, v9}, Lcom/google/android/checkers/a;.a:(I)V // method@007c
+002c14: 5483 2200                              |006e: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c18: 5233 3d00                              |0070: iget v3, v3, Lcom/google/android/checkers/a;.d:I // field@003d
+002c1c: 5983 2400                              |0072: iput v3, v8, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+002c20: 5483 2200                              |0074: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c24: 5233 3f00                              |0076: iget v3, v3, Lcom/google/android/checkers/a;.f:I // field@003f
+002c28: 5983 2500                              |0078: iput v3, v8, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+002c2c: 5483 2200                              |007a: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c30: 5233 3e00                              |007c: iget v3, v3, Lcom/google/android/checkers/a;.e:I // field@003e
+002c34: 5983 2600                              |007e: iput v3, v8, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+002c38: 5483 2200                              |0080: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c3c: 5233 4000                              |0082: iget v3, v3, Lcom/google/android/checkers/a;.g:I // field@0040
+002c40: 5983 2700                              |0084: iput v3, v8, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+002c44: 5c81 2b00                              |0086: iput-boolean v1, v8, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+002c48: 1203                                   |0088: const/4 v3, #int 0 // #0
+002c4a: 5b83 0f00                              |0089: iput-object v3, v8, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+002c4e: 5483 2200                              |008b: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c52: 5584 0300                              |008d: iget-boolean v4, v8, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+002c56: 6e30 7a00 0304                         |008f: invoke-virtual {v3, v0, v4}, Lcom/google/android/checkers/a;.a:(ZZ)I // method@007a
+002c5c: 0a03                                   |0092: move-result v3
+002c5e: 2b03 6900 0000                         |0093: packed-switch v3, 000000fc // +00000069
+002c64: 0e00                                   |0096: return-void
+002c66: 5981 0c00                              |0097: iput v1, v8, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+002c6a: 2898                                   |0099: goto 0031 // -0068
+002c6c: 0120                                   |009a: move v0, v2
+002c6e: 28ab                                   |009b: goto 0046 // -0055
+002c70: 5981 1f00                              |009c: iput v1, v8, Lcom/google/android/checkers/CheckersView;.m:I // field@001f
+002c74: 5483 2200                              |009e: iget-object v3, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002c78: 5433 3a00                              |00a0: iget-object v3, v3, Lcom/google/android/checkers/a;.a:[I // field@003a
+002c7c: 4403 0309                              |00a2: aget v3, v3, v9
+002c80: 5284 2500                              |00a4: iget v4, v8, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+002c84: 5285 2700                              |00a6: iget v5, v8, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+002c88: b654                                   |00a8: or-int/2addr v4, v5
+002c8a: b543                                   |00a9: and-int/2addr v3, v4
+002c8c: 5983 2000                              |00aa: iput v3, v8, Lcom/google/android/checkers/CheckersView;.n:I // field@0020
+002c90: 28bd                                   |00ac: goto 0069 // -0043
+002c92: 3800 0800                              |00ad: if-eqz v0, 00b5 // +0008
+002c96: 1260                                   |00af: const/4 v0, #int 6 // #6
+002c98: 5980 2300                              |00b0: iput v0, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002c9c: 5981 0e00                              |00b2: iput v1, v8, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+002ca0: 28e2                                   |00b4: goto 0096 // -001e
+002ca2: 1250                                   |00b5: const/4 v0, #int 5 // #5
+002ca4: 28fa                                   |00b6: goto 00b0 // -0006
+002ca6: 5c82 2b00                              |00b7: iput-boolean v2, v8, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+002caa: 5481 2200                              |00b9: iget-object v1, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002cae: 5211 3c00                              |00bb: iget v1, v1, Lcom/google/android/checkers/a;.c:I // field@003c
+002cb2: 5981 0e00                              |00bd: iput v1, v8, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+002cb6: 5281 2300                              |00bf: iget v1, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002cba: 3321 1800                              |00c1: if-ne v1, v2, 00d9 // +0018
+002cbe: 5281 2c00                              |00c3: iget v1, v8, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+002cc2: 3901 0900                              |00c5: if-nez v1, 00ce // +0009
+002cc6: 5987 2300                              |00c7: iput v7, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002cca: 1a00 d200                              |00c9: const-string v0, "free play" // string@00d2
+002cce: 5b80 0f00                              |00cb: iput-object v0, v8, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+002cd2: 28c9                                   |00cd: goto 0096 // -0037
+002cd4: 1241                                   |00ce: const/4 v1, #int 4 // #4
+002cd6: 5981 2300                              |00cf: iput v1, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002cda: 5481 2200                              |00d1: iget-object v1, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002cde: 5582 0300                              |00d3: iget-boolean v2, v8, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+002ce2: 6e30 8700 0102                         |00d5: invoke-virtual {v1, v0, v2}, Lcom/google/android/checkers/a;.b:(ZZ)V // method@0087
+002ce8: 28be                                   |00d8: goto 0096 // -0042
+002cea: 5281 2300                              |00d9: iget v1, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002cee: 3371 1700                              |00db: if-ne v1, v7, 00f2 // +0017
+002cf2: 5281 2c00                              |00dd: iget v1, v8, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+002cf6: 3901 0900                              |00df: if-nez v1, 00e8 // +0009
+002cfa: 5982 2300                              |00e1: iput v2, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002cfe: 1a00 d200                              |00e3: const-string v0, "free play" // string@00d2
+002d02: 5b80 0f00                              |00e5: iput-object v0, v8, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+002d06: 28af                                   |00e7: goto 0096 // -0051
+002d08: 5986 2300                              |00e8: iput v6, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002d0c: 5481 2200                              |00ea: iget-object v1, v8, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+002d10: 5582 0300                              |00ec: iget-boolean v2, v8, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+002d14: 6e30 8700 0102                         |00ee: invoke-virtual {v1, v0, v2}, Lcom/google/android/checkers/a;.b:(ZZ)V // method@0087
+002d1a: 28a5                                   |00f1: goto 0096 // -005b
+002d1c: 5280 2300                              |00f2: iget v0, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002d20: 3360 0500                              |00f4: if-ne v0, v6, 00f9 // +0005
+002d24: 5987 2300                              |00f6: iput v7, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002d28: 289e                                   |00f8: goto 0096 // -0062
+002d2a: 5982 2300                              |00f9: iput v2, v8, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+002d2e: 289b                                   |00fb: goto 0096 // -0065
+002d30: 0001 0300 0000 0000 1a00 0000 2400 ... |00fc: packed-switch-data (10 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #13              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'd'
+      type          : '()V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 6
+      ins           : 1
+      outs          : 5
+      insns size    : 88 16-bit code units
+002d44:                                        |[002d44] com.google.android.checkers.CheckersView.d:()V
+002d54: 1303 8b00                              |0000: const/16 v3, #int 139 // #8b
+002d58: 1301 cc00                              |0002: const/16 v1, #int 204 // #cc
+002d5c: 1304 ff00                              |0004: const/16 v4, #int 255 // #ff
+002d60: 5250 0700                              |0006: iget v0, v5, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+002d64: 2b00 4000 0000                         |0008: packed-switch v0, 00000048 // +00000040
+002d6a: 0e00                                   |000b: return-void
+002d6c: 5450 1700                              |000c: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+002d70: 1301 6600                              |000e: const/16 v1, #int 102 // #66
+002d74: 1302 cd00                              |0010: const/16 v2, #int 205 // #cd
+002d78: 1303 aa00                              |0012: const/16 v3, #int 170 // #aa
+002d7c: 6e53 2200 4021                         |0014: invoke-virtual {v0, v4, v1, v2, v3}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+002d82: 28f4                                   |0017: goto 000b // -000c
+002d84: 5450 1700                              |0018: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+002d88: 1301 4500                              |001a: const/16 v1, #int 69 // #45
+002d8c: 1302 7400                              |001c: const/16 v2, #int 116 // #74
+002d90: 6e52 2200 4031                         |001e: invoke-virtual {v0, v4, v1, v3, v2}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+002d96: 28ea                                   |0021: goto 000b // -0016
+002d98: 5450 1700                              |0022: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+002d9c: 1301 1e00                              |0024: const/16 v1, #int 30 // #1e
+002da0: 1302 9000                              |0026: const/16 v2, #int 144 // #90
+002da4: 6e54 2200 4021                         |0028: invoke-virtual {v0, v4, v1, v2, v4}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+002daa: 28e0                                   |002b: goto 000b // -0020
+002dac: 5450 1700                              |002c: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+002db0: 1301 8e00                              |002e: const/16 v1, #int 142 // #8e
+002db4: 1302 6b00                              |0030: const/16 v2, #int 107 // #6b
+002db8: 1303 2300                              |0032: const/16 v3, #int 35 // #23
+002dbc: 6e53 2200 4021                         |0034: invoke-virtual {v0, v4, v1, v2, v3}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+002dc2: 28d4                                   |0037: goto 000b // -002c
+002dc4: 5450 1700                              |0038: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+002dc8: 1301 6c00                              |003a: const/16 v1, #int 108 // #6c
+002dcc: 1302 7b00                              |003c: const/16 v2, #int 123 // #7b
+002dd0: 6e53 2200 4021                         |003e: invoke-virtual {v0, v4, v1, v2, v3}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+002dd6: 28ca                                   |0041: goto 000b // -0036
+002dd8: 5450 1700                              |0042: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+002ddc: 6e51 2200 4011                         |0044: invoke-virtual {v0, v4, v1, v1, v1}, Landroid/graphics/Paint;.setARGB:(IIII)V // method@0022
+002de2: 28c4                                   |0047: goto 000b // -003c
+002de4: 0001 0600 0100 0000 0400 0000 1000 ... |0048: packed-switch-data (16 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #14              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'e'
+      type          : '()Z'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 3
+      ins           : 1
+      outs          : 0
+      insns size    : 10 16-bit code units
+002e04:                                        |[002e04] com.google.android.checkers.CheckersView.e:()Z
+002e14: 5220 2500                              |0000: iget v0, v2, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+002e18: 1501 f0ff                              |0002: const/high16 v1, #int -1048576 // #fff0
+002e1c: 3310 0400                              |0004: if-ne v0, v1, 0008 // +0004
+002e20: 1210                                   |0006: const/4 v0, #int 1 // #1
+002e22: 0f00                                   |0007: return v0
+002e24: 1200                                   |0008: const/4 v0, #int 0 // #0
+002e26: 28fe                                   |0009: goto 0007 // -0002
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '()V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 4
+      ins           : 1
+      outs          : 3
+      insns size    : 64 16-bit code units
+002e28:                                        |[002e28] com.google.android.checkers.CheckersView.a:()V
+002e38: 1270                                   |0000: const/4 v0, #int 7 // #7
+002e3a: 2300 3800                              |0001: new-array v0, v0, [Ljava/lang/CharSequence; // type@0038
+002e3e: 1201                                   |0003: const/4 v1, #int 0 // #0
+002e40: 1a02 9d00                              |0004: const-string v2, "Wood" // string@009d
+002e44: 4d02 0001                              |0006: aput-object v2, v0, v1
+002e48: 1211                                   |0008: const/4 v1, #int 1 // #1
+002e4a: 1a02 6000                              |0009: const-string v2, "Light Aquamarine" // string@0060
+002e4e: 4d02 0001                              |000b: aput-object v2, v0, v1
+002e52: 1221                                   |000d: const/4 v1, #int 2 // #2
+002e54: 1a02 1400                              |000e: const-string v2, "Dark Aquamarine" // string@0014
+002e58: 4d02 0001                              |0010: aput-object v2, v0, v1
+002e5c: 1231                                   |0012: const/4 v1, #int 3 // #3
+002e5e: 1a02 0c00                              |0013: const-string v2, "Blue" // string@000c
+002e62: 4d02 0001                              |0015: aput-object v2, v0, v1
+002e66: 1241                                   |0017: const/4 v1, #int 4 // #4
+002e68: 1a02 0e00                              |0018: const-string v2, "Brown" // string@000e
+002e6c: 4d02 0001                              |001a: aput-object v2, v0, v1
+002e70: 1251                                   |001c: const/4 v1, #int 5 // #5
+002e72: 1a02 1a00                              |001d: const-string v2, "Grey" // string@001a
+002e76: 4d02 0001                              |001f: aput-object v2, v0, v1
+002e7a: 1261                                   |0021: const/4 v1, #int 6 // #6
+002e7c: 1a02 6100                              |0022: const-string v2, "Light Grey" // string@0061
+002e80: 4d02 0001                              |0024: aput-object v2, v0, v1
+002e84: 2201 0500                              |0026: new-instance v1, Landroid/app/AlertDialog$Builder; // type@0005
+002e88: 5432 1300                              |0028: iget-object v2, v3, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+002e8c: 7020 0900 2100                         |002a: invoke-direct {v1, v2}, Landroid/app/AlertDialog$Builder;.<init>:(Landroid/content/Context;)V // method@0009
+002e92: 1a02 0d00                              |002d: const-string v2, "Board Color" // string@000d
+002e96: 6e20 0f00 2100                         |002f: invoke-virtual {v1, v2}, Landroid/app/AlertDialog$Builder;.setTitle:(Ljava/lang/CharSequence;)Landroid/app/AlertDialog$Builder; // method@000f
+002e9c: 0c01                                   |0032: move-result-object v1
+002e9e: 2202 2500                              |0033: new-instance v2, Lcom/google/android/checkers/f; // type@0025
+002ea2: 7020 9700 3200                         |0035: invoke-direct {v2, v3}, Lcom/google/android/checkers/f;.<init>:(Lcom/google/android/checkers/CheckersView;)V // method@0097
+002ea8: 6e30 0b00 0102                         |0038: invoke-virtual {v1, v0, v2}, Landroid/app/AlertDialog$Builder;.setItems:([Ljava/lang/CharSequence;Landroid/content/DialogInterface$OnClickListener;)Landroid/app/AlertDialog$Builder; // method@000b
+002eae: 0c00                                   |003b: move-result-object v0
+002eb0: 6e10 1000 0000                         |003c: invoke-virtual {v0}, Landroid/app/AlertDialog$Builder;.show:()Landroid/app/AlertDialog; // method@0010
+002eb6: 0e00                                   |003f: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #1              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(FF)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 10
+      ins           : 3
+      outs          : 1
+      insns size    : 113 16-bit code units
+002eb8:                                        |[002eb8] com.google.android.checkers.CheckersView.a:(FF)V
+002ec8: 1206                                   |0000: const/4 v6, #int 0 // #0
+002eca: 6e10 6a00 0700                         |0001: invoke-virtual {v7}, Lcom/google/android/checkers/CheckersView;.getWidth:()I // method@006a
+002ed0: 0a01                                   |0004: move-result v1
+002ed2: 6e10 6900 0700                         |0005: invoke-virtual {v7}, Lcom/google/android/checkers/CheckersView;.getHeight:()I // method@0069
+002ed8: 0a02                                   |0008: move-result v2
+002eda: 3521 4900                              |0009: if-ge v1, v2, 0052 // +0049
+002ede: 0110                                   |000b: move v0, v1
+002ee0: e200 0003                              |000c: ushr-int/lit8 v0, v0, #int 3 // #03
+002ee4: e003 0003                              |000e: shl-int/lit8 v3, v0, #int 3 // #03
+002ee8: 5274 1000                              |0010: iget v4, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002eec: 2e04 0604                              |0012: cmpg-float v4, v6, v4
+002ef0: 3c04 1600                              |0014: if-gtz v4, 002a // +0016
+002ef4: 5274 1000                              |0016: iget v4, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002ef8: 8235                                   |0018: int-to-float v5, v3
+002efa: 2e04 0405                              |0019: cmpg-float v4, v4, v5
+002efe: 3b04 0f00                              |001b: if-gez v4, 002a // +000f
+002f02: 5274 1100                              |001d: iget v4, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f06: 2e04 0604                              |001f: cmpg-float v4, v6, v4
+002f0a: 3c04 0900                              |0021: if-gtz v4, 002a // +0009
+002f0e: 5274 1100                              |0023: iget v4, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f12: 8233                                   |0025: int-to-float v3, v3
+002f14: 2e03 0403                              |0026: cmpg-float v3, v4, v3
+002f18: 3a03 0400                              |0028: if-ltz v3, 002c // +0004
+002f1c: 1300 1000                              |002a: const/16 v0, #int 16 // #10
+002f20: 1d07                                   |002c: monitor-enter v7
+002f22: 5273 1000                              |002d: iget v3, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002f26: 8204                                   |002f: int-to-float v4, v0
+002f28: c884                                   |0030: mul-float/2addr v4, v8
+002f2a: c643                                   |0031: add-float/2addr v3, v4
+002f2c: 5973 1000                              |0032: iput v3, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002f30: 5273 1100                              |0034: iget v3, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f34: 8200                                   |0036: int-to-float v0, v0
+002f36: c890                                   |0037: mul-float/2addr v0, v9
+002f38: c630                                   |0038: add-float/2addr v0, v3
+002f3a: 5970 1100                              |0039: iput v0, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f3e: 5270 1000                              |003b: iget v0, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002f42: 2e00 0006                              |003d: cmpg-float v0, v0, v6
+002f46: 3b00 1500                              |003f: if-gez v0, 0054 // +0015
+002f4a: 1200                                   |0041: const/4 v0, #int 0 // #0
+002f4c: 5970 1000                              |0042: iput v0, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002f50: 5270 1100                              |0044: iget v0, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f54: 2e00 0006                              |0046: cmpg-float v0, v0, v6
+002f58: 3b00 1c00                              |0048: if-gez v0, 0064 // +001c
+002f5c: 1200                                   |004a: const/4 v0, #int 0 // #0
+002f5e: 5970 1100                              |004b: iput v0, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f62: 1e07                                   |004d: monitor-exit v7
+002f64: 6e10 6d00 0700                         |004e: invoke-virtual {v7}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+002f6a: 0e00                                   |0051: return-void
+002f6c: 0120                                   |0052: move v0, v2
+002f6e: 28b9                                   |0053: goto 000c // -0047
+002f70: 5270 1000                              |0054: iget v0, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002f74: 8213                                   |0056: int-to-float v3, v1
+002f76: 2d00 0003                              |0057: cmpl-float v0, v0, v3
+002f7a: 3a00 ebff                              |0059: if-ltz v0, 0044 // -0015
+002f7e: d800 01ff                              |005b: add-int/lit8 v0, v1, #int -1 // #ff
+002f82: 8200                                   |005d: int-to-float v0, v0
+002f84: 5970 1000                              |005e: iput v0, v7, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+002f88: 28e4                                   |0060: goto 0044 // -001c
+002f8a: 0d00                                   |0061: move-exception v0
+002f8c: 1e07                                   |0062: monitor-exit v7
+002f8e: 2700                                   |0063: throw v0
+002f90: 5270 1100                              |0064: iget v0, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002f94: 8221                                   |0066: int-to-float v1, v2
+002f96: 2d00 0001                              |0067: cmpl-float v0, v0, v1
+002f9a: 3a00 e4ff                              |0069: if-ltz v0, 004d // -001c
+002f9e: d800 02ff                              |006b: add-int/lit8 v0, v2, #int -1 // #ff
+002fa2: 8200                                   |006d: int-to-float v0, v0
+002fa4: 5970 1100                              |006e: iput v0, v7, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+002fa8: 28dd                                   |0070: goto 004d // -0023
+      catches       : 3
+        0x002d - 0x004e
+          <any> -> 0x0061
+        0x0054 - 0x0060
+          <any> -> 0x0061
+        0x0064 - 0x0070
+          <any> -> 0x0061
+      positions     : 
+      locals        : 
+
+    #2              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(IIII)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 11
+      ins           : 5
+      outs          : 6
+      insns size    : 16 16-bit code units
+002fc8:                                        |[002fc8] com.google.android.checkers.CheckersView.a:(IIII)V
+002fd8: 1211                                   |0000: const/4 v1, #int 1 // #1
+002fda: 0760                                   |0001: move-object v0, v6
+002fdc: 0172                                   |0002: move v2, v7
+002fde: 0183                                   |0003: move v3, v8
+002fe0: 0194                                   |0004: move v4, v9
+002fe2: 01a5                                   |0005: move v5, v10
+002fe4: 7606 5b00 0000                         |0006: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(ZIIII)Z // method@005b
+002fea: 0a00                                   |0009: move-result v0
+002fec: 3800 0500                              |000a: if-eqz v0, 000f // +0005
+002ff0: 6e10 6d00 0600                         |000c: invoke-virtual {v6}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+002ff6: 0e00                                   |000f: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #3              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Landroid/content/SharedPreferences$Editor;)V'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 4
+      ins           : 2
+      outs          : 3
+      insns size    : 170 16-bit code units
+002ff8:                                        |[002ff8] com.google.android.checkers.CheckersView.a:(Landroid/content/SharedPreferences$Editor;)V
+003008: 1d02                                   |0000: monitor-enter v2
+00300a: 7210 1300 0300                         |0001: invoke-interface {v3}, Landroid/content/SharedPreferences$Editor;.clear:()Landroid/content/SharedPreferences$Editor; // method@0013
+003010: 1a00 d000                              |0004: const-string v0, "format" // string@00d0
+003014: 1301 2200                              |0006: const/16 v1, #int 34 // #22
+003018: 7230 1600 0301                         |0008: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+00301e: 1a00 3101                              |000b: const-string v0, "state" // string@0131
+003022: 5221 2300                              |000d: iget v1, v2, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+003026: 7230 1600 0301                         |000f: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+00302c: 1a00 3f01                              |0012: const-string v0, "wp" // string@013f
+003030: 5221 2400                              |0014: iget v1, v2, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+003034: 7230 1600 0301                         |0016: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+00303a: 1a00 b400                              |0019: const-string v0, "bp" // string@00b4
+00303e: 5221 2500                              |001b: iget v1, v2, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+003042: 7230 1600 0301                         |001d: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003048: 1a00 3e01                              |0020: const-string v0, "wk" // string@013e
+00304c: 5221 2600                              |0022: iget v1, v2, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+003050: 7230 1600 0301                         |0024: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003056: 1a00 b300                              |0027: const-string v0, "bk" // string@00b3
+00305a: 5221 2700                              |0029: iget v1, v2, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+00305e: 7230 1600 0301                         |002b: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003064: 1a00 e800                              |002e: const-string v0, "l1" // string@00e8
+003068: 5221 2800                              |0030: iget v1, v2, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+00306c: 7230 1600 0301                         |0032: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003072: 1a00 e900                              |0035: const-string v0, "l2" // string@00e9
+003076: 5221 2900                              |0037: iget v1, v2, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+00307a: 7230 1600 0301                         |0039: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003080: 1a00 ef00                              |003c: const-string v0, "lm" // string@00ef
+003084: 5221 2a00                              |003e: iget v1, v2, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+003088: 7230 1600 0301                         |0040: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+00308e: 1a00 b800                              |0043: const-string v0, "cap" // string@00b8
+003092: 5521 2b00                              |0045: iget-boolean v1, v2, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+003096: 7230 1500 0301                         |0047: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putBoolean:(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; // method@0015
+00309c: 1a00 ee00                              |004a: const-string v0, "level" // string@00ee
+0030a0: 5221 2c00                              |004c: iget v1, v2, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+0030a4: 7230 1600 0301                         |004e: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+0030aa: 1a00 2d01                              |0051: const-string v0, "show" // string@012d
+0030ae: 5521 0200                              |0053: iget-boolean v1, v2, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+0030b2: 7230 1500 0301                         |0055: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putBoolean:(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; // method@0015
+0030b8: 1a00 d100                              |0058: const-string v0, "free" // string@00d1
+0030bc: 5521 0300                              |005a: iget-boolean v1, v2, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+0030c0: 7230 1500 0301                         |005c: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putBoolean:(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; // method@0015
+0030c6: 1a00 1801                              |005f: const-string v0, "rot" // string@0118
+0030ca: 5521 0400                              |0061: iget-boolean v1, v2, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+0030ce: 7230 1500 0301                         |0063: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putBoolean:(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; // method@0015
+0030d4: 1a00 d300                              |0066: const-string v0, "full" // string@00d3
+0030d8: 5521 0500                              |0068: iget-boolean v1, v2, Lcom/google/android/checkers/CheckersView;.D:Z // field@0005
+0030dc: 7230 1500 0301                         |006a: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putBoolean:(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; // method@0015
+0030e2: 1a00 2f01                              |006d: const-string v0, "start" // string@012f
+0030e6: 5521 0600                              |006f: iget-boolean v1, v2, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+0030ea: 7230 1500 0301                         |0071: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putBoolean:(Ljava/lang/String;Z)Landroid/content/SharedPreferences$Editor; // method@0015
+0030f0: 1a00 bd00                              |0074: const-string v0, "color" // string@00bd
+0030f4: 5221 0700                              |0076: iget v1, v2, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+0030f8: 7230 1600 0301                         |0078: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+0030fe: 1a00 f300                              |007b: const-string v0, "lwp" // string@00f3
+003102: 5421 0800                              |007d: iget-object v1, v2, Lcom/google/android/checkers/CheckersView;.G:[I // field@0008
+003106: 7130 5200 0301                         |007f: invoke-static {v3, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V // method@0052
+00310c: 1a00 f200                              |0082: const-string v0, "lwk" // string@00f2
+003110: 5421 0900                              |0084: iget-object v1, v2, Lcom/google/android/checkers/CheckersView;.H:[I // field@0009
+003114: 7130 5200 0301                         |0086: invoke-static {v3, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V // method@0052
+00311a: 1a00 eb00                              |0089: const-string v0, "lbp" // string@00eb
+00311e: 5421 0a00                              |008b: iget-object v1, v2, Lcom/google/android/checkers/CheckersView;.I:[I // field@000a
+003122: 7130 5200 0301                         |008d: invoke-static {v3, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V // method@0052
+003128: 1a00 ea00                              |0090: const-string v0, "lbk" // string@00ea
+00312c: 5421 0b00                              |0092: iget-object v1, v2, Lcom/google/android/checkers/CheckersView;.J:[I // field@000b
+003130: 7130 5200 0301                         |0094: invoke-static {v3, v0, v1}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V // method@0052
+003136: 1a00 f100                              |0097: const-string v0, "lp" // string@00f1
+00313a: 5221 0c00                              |0099: iget v1, v2, Lcom/google/android/checkers/CheckersView;.K:I // field@000c
+00313e: 7230 1600 0301                         |009b: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003144: 1a00 ec00                              |009e: const-string v0, "lc" // string@00ec
+003148: 5221 0d00                              |00a0: iget v1, v2, Lcom/google/android/checkers/CheckersView;.L:I // field@000d
+00314c: 7230 1600 0301                         |00a2: invoke-interface {v3, v0, v1}, Landroid/content/SharedPreferences$Editor;.putInt:(Ljava/lang/String;I)Landroid/content/SharedPreferences$Editor; // method@0016
+003152: 1e02                                   |00a5: monitor-exit v2
+003154: 0e00                                   |00a6: return-void
+003156: 0d00                                   |00a7: move-exception v0
+003158: 1e02                                   |00a8: monitor-exit v2
+00315a: 2700                                   |00a9: throw v0
+      catches       : 1
+        0x0001 - 0x00a5
+          <any> -> 0x00a7
+      positions     : 
+      locals        : 
+
+    #4              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(I)Z'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 8
+      ins           : 2
+      outs          : 6
+      insns size    : 17 16-bit code units
+003168:                                        |[003168] com.google.android.checkers.CheckersView.a:(I)Z
+003178: 1201                                   |0000: const/4 v1, #int 0 // #0
+00317a: 0760                                   |0001: move-object v0, v6
+00317c: 0172                                   |0002: move v2, v7
+00317e: 0113                                   |0003: move v3, v1
+003180: 0114                                   |0004: move v4, v1
+003182: 0115                                   |0005: move v5, v1
+003184: 7606 5b00 0000                         |0006: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(ZIIII)Z // method@005b
+00318a: 0a00                                   |0009: move-result v0
+00318c: 3800 0600                              |000a: if-eqz v0, 0010 // +0006
+003190: 6e10 6d00 0600                         |000c: invoke-virtual {v6}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+003196: 1211                                   |000f: const/4 v1, #int 1 // #1
+003198: 0f01                                   |0010: return v1
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #5              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'a'
+      type          : '(Z)Z'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 3
+      ins           : 2
+      outs          : 1
+      insns size    : 22 16-bit code units
+00319c:                                        |[00319c] com.google.android.checkers.CheckersView.a:(Z)Z
+0031ac: 1d01                                   |0000: monitor-enter v1
+0031ae: 3802 0c00                              |0001: if-eqz v2, 000d // +000c
+0031b2: 5510 0200                              |0003: iget-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+0031b6: 3800 0c00                              |0005: if-eqz v0, 0011 // +000c
+0031ba: 1200                                   |0007: const/4 v0, #int 0 // #0
+0031bc: 5c10 0200                              |0008: iput-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+0031c0: 6e10 6d00 0100                         |000a: invoke-virtual {v1}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+0031c6: 5510 0200                              |000d: iget-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+0031ca: 1e01                                   |000f: monitor-exit v1
+0031cc: 0f00                                   |0010: return v0
+0031ce: 1210                                   |0011: const/4 v0, #int 1 // #1
+0031d0: 28f6                                   |0012: goto 0008 // -000a
+0031d2: 0d00                                   |0013: move-exception v0
+0031d4: 1e01                                   |0014: monitor-exit v1
+0031d6: 2700                                   |0015: throw v0
+      catches       : 1
+        0x0003 - 0x000f
+          <any> -> 0x0013
+      positions     : 
+      locals        : 
+
+    #6              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'b'
+      type          : '()V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 7
+      ins           : 1
+      outs          : 6
+      insns size    : 30 16-bit code units
+0031e4:                                        |[0031e4] com.google.android.checkers.CheckersView.b:()V
+0031f4: 1201                                   |0000: const/4 v1, #int 0 // #0
+0031f6: 1d06                                   |0001: monitor-enter v6
+0031f8: 5260 1000                              |0002: iget v0, v6, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+0031fc: 5262 1100                              |0004: iget v2, v6, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+003200: 7030 5c00 0602                         |0006: invoke-direct {v6, v0, v2}, Lcom/google/android/checkers/CheckersView;.b:(FF)I // method@005c
+003206: 0a02                                   |0009: move-result v2
+003208: 1e06                                   |000a: monitor-exit v6
+00320a: 3802 0f00                              |000b: if-eqz v2, 001a // +000f
+00320e: 0760                                   |000d: move-object v0, v6
+003210: 0113                                   |000e: move v3, v1
+003212: 0114                                   |000f: move v4, v1
+003214: 0115                                   |0010: move v5, v1
+003216: 7606 5b00 0000                         |0011: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(ZIIII)Z // method@005b
+00321c: 0a00                                   |0014: move-result v0
+00321e: 3800 0500                              |0015: if-eqz v0, 001a // +0005
+003222: 6e10 6d00 0600                         |0017: invoke-virtual {v6}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+003228: 0e00                                   |001a: return-void
+00322a: 0d00                                   |001b: move-exception v0
+00322c: 1e06                                   |001c: monitor-exit v6
+00322e: 2700                                   |001d: throw v0
+      catches       : 1
+        0x0002 - 0x000b
+          <any> -> 0x001b
+      positions     : 
+      locals        : 
+
+    #7              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'b'
+      type          : '(Z)Z'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 7
+      ins           : 2
+      outs          : 3
+      insns size    : 69 16-bit code units
+00323c:                                        |[00323c] com.google.android.checkers.CheckersView.b:(Z)Z
+00324c: 1233                                   |0000: const/4 v3, #int 3 // #3
+00324e: 1210                                   |0001: const/4 v0, #int 1 // #1
+003250: 1201                                   |0002: const/4 v1, #int 0 // #0
+003252: 1d05                                   |0003: monitor-enter v5
+003254: 3806 3400                              |0004: if-eqz v6, 0038 // +0034
+003258: 5552 0300                              |0006: iget-boolean v2, v5, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+00325c: 3802 3400                              |0008: if-eqz v2, 003c // +0034
+003260: 0112                                   |000a: move v2, v1
+003262: 5c52 0300                              |000b: iput-boolean v2, v5, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+003266: 5252 2300                              |000d: iget v2, v5, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00326a: 3232 0600                              |000f: if-eq v2, v3, 0015 // +0006
+00326e: 5252 2300                              |0011: iget v2, v5, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+003272: 3302 2500                              |0013: if-ne v2, v0, 0038 // +0025
+003276: 5252 2300                              |0015: iget v2, v5, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00327a: 3332 2700                              |0017: if-ne v2, v3, 003e // +0027
+00327e: 0102                                   |0019: move v2, v0
+003280: 1203                                   |001a: const/4 v3, #int 0 // #0
+003282: 5953 2800                              |001b: iput v3, v5, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+003286: 1203                                   |001d: const/4 v3, #int 0 // #0
+003288: 5953 2900                              |001e: iput v3, v5, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+00328c: 1203                                   |0020: const/4 v3, #int 0 // #0
+00328e: 5953 2a00                              |0021: iput v3, v5, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+003292: 5453 2200                              |0023: iget-object v3, v5, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+003296: 5554 0300                              |0025: iget-boolean v4, v5, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+00329a: 6e30 7a00 2304                         |0027: invoke-virtual {v3, v2, v4}, Lcom/google/android/checkers/a;.a:(ZZ)I // method@007a
+0032a0: 0a02                                   |002a: move-result v2
+0032a2: 3302 1500                              |002b: if-ne v2, v0, 0040 // +0015
+0032a6: 5c50 2b00                              |002d: iput-boolean v0, v5, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+0032aa: 5450 2200                              |002f: iget-object v0, v5, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+0032ae: 5200 3c00                              |0031: iget v0, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+0032b2: 5950 0e00                              |0033: iput v0, v5, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+0032b6: 6e10 6d00 0500                         |0035: invoke-virtual {v5}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+0032bc: 5550 0300                              |0038: iget-boolean v0, v5, Lcom/google/android/checkers/CheckersView;.B:Z // field@0003
+0032c0: 1e05                                   |003a: monitor-exit v5
+0032c2: 0f00                                   |003b: return v0
+0032c4: 0102                                   |003c: move v2, v0
+0032c6: 28ce                                   |003d: goto 000b // -0032
+0032c8: 0112                                   |003e: move v2, v1
+0032ca: 28db                                   |003f: goto 001a // -0025
+0032cc: 0110                                   |0040: move v0, v1
+0032ce: 28ec                                   |0041: goto 002d // -0014
+0032d0: 0d00                                   |0042: move-exception v0
+0032d2: 1e05                                   |0043: monitor-exit v5
+0032d4: 2700                                   |0044: throw v0
+      catches       : 1
+        0x0006 - 0x003a
+          <any> -> 0x0042
+      positions     : 
+      locals        : 
+
+    #8              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'c'
+      type          : '()I'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 2
+      ins           : 1
+      outs          : 0
+      insns size    : 8 16-bit code units
+0032e4:                                        |[0032e4] com.google.android.checkers.CheckersView.c:()I
+0032f4: 1d01                                   |0000: monitor-enter v1
+0032f6: 5210 2c00                              |0001: iget v0, v1, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+0032fa: 1e01                                   |0003: monitor-exit v1
+0032fc: 0f00                                   |0004: return v0
+0032fe: 0d00                                   |0005: move-exception v0
+003300: 1e01                                   |0006: monitor-exit v1
+003302: 2700                                   |0007: throw v0
+      catches       : 1
+        0x0001 - 0x0003
+          <any> -> 0x0005
+      positions     : 
+      locals        : 
+
+    #9              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'c'
+      type          : '(Z)Z'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 5
+      ins           : 2
+      outs          : 3
+      insns size    : 34 16-bit code units
+003310:                                        |[003310] com.google.android.checkers.CheckersView.c:(Z)Z
+003320: 1200                                   |0000: const/4 v0, #int 0 // #0
+003322: 1d03                                   |0001: monitor-enter v3
+003324: 3804 1700                              |0002: if-eqz v4, 0019 // +0017
+003328: 5531 0400                              |0004: iget-boolean v1, v3, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+00332c: 3801 1700                              |0006: if-eqz v1, 001d // +0017
+003330: 5c30 0400                              |0008: iput-boolean v0, v3, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+003334: 5430 1300                              |000a: iget-object v0, v3, Lcom/google/android/checkers/CheckersView;.a:Landroid/content/Context; // field@0013
+003338: 1a01 1901                              |000c: const-string v1, "rotated board" // string@0119
+00333c: 1202                                   |000e: const/4 v2, #int 0 // #0
+00333e: 7130 3c00 1002                         |000f: invoke-static {v0, v1, v2}, Landroid/widget/Toast;.makeText:(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast; // method@003c
+003344: 0c00                                   |0012: move-result-object v0
+003346: 6e10 3d00 0000                         |0013: invoke-virtual {v0}, Landroid/widget/Toast;.show:()V // method@003d
+00334c: 6e10 6d00 0300                         |0016: invoke-virtual {v3}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+003352: 5530 0400                              |0019: iget-boolean v0, v3, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+003356: 1e03                                   |001b: monitor-exit v3
+003358: 0f00                                   |001c: return v0
+00335a: 1210                                   |001d: const/4 v0, #int 1 // #1
+00335c: 28ea                                   |001e: goto 0008 // -0016
+00335e: 0d00                                   |001f: move-exception v0
+003360: 1e03                                   |0020: monitor-exit v3
+003362: 2700                                   |0021: throw v0
+      catches       : 1
+        0x0004 - 0x001b
+          <any> -> 0x001f
+      positions     : 
+      locals        : 
+
+    #10              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'd'
+      type          : '(Z)Z'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 3
+      ins           : 2
+      outs          : 0
+      insns size    : 19 16-bit code units
+003370:                                        |[003370] com.google.android.checkers.CheckersView.d:(Z)Z
+003380: 1d01                                   |0000: monitor-enter v1
+003382: 3802 0900                              |0001: if-eqz v2, 000a // +0009
+003386: 5510 0500                              |0003: iget-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.D:Z // field@0005
+00338a: 3800 0900                              |0005: if-eqz v0, 000e // +0009
+00338e: 1200                                   |0007: const/4 v0, #int 0 // #0
+003390: 5c10 0500                              |0008: iput-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.D:Z // field@0005
+003394: 5510 0500                              |000a: iget-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.D:Z // field@0005
+003398: 1e01                                   |000c: monitor-exit v1
+00339a: 0f00                                   |000d: return v0
+00339c: 1210                                   |000e: const/4 v0, #int 1 // #1
+00339e: 28f9                                   |000f: goto 0008 // -0007
+0033a0: 0d00                                   |0010: move-exception v0
+0033a2: 1e01                                   |0011: monitor-exit v1
+0033a4: 2700                                   |0012: throw v0
+      catches       : 1
+        0x0003 - 0x000c
+          <any> -> 0x0010
+      positions     : 
+      locals        : 
+
+    #11              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'draw'
+      type          : '(Landroid/graphics/Canvas;)V'
+      access        : 0x20001 (PUBLIC DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 30
+      ins           : 2
+      outs          : 8
+      insns size    : 1264 16-bit code units
+0033b4:                                        |[0033b4] com.google.android.checkers.CheckersView.draw:(Landroid/graphics/Canvas;)V
+0033c4: 1d1c                                   |0000: monitor-enter v28
+0033c6: 7502 3800 1c00                         |0001: invoke-super/range {v28, v29}, Landroid/view/View;.draw:(Landroid/graphics/Canvas;)V // method@0038
+0033cc: 7401 6a00 1c00                         |0004: invoke-virtual/range {v28}, Lcom/google/android/checkers/CheckersView;.getWidth:()I // method@006a
+0033d2: 0a03                                   |0007: move-result v3
+0033d4: 7401 6900 1c00                         |0008: invoke-virtual/range {v28}, Lcom/google/android/checkers/CheckersView;.getHeight:()I // method@0069
+0033da: 0a04                                   |000b: move-result v4
+0033dc: 3543 bc01                              |000c: if-ge v3, v4, 01c8 // +01bc
+0033e0: 0132                                   |000e: move v2, v3
+0033e2: e216 0203                              |000f: ushr-int/lit8 v22, v2, #int 3 // #03
+0033e6: e017 1603                              |0011: shl-int/lit8 v23, v22, #int 3 // #03
+0033ea: e218 1601                              |0013: ushr-int/lit8 v24, v22, #int 1 // #01
+0033ee: 0800 1c00                              |0015: move-object/from16 v0, v28
+0033f2: 5200 1d00                              |0017: iget v0, v0, Lcom/google/android/checkers/CheckersView;.k:I // field@001d
+0033f6: 0214 0000                              |0019: move/from16 v20, v0
+0033fa: db19 1403                              |001b: div-int/lit8 v25, v20, #int 3 // #03
+0033fe: 3543 ae01                              |001d: if-ge v3, v4, 01cb // +01ae
+003402: 1224                                   |001f: const/4 v4, #int 2 // #2
+003404: da02 140b                              |0020: mul-int/lit8 v2, v20, #int 11 // #0b
+003408: 9103 1702                              |0022: sub-int v3, v23, v2
+00340c: 9002 1714                              |0024: add-int v2, v23, v20
+003410: 0211 0200                              |0026: move/from16 v17, v2
+003414: 0212 0300                              |0028: move/from16 v18, v3
+003418: 0213 0200                              |002a: move/from16 v19, v2
+00341c: 0215 0400                              |002c: move/from16 v21, v4
+003420: 0800 1c00                              |002e: move-object/from16 v0, v28
+003424: 5402 1400                              |0030: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+003428: 0800 1d00                              |0032: move-object/from16 v0, v29
+00342c: 6e20 1e00 2000                         |0034: invoke-virtual {v0, v2}, Landroid/graphics/Canvas;.drawPaint:(Landroid/graphics/Paint;)V // method@001e
+003432: 0800 1c00                              |0037: move-object/from16 v0, v28
+003436: 5202 0700                              |0039: iget v2, v0, Lcom/google/android/checkers/CheckersView;.F:I // field@0007
+00343a: 3902 a201                              |003b: if-nez v2, 01dd // +01a2
+00343e: 0800 1c00                              |003d: move-object/from16 v0, v28
+003442: 5407 1600                              |003f: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.d:Landroid/graphics/Paint; // field@0016
+003446: 0800 1c00                              |0041: move-object/from16 v0, v28
+00344a: 5402 2100                              |0043: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.o:Landroid/graphics/drawable/Drawable; // field@0021
+00344e: 1203                                   |0045: const/4 v3, #int 0 // #0
+003450: 1204                                   |0046: const/4 v4, #int 0 // #0
+003452: 0200 1700                              |0047: move/from16 v0, v23
+003456: 0201 1700                              |0049: move/from16 v1, v23
+00345a: 6e51 2800 3204                         |004b: invoke-virtual {v2, v3, v4, v0, v1}, Landroid/graphics/drawable/Drawable;.setBounds:(IIII)V // method@0028
+003460: 0800 1c00                              |004e: move-object/from16 v0, v28
+003464: 5402 2100                              |0050: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.o:Landroid/graphics/drawable/Drawable; // field@0021
+003468: 0800 1d00                              |0052: move-object/from16 v0, v29
+00346c: 6e20 2700 0200                         |0054: invoke-virtual {v2, v0}, Landroid/graphics/drawable/Drawable;.draw:(Landroid/graphics/Canvas;)V // method@0027
+003472: 1202                                   |0057: const/4 v2, #int 0 // #0
+003474: 0129                                   |0058: move v9, v2
+003476: 1302 0800                              |0059: const/16 v2, #int 8 // #8
+00347a: 3429 9a01                              |005b: if-lt v9, v2, 01f5 // +019a
+00347e: 120d                                   |005d: const/4 v13, #int 0 // #0
+003480: 120c                                   |005e: const/4 v12, #int 0 // #0
+003482: 120b                                   |005f: const/4 v11, #int 0 // #0
+003484: 120a                                   |0060: const/4 v10, #int 0 // #0
+003486: 1213                                   |0061: const/4 v3, #int 1 // #1
+003488: 1202                                   |0062: const/4 v2, #int 0 // #0
+00348a: 0210 0200                              |0063: move/from16 v16, v2
+00348e: 1302 0800                              |0065: const/16 v2, #int 8 // #8
+003492: 0200 1000                              |0067: move/from16 v0, v16
+003496: 3420 ad01                              |0069: if-lt v0, v2, 0216 // +01ad
+00349a: 7601 6700 1c00                         |006b: invoke-direct/range {v28}, Lcom/google/android/checkers/CheckersView;.e:()Z // method@0067
+0034a0: 0a02                                   |006e: move-result v2
+0034a2: 3802 4d03                              |006f: if-eqz v2, 03bc // +034d
+0034a6: 1a02 1100                              |0071: const-string v2, "Checkers for Android" // string@0011
+0034aa: 0200 1500                              |0073: move/from16 v0, v21
+0034ae: 8203                                   |0075: int-to-float v3, v0
+0034b0: 0200 1300                              |0076: move/from16 v0, v19
+0034b4: 8204                                   |0078: int-to-float v4, v0
+0034b6: 0800 1c00                              |0079: move-object/from16 v0, v28
+0034ba: 5405 1500                              |007b: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+0034be: 0800 1d00                              |007d: move-object/from16 v0, v29
+0034c2: 6e55 2000 2043                         |007f: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+0034c8: 1a02 b500                              |0082: const-string v2, "by Aart J.C. Bik" // string@00b5
+0034cc: 0200 1500                              |0084: move/from16 v0, v21
+0034d0: 8203                                   |0086: int-to-float v3, v0
+0034d2: 9004 1314                              |0087: add-int v4, v19, v20
+0034d6: 8244                                   |0089: int-to-float v4, v4
+0034d8: 0800 1c00                              |008a: move-object/from16 v0, v28
+0034dc: 5405 1500                              |008c: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+0034e0: 0800 1d00                              |008e: move-object/from16 v0, v29
+0034e4: 6e55 2000 2043                         |0090: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+0034ea: 6302 6a00                              |0093: sget-boolean v2, Lcom/google/android/checkers/g;.r:Z // field@006a
+0034ee: 3902 1500                              |0095: if-nez v2, 00aa // +0015
+0034f2: 1a02 f800                              |0097: const-string v2, "no endgame TBs" // string@00f8
+0034f6: 0200 1500                              |0099: move/from16 v0, v21
+0034fa: 8203                                   |009b: int-to-float v3, v0
+0034fc: da04 1402                              |009c: mul-int/lit8 v4, v20, #int 2 // #02
+003500: 9004 0413                              |009e: add-int v4, v4, v19
+003504: 8244                                   |00a0: int-to-float v4, v4
+003506: 0800 1c00                              |00a1: move-object/from16 v0, v28
+00350a: 5405 1500                              |00a3: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+00350e: 0800 1d00                              |00a5: move-object/from16 v0, v29
+003512: 6e55 2000 2043                         |00a7: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003518: 0800 1c00                              |00aa: move-object/from16 v0, v28
+00351c: 5502 2b00                              |00ac: iget-boolean v2, v0, Lcom/google/android/checkers/CheckersView;.y:Z // field@002b
+003520: 3802 1300                              |00ae: if-eqz v2, 00c1 // +0013
+003524: 1a02 7000                              |00b0: const-string v2, "MUST CAPTURE" // string@0070
+003528: 0200 1200                              |00b2: move/from16 v0, v18
+00352c: 8203                                   |00b4: int-to-float v3, v0
+00352e: 0200 1100                              |00b5: move/from16 v0, v17
+003532: 8204                                   |00b7: int-to-float v4, v0
+003534: 0800 1c00                              |00b8: move-object/from16 v0, v28
+003538: 5405 1800                              |00ba: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.f:Landroid/graphics/Paint; // field@0018
+00353c: 0800 1d00                              |00bc: move-object/from16 v0, v29
+003540: 6e55 2000 2043                         |00be: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003546: 0800 1c00                              |00c1: move-object/from16 v0, v28
+00354a: 5202 2300                              |00c3: iget v2, v0, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+00354e: 2b02 1b04 0000                         |00c5: packed-switch v2, 000004e0 // +0000041b
+003554: 0800 1c00                              |00c8: move-object/from16 v0, v28
+003558: 5502 0200                              |00ca: iget-boolean v2, v0, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+00355c: 3802 2600                              |00cc: if-eqz v2, 00f2 // +0026
+003560: 0800 1c00                              |00ce: move-object/from16 v0, v28
+003564: 5202 2300                              |00d0: iget v2, v0, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+003568: 1213                                   |00d2: const/4 v3, #int 1 // #1
+00356a: 3232 0900                              |00d3: if-eq v2, v3, 00dc // +0009
+00356e: 0800 1c00                              |00d5: move-object/from16 v0, v28
+003572: 5202 2300                              |00d7: iget v2, v0, Lcom/google/android/checkers/CheckersView;.q:I // field@0023
+003576: 1233                                   |00d9: const/4 v3, #int 3 // #3
+003578: 3332 1800                              |00da: if-ne v2, v3, 00f2 // +0018
+00357c: 0800 1c00                              |00dc: move-object/from16 v0, v28
+003580: 5402 2200                              |00de: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+003584: 5229 3c00                              |00e0: iget v9, v2, Lcom/google/android/checkers/a;.c:I // field@003c
+003588: 0800 1c00                              |00e2: move-object/from16 v0, v28
+00358c: 5402 2200                              |00e4: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+003590: 542a 3b00                              |00e6: iget-object v10, v2, Lcom/google/android/checkers/a;.b:[I // field@003b
+003594: 0800 1c00                              |00e8: move-object/from16 v0, v28
+003598: 5402 2200                              |00ea: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+00359c: 542b 3a00                              |00ec: iget-object v11, v2, Lcom/google/android/checkers/a;.a:[I // field@003a
+0035a0: 1202                                   |00ee: const/4 v2, #int 0 // #0
+0035a2: 0128                                   |00ef: move v8, v2
+0035a4: 3498 dc03                              |00f0: if-lt v8, v9, 04cc // +03dc
+0035a8: 0800 1c00                              |00f2: move-object/from16 v0, v28
+0035ac: 5402 0f00                              |00f4: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0035b0: 3802 1700                              |00f6: if-eqz v2, 010d // +0017
+0035b4: 0800 1c00                              |00f8: move-object/from16 v0, v28
+0035b8: 5402 0f00                              |00fa: iget-object v2, v0, Lcom/google/android/checkers/CheckersView;.N:Ljava/lang/String; // field@000f
+0035bc: 0200 1200                              |00fc: move/from16 v0, v18
+0035c0: 8203                                   |00fe: int-to-float v3, v0
+0035c2: da04 1402                              |00ff: mul-int/lit8 v4, v20, #int 2 // #02
+0035c6: 9004 0411                              |0101: add-int v4, v4, v17
+0035ca: 8244                                   |0103: int-to-float v4, v4
+0035cc: 0800 1c00                              |0104: move-object/from16 v0, v28
+0035d0: 5405 1b00                              |0106: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.i:Landroid/graphics/Paint; // field@001b
+0035d4: 0800 1d00                              |0108: move-object/from16 v0, v29
+0035d8: 6e55 2000 2043                         |010a: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+0035de: 1202                                   |010d: const/4 v2, #int 0 // #0
+0035e0: 1203                                   |010e: const/4 v3, #int 0 // #0
+0035e2: 0800 1c00                              |010f: move-object/from16 v0, v28
+0035e6: 5204 1000                              |0111: iget v4, v0, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+0035ea: 2e03 0304                              |0113: cmpg-float v3, v3, v4
+0035ee: 3c03 5100                              |0115: if-gtz v3, 0166 // +0051
+0035f2: 0800 1c00                              |0117: move-object/from16 v0, v28
+0035f6: 5203 1000                              |0119: iget v3, v0, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+0035fa: 0200 1700                              |011b: move/from16 v0, v23
+0035fe: 8204                                   |011d: int-to-float v4, v0
+003600: 2e03 0304                              |011e: cmpg-float v3, v3, v4
+003604: 3b03 4600                              |0120: if-gez v3, 0166 // +0046
+003608: 1203                                   |0122: const/4 v3, #int 0 // #0
+00360a: 0800 1c00                              |0123: move-object/from16 v0, v28
+00360e: 5204 1100                              |0125: iget v4, v0, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+003612: 2e03 0304                              |0127: cmpg-float v3, v3, v4
+003616: 3c03 3d00                              |0129: if-gtz v3, 0166 // +003d
+00361a: 0800 1c00                              |012b: move-object/from16 v0, v28
+00361e: 5203 1100                              |012d: iget v3, v0, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+003622: 0200 1700                              |012f: move/from16 v0, v23
+003626: 8204                                   |0131: int-to-float v4, v0
+003628: 2e03 0304                              |0132: cmpg-float v3, v3, v4
+00362c: 3b03 3200                              |0134: if-gez v3, 0166 // +0032
+003630: 0800 1c00                              |0136: move-object/from16 v0, v28
+003634: 5203 1000                              |0138: iget v3, v0, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+003638: 8733                                   |013a: float-to-int v3, v3
+00363a: 9303 0316                              |013b: div-int v3, v3, v22
+00363e: 0800 1c00                              |013d: move-object/from16 v0, v28
+003642: 5204 1100                              |013f: iget v4, v0, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+003646: 8744                                   |0141: float-to-int v4, v4
+003648: 9304 0416                              |0142: div-int v4, v4, v22
+00364c: 3a03 2200                              |0144: if-ltz v3, 0166 // +0022
+003650: 1305 0800                              |0146: const/16 v5, #int 8 // #8
+003654: 3553 1e00                              |0148: if-ge v3, v5, 0166 // +001e
+003658: 3a04 1c00                              |014a: if-ltz v4, 0166 // +001c
+00365c: 1305 0800                              |014c: const/16 v5, #int 8 // #8
+003660: 3554 1800                              |014e: if-ge v4, v5, 0166 // +0018
+003664: 9202 1603                              |0150: mul-int v2, v22, v3
+003668: 9206 1604                              |0152: mul-int v6, v22, v4
+00366c: 8223                                   |0154: int-to-float v3, v2
+00366e: 8264                                   |0155: int-to-float v4, v6
+003670: 9002 0216                              |0156: add-int v2, v2, v22
+003674: 8225                                   |0158: int-to-float v5, v2
+003676: 9002 0616                              |0159: add-int v2, v6, v22
+00367a: 8226                                   |015b: int-to-float v6, v2
+00367c: 0800 1c00                              |015c: move-object/from16 v0, v28
+003680: 5407 1c00                              |015e: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.j:Landroid/graphics/Paint; // field@001c
+003684: 0802 1d00                              |0160: move-object/from16 v2, v29
+003688: 7406 1f00 0200                         |0162: invoke-virtual/range {v2, v3, v4, v5, v6, v7}, Landroid/graphics/Canvas;.drawRect:(FFFFLandroid/graphics/Paint;)V // method@001f
+00368e: 1212                                   |0165: const/4 v2, #int 1 // #1
+003690: 3902 2800                              |0166: if-nez v2, 018e // +0028
+003694: 0800 1c00                              |0168: move-object/from16 v0, v28
+003698: 5202 1000                              |016a: iget v2, v0, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+00369c: 0800 1c00                              |016c: move-object/from16 v0, v28
+0036a0: 5203 1100                              |016e: iget v3, v0, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+0036a4: 1504 a040                              |0170: const/high16 v4, #int 1084227584 // #40a0
+0036a8: 0800 1c00                              |0172: move-object/from16 v0, v28
+0036ac: 5405 1500                              |0174: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+0036b0: 0800 1d00                              |0176: move-object/from16 v0, v29
+0036b4: 6e55 1c00 2043                         |0178: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0036ba: 0800 1c00                              |017b: move-object/from16 v0, v28
+0036be: 5202 1000                              |017d: iget v2, v0, Lcom/google/android/checkers/CheckersView;.O:F // field@0010
+0036c2: 0800 1c00                              |017f: move-object/from16 v0, v28
+0036c6: 5203 1100                              |0181: iget v3, v0, Lcom/google/android/checkers/CheckersView;.P:F // field@0011
+0036ca: 1504 4040                              |0183: const/high16 v4, #int 1077936128 // #4040
+0036ce: 0800 1c00                              |0185: move-object/from16 v0, v28
+0036d2: 5405 1400                              |0187: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+0036d6: 0800 1d00                              |0189: move-object/from16 v0, v29
+0036da: 6e55 1c00 2043                         |018b: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+0036e0: 0800 1c00                              |018e: move-object/from16 v0, v28
+0036e4: 5202 1e00                              |0190: iget v2, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+0036e8: 1203                                   |0192: const/4 v3, #int 0 // #0
+0036ea: 2d02 0203                              |0193: cmpl-float v2, v2, v3
+0036ee: 3d02 3100                              |0195: if-lez v2, 01c6 // +0031
+0036f2: 0800 1c00                              |0197: move-object/from16 v0, v28
+0036f6: 5202 1e00                              |0199: iget v2, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+0036fa: 8922                                   |019b: float-to-double v2, v2
+0036fc: 1804 9a99 9999 9999 a93f               |019c: const-wide v4, #double 0.050000 // #3fa999999999999a
+003706: cc42                                   |01a1: sub-double/2addr v2, v4
+003708: 8c22                                   |01a2: double-to-float v2, v2
+00370a: 0800 1c00                              |01a3: move-object/from16 v0, v28
+00370e: 5902 1e00                              |01a5: iput v2, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+003712: 0800 1c00                              |01a7: move-object/from16 v0, v28
+003716: 5202 1e00                              |01a9: iget v2, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+00371a: 1203                                   |01ab: const/4 v3, #int 0 // #0
+00371c: 2e02 0203                              |01ac: cmpg-float v2, v2, v3
+003720: 3c02 1100                              |01ae: if-gtz v2, 01bf // +0011
+003724: 1202                                   |01b0: const/4 v2, #int 0 // #0
+003726: 0800 1c00                              |01b1: move-object/from16 v0, v28
+00372a: 5902 1e00                              |01b3: iput v2, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+00372e: 1202                                   |01b5: const/4 v2, #int 0 // #0
+003730: 0800 1c00                              |01b6: move-object/from16 v0, v28
+003734: 5902 1f00                              |01b8: iput v2, v0, Lcom/google/android/checkers/CheckersView;.m:I // field@001f
+003738: 1202                                   |01ba: const/4 v2, #int 0 // #0
+00373a: 0800 1c00                              |01bb: move-object/from16 v0, v28
+00373e: 5902 2000                              |01bd: iput v2, v0, Lcom/google/android/checkers/CheckersView;.n:I // field@0020
+003742: 1602 3200                              |01bf: const-wide/16 v2, #int 50 // #32
+003746: 0800 1c00                              |01c1: move-object/from16 v0, v28
+00374a: 6e30 6e00 2003                         |01c3: invoke-virtual {v0, v2, v3}, Lcom/google/android/checkers/CheckersView;.postInvalidateDelayed:(J)V // method@006e
+003750: 1e1c                                   |01c6: monitor-exit v28
+003752: 0e00                                   |01c7: return-void
+003754: 0142                                   |01c8: move v2, v4
+003756: 2900 46fe                              |01c9: goto/16 000f // -01ba
+00375a: d803 1702                              |01cb: add-int/lit8 v3, v23, #int 2 // #02
+00375e: da02 1402                              |01cd: mul-int/lit8 v2, v20, #int 2 // #02
+003762: 9102 1702                              |01cf: sub-int v2, v23, v2
+003766: 9102 0219                              |01d1: sub-int v2, v2, v25
+00376a: 0211 0200                              |01d3: move/from16 v17, v2
+00376e: 0212 0300                              |01d5: move/from16 v18, v3
+003772: 0213 1400                              |01d7: move/from16 v19, v20
+003776: 0215 0300                              |01d9: move/from16 v21, v3
+00377a: 2900 53fe                              |01db: goto/16 002e // -01ad
+00377e: 0800 1c00                              |01dd: move-object/from16 v0, v28
+003782: 5408 1500                              |01df: iget-object v8, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003786: 1203                                   |01e1: const/4 v3, #int 0 // #0
+003788: 1204                                   |01e2: const/4 v4, #int 0 // #0
+00378a: 0200 1700                              |01e3: move/from16 v0, v23
+00378e: 8205                                   |01e5: int-to-float v5, v0
+003790: 0200 1700                              |01e6: move/from16 v0, v23
+003794: 8206                                   |01e8: int-to-float v6, v0
+003796: 0800 1c00                              |01e9: move-object/from16 v0, v28
+00379a: 5407 1700                              |01eb: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.e:Landroid/graphics/Paint; // field@0017
+00379e: 0802 1d00                              |01ed: move-object/from16 v2, v29
+0037a2: 7406 1f00 0200                         |01ef: invoke-virtual/range {v2, v3, v4, v5, v6, v7}, Landroid/graphics/Canvas;.drawRect:(FFFFLandroid/graphics/Paint;)V // method@001f
+0037a8: 0787                                   |01f2: move-object v7, v8
+0037aa: 2900 64fe                              |01f3: goto/16 0057 // -019c
+0037ae: 920a 1609                              |01f5: mul-int v10, v22, v9
+0037b2: dd02 0901                              |01f7: and-int/lit8 v2, v9, #int 1 // #01
+0037b6: 0128                                   |01f9: move v8, v2
+0037b8: 1302 0800                              |01fa: const/16 v2, #int 8 // #8
+0037bc: 3428 0700                              |01fc: if-lt v8, v2, 0203 // +0007
+0037c0: d802 0901                              |01fe: add-int/lit8 v2, v9, #int 1 // #01
+0037c4: 0129                                   |0200: move v9, v2
+0037c6: 2900 58fe                              |0201: goto/16 0059 // -01a8
+0037ca: 9202 1608                              |0203: mul-int v2, v22, v8
+0037ce: 82a3                                   |0205: int-to-float v3, v10
+0037d0: 8224                                   |0206: int-to-float v4, v2
+0037d2: 9005 0a16                              |0207: add-int v5, v10, v22
+0037d6: 8255                                   |0209: int-to-float v5, v5
+0037d8: 9002 0216                              |020a: add-int v2, v2, v22
+0037dc: 8226                                   |020c: int-to-float v6, v2
+0037de: 0802 1d00                              |020d: move-object/from16 v2, v29
+0037e2: 7406 1f00 0200                         |020f: invoke-virtual/range {v2, v3, v4, v5, v6, v7}, Landroid/graphics/Canvas;.drawRect:(FFFFLandroid/graphics/Paint;)V // method@001f
+0037e8: d802 0802                              |0212: add-int/lit8 v2, v8, #int 2 // #02
+0037ec: 0128                                   |0214: move v8, v2
+0037ee: 28e5                                   |0215: goto 01fa // -001b
+0037f0: d902 1001                              |0216: rsub-int/lit8 v2, v16, #int 1 // #01
+0037f4: dd02 0201                              |0218: and-int/lit8 v2, v2, #int 1 // #01
+0037f8: 012e                                   |021a: move v14, v2
+0037fa: 013f                                   |021b: move v15, v3
+0037fc: 1302 0800                              |021c: const/16 v2, #int 8 // #8
+003800: 342e 0900                              |021e: if-lt v14, v2, 0227 // +0009
+003804: d802 1001                              |0220: add-int/lit8 v2, v16, #int 1 // #01
+003808: 0210 0200                              |0222: move/from16 v16, v2
+00380c: 01f3                                   |0224: move v3, v15
+00380e: 2900 40fe                              |0225: goto/16 0065 // -01c0
+003812: 0800 1c00                              |0227: move-object/from16 v0, v28
+003816: 5502 0400                              |0229: iget-boolean v2, v0, Lcom/google/android/checkers/CheckersView;.C:Z // field@0004
+00381a: 3802 5d00                              |022b: if-eqz v2, 0288 // +005d
+00381e: d902 0e07                              |022d: rsub-int/lit8 v2, v14, #int 7 // #07
+003822: 9203 1602                              |022f: mul-int v3, v22, v2
+003826: d902 1007                              |0231: rsub-int/lit8 v2, v16, #int 7 // #07
+00382a: 9202 0216                              |0233: mul-int v2, v2, v22
+00382e: 0135                                   |0235: move v5, v3
+003830: 901a 1805                              |0236: add-int v26, v24, v5
+003834: 901b 1802                              |0238: add-int v27, v24, v2
+003838: 0800 1c00                              |023a: move-object/from16 v0, v28
+00383c: 5203 2800                              |023c: iget v3, v0, Lcom/google/android/checkers/CheckersView;.v:I // field@0028
+003840: b5f3                                   |023e: and-int/2addr v3, v15
+003842: 3803 4f00                              |023f: if-eqz v3, 028e // +004f
+003846: d803 0501                              |0241: add-int/lit8 v3, v5, #int 1 // #01
+00384a: 8233                                   |0243: int-to-float v3, v3
+00384c: d804 0201                              |0244: add-int/lit8 v4, v2, #int 1 // #01
+003850: 8244                                   |0246: int-to-float v4, v4
+003852: 9005 0516                              |0247: add-int v5, v5, v22
+003856: d805 05ff                              |0249: add-int/lit8 v5, v5, #int -1 // #ff
+00385a: 8255                                   |024b: int-to-float v5, v5
+00385c: 9002 0216                              |024c: add-int v2, v2, v22
+003860: d802 02ff                              |024e: add-int/lit8 v2, v2, #int -1 // #ff
+003864: 8226                                   |0250: int-to-float v6, v2
+003866: 0800 1c00                              |0251: move-object/from16 v0, v28
+00386a: 5407 1800                              |0253: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.f:Landroid/graphics/Paint; // field@0018
+00386e: 0802 1d00                              |0255: move-object/from16 v2, v29
+003872: 7406 1f00 0200                         |0257: invoke-virtual/range {v2, v3, v4, v5, v6, v7}, Landroid/graphics/Canvas;.drawRect:(FFFFLandroid/graphics/Paint;)V // method@001f
+003878: 0800 1c00                              |025a: move-object/from16 v0, v28
+00387c: 5202 2400                              |025c: iget v2, v0, Lcom/google/android/checkers/CheckersView;.r:I // field@0024
+003880: b5f2                                   |025e: and-int/2addr v2, v15
+003882: 3802 7a00                              |025f: if-eqz v2, 02d9 // +007a
+003886: 0800 1c00                              |0261: move-object/from16 v0, v28
+00388a: 5407 1400                              |0263: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+00388e: 0800 1c00                              |0265: move-object/from16 v0, v28
+003892: 5408 1500                              |0267: iget-object v8, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003896: 1209                                   |0269: const/4 v9, #int 0 // #0
+003898: 0802 1d00                              |026a: move-object/from16 v2, v29
+00389c: 0203 1a00                              |026c: move/from16 v3, v26
+0038a0: 0204 1b00                              |026e: move/from16 v4, v27
+0038a4: 0205 1800                              |0270: move/from16 v5, v24
+0038a8: 0206 1900                              |0272: move/from16 v6, v25
+0038ac: 7708 5500 0200                         |0274: invoke-static/range {v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V // method@0055
+0038b2: d802 0d01                              |0277: add-int/lit8 v2, v13, #int 1 // #01
+0038b6: 01b3                                   |0279: move v3, v11
+0038b8: 01c4                                   |027a: move v4, v12
+0038ba: 0125                                   |027b: move v5, v2
+0038bc: 01a2                                   |027c: move v2, v10
+0038be: e007 0f01                              |027d: shl-int/lit8 v7, v15, #int 1 // #01
+0038c2: d806 0e02                              |027f: add-int/lit8 v6, v14, #int 2 // #02
+0038c6: 016e                                   |0281: move v14, v6
+0038c8: 012a                                   |0282: move v10, v2
+0038ca: 013b                                   |0283: move v11, v3
+0038cc: 014c                                   |0284: move v12, v4
+0038ce: 015d                                   |0285: move v13, v5
+0038d0: 017f                                   |0286: move v15, v7
+0038d2: 2895                                   |0287: goto 021c // -006b
+0038d4: 9203 160e                              |0288: mul-int v3, v22, v14
+0038d8: 9202 1610                              |028a: mul-int v2, v22, v16
+0038dc: 0135                                   |028c: move v5, v3
+0038de: 28a9                                   |028d: goto 0236 // -0057
+0038e0: 0800 1c00                              |028e: move-object/from16 v0, v28
+0038e4: 5203 2900                              |0290: iget v3, v0, Lcom/google/android/checkers/CheckersView;.w:I // field@0029
+0038e8: b5f3                                   |0292: and-int/2addr v3, v15
+0038ea: 3803 1f00                              |0293: if-eqz v3, 02b2 // +001f
+0038ee: d803 0501                              |0295: add-int/lit8 v3, v5, #int 1 // #01
+0038f2: 8233                                   |0297: int-to-float v3, v3
+0038f4: d804 0201                              |0298: add-int/lit8 v4, v2, #int 1 // #01
+0038f8: 8244                                   |029a: int-to-float v4, v4
+0038fa: 9005 0516                              |029b: add-int v5, v5, v22
+0038fe: d805 05ff                              |029d: add-int/lit8 v5, v5, #int -1 // #ff
+003902: 8255                                   |029f: int-to-float v5, v5
+003904: 9002 0216                              |02a0: add-int v2, v2, v22
+003908: d802 02ff                              |02a2: add-int/lit8 v2, v2, #int -1 // #ff
+00390c: 8226                                   |02a4: int-to-float v6, v2
+00390e: 0800 1c00                              |02a5: move-object/from16 v0, v28
+003912: 5407 1900                              |02a7: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.g:Landroid/graphics/Paint; // field@0019
+003916: 0802 1d00                              |02a9: move-object/from16 v2, v29
+00391a: 7406 1f00 0200                         |02ab: invoke-virtual/range {v2, v3, v4, v5, v6, v7}, Landroid/graphics/Canvas;.drawRect:(FFFFLandroid/graphics/Paint;)V // method@001f
+003920: 28ac                                   |02ae: goto 025a // -0054
+003922: 0d02                                   |02af: move-exception v2
+003924: 1e1c                                   |02b0: monitor-exit v28
+003926: 2702                                   |02b1: throw v2
+003928: 0800 1c00                              |02b2: move-object/from16 v0, v28
+00392c: 5503 0200                              |02b4: iget-boolean v3, v0, Lcom/google/android/checkers/CheckersView;.A:Z // field@0002
+003930: 3803 a4ff                              |02b6: if-eqz v3, 025a // -005c
+003934: 0800 1c00                              |02b8: move-object/from16 v0, v28
+003938: 5203 2a00                              |02ba: iget v3, v0, Lcom/google/android/checkers/CheckersView;.x:I // field@002a
+00393c: b5f3                                   |02bc: and-int/2addr v3, v15
+00393e: 3803 9dff                              |02bd: if-eqz v3, 025a // -0063
+003942: d803 0501                              |02bf: add-int/lit8 v3, v5, #int 1 // #01
+003946: 8233                                   |02c1: int-to-float v3, v3
+003948: d804 0201                              |02c2: add-int/lit8 v4, v2, #int 1 // #01
+00394c: 8244                                   |02c4: int-to-float v4, v4
+00394e: 9005 0516                              |02c5: add-int v5, v5, v22
+003952: d805 05ff                              |02c7: add-int/lit8 v5, v5, #int -1 // #ff
+003956: 8255                                   |02c9: int-to-float v5, v5
+003958: 9002 0216                              |02ca: add-int v2, v2, v22
+00395c: d802 02ff                              |02cc: add-int/lit8 v2, v2, #int -1 // #ff
+003960: 8226                                   |02ce: int-to-float v6, v2
+003962: 0800 1c00                              |02cf: move-object/from16 v0, v28
+003966: 5407 1b00                              |02d1: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.i:Landroid/graphics/Paint; // field@001b
+00396a: 0802 1d00                              |02d3: move-object/from16 v2, v29
+00396e: 7406 1f00 0200                         |02d5: invoke-virtual/range {v2, v3, v4, v5, v6, v7}, Landroid/graphics/Canvas;.drawRect:(FFFFLandroid/graphics/Paint;)V // method@001f
+003974: 2882                                   |02d8: goto 025a // -007e
+003976: 0800 1c00                              |02d9: move-object/from16 v0, v28
+00397a: 5202 2500                              |02db: iget v2, v0, Lcom/google/android/checkers/CheckersView;.s:I // field@0025
+00397e: b5f2                                   |02dd: and-int/2addr v2, v15
+003980: 3802 1f00                              |02de: if-eqz v2, 02fd // +001f
+003984: 0800 1c00                              |02e0: move-object/from16 v0, v28
+003988: 5407 1500                              |02e2: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+00398c: 0800 1c00                              |02e4: move-object/from16 v0, v28
+003990: 5408 1400                              |02e6: iget-object v8, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+003994: 1209                                   |02e8: const/4 v9, #int 0 // #0
+003996: 0802 1d00                              |02e9: move-object/from16 v2, v29
+00399a: 0203 1a00                              |02eb: move/from16 v3, v26
+00399e: 0204 1b00                              |02ed: move/from16 v4, v27
+0039a2: 0205 1800                              |02ef: move/from16 v5, v24
+0039a6: 0206 1900                              |02f1: move/from16 v6, v25
+0039aa: 7708 5500 0200                         |02f3: invoke-static/range {v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V // method@0055
+0039b0: d802 0b01                              |02f6: add-int/lit8 v2, v11, #int 1 // #01
+0039b4: 0123                                   |02f8: move v3, v2
+0039b6: 01c4                                   |02f9: move v4, v12
+0039b8: 01d5                                   |02fa: move v5, v13
+0039ba: 01a2                                   |02fb: move v2, v10
+0039bc: 2881                                   |02fc: goto 027d // -007f
+0039be: 0800 1c00                              |02fd: move-object/from16 v0, v28
+0039c2: 5202 2600                              |02ff: iget v2, v0, Lcom/google/android/checkers/CheckersView;.t:I // field@0026
+0039c6: b5f2                                   |0301: and-int/2addr v2, v15
+0039c8: 3802 2000                              |0302: if-eqz v2, 0322 // +0020
+0039cc: 0800 1c00                              |0304: move-object/from16 v0, v28
+0039d0: 5407 1400                              |0306: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+0039d4: 0800 1c00                              |0308: move-object/from16 v0, v28
+0039d8: 5408 1500                              |030a: iget-object v8, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+0039dc: 1219                                   |030c: const/4 v9, #int 1 // #1
+0039de: 0802 1d00                              |030d: move-object/from16 v2, v29
+0039e2: 0203 1a00                              |030f: move/from16 v3, v26
+0039e6: 0204 1b00                              |0311: move/from16 v4, v27
+0039ea: 0205 1800                              |0313: move/from16 v5, v24
+0039ee: 0206 1900                              |0315: move/from16 v6, v25
+0039f2: 7708 5500 0200                         |0317: invoke-static/range {v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V // method@0055
+0039f8: d802 0c01                              |031a: add-int/lit8 v2, v12, #int 1 // #01
+0039fc: 01b3                                   |031c: move v3, v11
+0039fe: 0124                                   |031d: move v4, v2
+003a00: 01d5                                   |031e: move v5, v13
+003a02: 01a2                                   |031f: move v2, v10
+003a04: 2900 5dff                              |0320: goto/16 027d // -00a3
+003a08: 0800 1c00                              |0322: move-object/from16 v0, v28
+003a0c: 5202 2700                              |0324: iget v2, v0, Lcom/google/android/checkers/CheckersView;.u:I // field@0027
+003a10: b5f2                                   |0326: and-int/2addr v2, v15
+003a12: 3802 1f00                              |0327: if-eqz v2, 0346 // +001f
+003a16: 0800 1c00                              |0329: move-object/from16 v0, v28
+003a1a: 5407 1500                              |032b: iget-object v7, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003a1e: 0800 1c00                              |032d: move-object/from16 v0, v28
+003a22: 5408 1400                              |032f: iget-object v8, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+003a26: 1219                                   |0331: const/4 v9, #int 1 // #1
+003a28: 0802 1d00                              |0332: move-object/from16 v2, v29
+003a2c: 0203 1a00                              |0334: move/from16 v3, v26
+003a30: 0204 1b00                              |0336: move/from16 v4, v27
+003a34: 0205 1800                              |0338: move/from16 v5, v24
+003a38: 0206 1900                              |033a: move/from16 v6, v25
+003a3c: 7708 5500 0200                         |033c: invoke-static/range {v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/CheckersView;.a:(Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V // method@0055
+003a42: d802 0a01                              |033f: add-int/lit8 v2, v10, #int 1 // #01
+003a46: 01b3                                   |0341: move v3, v11
+003a48: 01c4                                   |0342: move v4, v12
+003a4a: 01d5                                   |0343: move v5, v13
+003a4c: 2900 39ff                              |0344: goto/16 027d // -00c7
+003a50: 0800 1c00                              |0346: move-object/from16 v0, v28
+003a54: 5202 2000                              |0348: iget v2, v0, Lcom/google/android/checkers/CheckersView;.n:I // field@0020
+003a58: b5f2                                   |034a: and-int/2addr v2, v15
+003a5a: 3802 3600                              |034b: if-eqz v2, 0381 // +0036
+003a5e: 0200 1a00                              |034d: move/from16 v0, v26
+003a62: 8202                                   |034f: int-to-float v2, v0
+003a64: 0200 1b00                              |0350: move/from16 v0, v27
+003a68: 8203                                   |0352: int-to-float v3, v0
+003a6a: d804 18fe                              |0353: add-int/lit8 v4, v24, #int -2 // #fe
+003a6e: 8244                                   |0355: int-to-float v4, v4
+003a70: 0800 1c00                              |0356: move-object/from16 v0, v28
+003a74: 5205 1e00                              |0358: iget v5, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+003a78: c854                                   |035a: mul-float/2addr v4, v5
+003a7a: 0800 1c00                              |035b: move-object/from16 v0, v28
+003a7e: 5405 1500                              |035d: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003a82: 0800 1d00                              |035f: move-object/from16 v0, v29
+003a86: 6e55 1c00 2043                         |0361: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+003a8c: 0200 1a00                              |0364: move/from16 v0, v26
+003a90: 8202                                   |0366: int-to-float v2, v0
+003a92: 0200 1b00                              |0367: move/from16 v0, v27
+003a96: 8203                                   |0369: int-to-float v3, v0
+003a98: d804 18fc                              |036a: add-int/lit8 v4, v24, #int -4 // #fc
+003a9c: 8244                                   |036c: int-to-float v4, v4
+003a9e: 0800 1c00                              |036d: move-object/from16 v0, v28
+003aa2: 5205 1e00                              |036f: iget v5, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+003aa6: c854                                   |0371: mul-float/2addr v4, v5
+003aa8: 0800 1c00                              |0372: move-object/from16 v0, v28
+003aac: 5405 1400                              |0374: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+003ab0: 0800 1d00                              |0376: move-object/from16 v0, v29
+003ab4: 6e55 1c00 2043                         |0378: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+003aba: 01a2                                   |037b: move v2, v10
+003abc: 01b3                                   |037c: move v3, v11
+003abe: 01c4                                   |037d: move v4, v12
+003ac0: 01d5                                   |037e: move v5, v13
+003ac2: 2900 fefe                              |037f: goto/16 027d // -0102
+003ac6: 0800 1c00                              |0381: move-object/from16 v0, v28
+003aca: 5202 1f00                              |0383: iget v2, v0, Lcom/google/android/checkers/CheckersView;.m:I // field@001f
+003ace: b5f2                                   |0385: and-int/2addr v2, v15
+003ad0: 3802 3000                              |0386: if-eqz v2, 03b6 // +0030
+003ad4: 0200 1a00                              |0388: move/from16 v0, v26
+003ad8: 8202                                   |038a: int-to-float v2, v0
+003ada: 0200 1b00                              |038b: move/from16 v0, v27
+003ade: 8203                                   |038d: int-to-float v3, v0
+003ae0: d804 18fe                              |038e: add-int/lit8 v4, v24, #int -2 // #fe
+003ae4: 8244                                   |0390: int-to-float v4, v4
+003ae6: 0800 1c00                              |0391: move-object/from16 v0, v28
+003aea: 5205 1e00                              |0393: iget v5, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+003aee: c854                                   |0395: mul-float/2addr v4, v5
+003af0: 0800 1c00                              |0396: move-object/from16 v0, v28
+003af4: 5405 1400                              |0398: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+003af8: 0800 1d00                              |039a: move-object/from16 v0, v29
+003afc: 6e55 1c00 2043                         |039c: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+003b02: 0200 1a00                              |039f: move/from16 v0, v26
+003b06: 8202                                   |03a1: int-to-float v2, v0
+003b08: 0200 1b00                              |03a2: move/from16 v0, v27
+003b0c: 8203                                   |03a4: int-to-float v3, v0
+003b0e: d804 18fc                              |03a5: add-int/lit8 v4, v24, #int -4 // #fc
+003b12: 8244                                   |03a7: int-to-float v4, v4
+003b14: 0800 1c00                              |03a8: move-object/from16 v0, v28
+003b18: 5205 1e00                              |03aa: iget v5, v0, Lcom/google/android/checkers/CheckersView;.l:F // field@001e
+003b1c: c854                                   |03ac: mul-float/2addr v4, v5
+003b1e: 0800 1c00                              |03ad: move-object/from16 v0, v28
+003b22: 5405 1500                              |03af: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003b26: 0800 1d00                              |03b1: move-object/from16 v0, v29
+003b2a: 6e55 1c00 2043                         |03b3: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawCircle:(FFFLandroid/graphics/Paint;)V // method@001c
+003b30: 01a2                                   |03b6: move v2, v10
+003b32: 01b3                                   |03b7: move v3, v11
+003b34: 01c4                                   |03b8: move v4, v12
+003b36: 01d5                                   |03b9: move v5, v13
+003b38: 2900 c3fe                              |03ba: goto/16 027d // -013d
+003b3c: 1a02 9c00                              |03bc: const-string v2, "White" // string@009c
+003b40: 0200 1500                              |03be: move/from16 v0, v21
+003b44: 8203                                   |03c0: int-to-float v3, v0
+003b46: 0200 1300                              |03c1: move/from16 v0, v19
+003b4a: 8204                                   |03c3: int-to-float v4, v0
+003b4c: 0800 1c00                              |03c4: move-object/from16 v0, v28
+003b50: 5405 1500                              |03c6: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003b54: 0800 1d00                              |03c8: move-object/from16 v0, v29
+003b58: 6e55 2000 2043                         |03ca: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003b5e: 1a02 0b00                              |03cd: const-string v2, "Black" // string@000b
+003b62: 0200 1500                              |03cf: move/from16 v0, v21
+003b66: 8203                                   |03d1: int-to-float v3, v0
+003b68: 9004 1314                              |03d2: add-int v4, v19, v20
+003b6c: 8244                                   |03d4: int-to-float v4, v4
+003b6e: 0800 1c00                              |03d5: move-object/from16 v0, v28
+003b72: 5405 1500                              |03d7: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003b76: 0800 1d00                              |03d9: move-object/from16 v0, v29
+003b7a: 6e55 2000 2043                         |03db: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003b80: 1a02 7200                              |03de: const-string v2, "Moves" // string@0072
+003b84: 0200 1500                              |03e0: move/from16 v0, v21
+003b88: 8203                                   |03e2: int-to-float v3, v0
+003b8a: da04 1402                              |03e3: mul-int/lit8 v4, v20, #int 2 // #02
+003b8e: 9004 0413                              |03e5: add-int v4, v4, v19
+003b92: 8244                                   |03e7: int-to-float v4, v4
+003b94: 0800 1c00                              |03e8: move-object/from16 v0, v28
+003b98: 5405 1500                              |03ea: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003b9c: 0800 1d00                              |03ec: move-object/from16 v0, v29
+003ba0: 6e55 2000 2043                         |03ee: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003ba6: 2202 3000                              |03f1: new-instance v2, Ljava/lang/StringBuilder; // type@0030
+003baa: 1a03 0300                              |03f3: const-string v3, ":  " // string@0003
+003bae: 7020 a600 3200                         |03f5: invoke-direct {v2, v3}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+003bb4: 6e20 a700 d200                         |03f8: invoke-virtual {v2, v13}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+003bba: 0c02                                   |03fb: move-result-object v2
+003bbc: 1a03 0200                              |03fc: const-string v3, "+" // string@0002
+003bc0: 6e20 a900 3200                         |03fe: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00a9
+003bc6: 0c02                                   |0401: move-result-object v2
+003bc8: 6e20 a700 c200                         |0402: invoke-virtual {v2, v12}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+003bce: 0c02                                   |0405: move-result-object v2
+003bd0: 6e10 aa00 0200                         |0406: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+003bd6: 0c02                                   |0409: move-result-object v2
+003bd8: da03 1403                              |040a: mul-int/lit8 v3, v20, #int 3 // #03
+003bdc: 9003 0315                              |040c: add-int v3, v3, v21
+003be0: 8233                                   |040e: int-to-float v3, v3
+003be2: 0200 1300                              |040f: move/from16 v0, v19
+003be6: 8204                                   |0411: int-to-float v4, v0
+003be8: 0800 1c00                              |0412: move-object/from16 v0, v28
+003bec: 5405 1500                              |0414: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003bf0: 0800 1d00                              |0416: move-object/from16 v0, v29
+003bf4: 6e55 2000 2043                         |0418: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003bfa: 2202 3000                              |041b: new-instance v2, Ljava/lang/StringBuilder; // type@0030
+003bfe: 1a03 0300                              |041d: const-string v3, ":  " // string@0003
+003c02: 7020 a600 3200                         |041f: invoke-direct {v2, v3}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+003c08: 6e20 a700 b200                         |0422: invoke-virtual {v2, v11}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+003c0e: 0c02                                   |0425: move-result-object v2
+003c10: 1a03 0200                              |0426: const-string v3, "+" // string@0002
+003c14: 6e20 a900 3200                         |0428: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@00a9
+003c1a: 0c02                                   |042b: move-result-object v2
+003c1c: 6e20 a700 a200                         |042c: invoke-virtual {v2, v10}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+003c22: 0c02                                   |042f: move-result-object v2
+003c24: 6e10 aa00 0200                         |0430: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+003c2a: 0c02                                   |0433: move-result-object v2
+003c2c: da03 1403                              |0434: mul-int/lit8 v3, v20, #int 3 // #03
+003c30: 9003 0315                              |0436: add-int v3, v3, v21
+003c34: 8233                                   |0438: int-to-float v3, v3
+003c36: 9004 1314                              |0439: add-int v4, v19, v20
+003c3a: 8244                                   |043b: int-to-float v4, v4
+003c3c: 0800 1c00                              |043c: move-object/from16 v0, v28
+003c40: 5405 1500                              |043e: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003c44: 0800 1d00                              |0440: move-object/from16 v0, v29
+003c48: 6e55 2000 2043                         |0442: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003c4e: 2202 3000                              |0445: new-instance v2, Ljava/lang/StringBuilder; // type@0030
+003c52: 1a03 0300                              |0447: const-string v3, ":  " // string@0003
+003c56: 7020 a600 3200                         |0449: invoke-direct {v2, v3}, Ljava/lang/StringBuilder;.<init>:(Ljava/lang/String;)V // method@00a6
+003c5c: 0800 1c00                              |044c: move-object/from16 v0, v28
+003c60: 5203 0e00                              |044e: iget v3, v0, Lcom/google/android/checkers/CheckersView;.M:I // field@000e
+003c64: 6e20 a700 3200                         |0450: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@00a7
+003c6a: 0c02                                   |0453: move-result-object v2
+003c6c: 6e10 aa00 0200                         |0454: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@00aa
+003c72: 0c02                                   |0457: move-result-object v2
+003c74: da03 1403                              |0458: mul-int/lit8 v3, v20, #int 3 // #03
+003c78: 9003 0315                              |045a: add-int v3, v3, v21
+003c7c: 8233                                   |045c: int-to-float v3, v3
+003c7e: da04 1402                              |045d: mul-int/lit8 v4, v20, #int 2 // #02
+003c82: 9004 0413                              |045f: add-int v4, v4, v19
+003c86: 8244                                   |0461: int-to-float v4, v4
+003c88: 0800 1c00                              |0462: move-object/from16 v0, v28
+003c8c: 5405 1500                              |0464: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003c90: 0800 1d00                              |0466: move-object/from16 v0, v29
+003c94: 6e55 2000 2043                         |0468: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003c9a: 2900 3ffc                              |046b: goto/16 00aa // -03c1
+003c9e: 1a02 0a00                              |046d: const-string v2, "BLACK'S MOVE?" // string@000a
+003ca2: 0200 1200                              |046f: move/from16 v0, v18
+003ca6: 8203                                   |0471: int-to-float v3, v0
+003ca8: 9004 1114                              |0472: add-int v4, v17, v20
+003cac: 8244                                   |0474: int-to-float v4, v4
+003cae: 0800 1c00                              |0475: move-object/from16 v0, v28
+003cb2: 5405 1500                              |0477: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003cb6: 0800 1d00                              |0479: move-object/from16 v0, v29
+003cba: 6e55 2000 2043                         |047b: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003cc0: 2900 4afc                              |047e: goto/16 00c8 // -03b6
+003cc4: 1a02 9a00                              |0480: const-string v2, "WHITE'S MOVE?" // string@009a
+003cc8: 0200 1200                              |0482: move/from16 v0, v18
+003ccc: 8203                                   |0484: int-to-float v3, v0
+003cce: 9004 1114                              |0485: add-int v4, v17, v20
+003cd2: 8244                                   |0487: int-to-float v4, v4
+003cd4: 0800 1c00                              |0488: move-object/from16 v0, v28
+003cd8: 5405 1500                              |048a: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003cdc: 0800 1d00                              |048c: move-object/from16 v0, v29
+003ce0: 6e55 2000 2043                         |048e: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003ce6: 2900 37fc                              |0491: goto/16 00c8 // -03c9
+003cea: 1a02 8100                              |0493: const-string v2, "THINKING...." // string@0081
+003cee: 0200 1200                              |0495: move/from16 v0, v18
+003cf2: 8203                                   |0497: int-to-float v3, v0
+003cf4: 9004 1114                              |0498: add-int v4, v17, v20
+003cf8: 8244                                   |049a: int-to-float v4, v4
+003cfa: 0800 1c00                              |049b: move-object/from16 v0, v28
+003cfe: 5405 1500                              |049d: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003d02: 0800 1d00                              |049f: move-object/from16 v0, v29
+003d06: 6e55 2000 2043                         |04a1: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003d0c: 2900 24fc                              |04a4: goto/16 00c8 // -03dc
+003d10: 1a02 9900                              |04a6: const-string v2, "WHITE WINS" // string@0099
+003d14: 0200 1200                              |04a8: move/from16 v0, v18
+003d18: 8203                                   |04aa: int-to-float v3, v0
+003d1a: 9004 1114                              |04ab: add-int v4, v17, v20
+003d1e: 8244                                   |04ad: int-to-float v4, v4
+003d20: 0800 1c00                              |04ae: move-object/from16 v0, v28
+003d24: 5405 1500                              |04b0: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003d28: 0800 1d00                              |04b2: move-object/from16 v0, v29
+003d2c: 6e55 2000 2043                         |04b4: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003d32: 2900 11fc                              |04b7: goto/16 00c8 // -03ef
+003d36: 1a02 0900                              |04b9: const-string v2, "BLACK WINS" // string@0009
+003d3a: 0200 1200                              |04bb: move/from16 v0, v18
+003d3e: 8203                                   |04bd: int-to-float v3, v0
+003d40: 9004 1114                              |04be: add-int v4, v17, v20
+003d44: 8244                                   |04c0: int-to-float v4, v4
+003d46: 0800 1c00                              |04c1: move-object/from16 v0, v28
+003d4a: 5405 1500                              |04c3: iget-object v5, v0, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003d4e: 0800 1d00                              |04c5: move-object/from16 v0, v29
+003d52: 6e55 2000 2043                         |04c7: invoke-virtual {v0, v2, v3, v4, v5}, Landroid/graphics/Canvas;.drawText:(Ljava/lang/String;FFLandroid/graphics/Paint;)V // method@0020
+003d58: 2900 fefb                              |04ca: goto/16 00c8 // -0402
+003d5c: 4404 0a08                              |04cc: aget v4, v10, v8
+003d60: 4405 0b08                              |04ce: aget v5, v11, v8
+003d64: 0802 1c00                              |04d0: move-object/from16 v2, v28
+003d68: 0803 1d00                              |04d2: move-object/from16 v3, v29
+003d6c: 0206 1600                              |04d4: move/from16 v6, v22
+003d70: 0207 1800                              |04d6: move/from16 v7, v24
+003d74: 7606 5f00 0200                         |04d8: invoke-direct/range {v2, v3, v4, v5, v6, v7}, Lcom/google/android/checkers/CheckersView;.b:(Landroid/graphics/Canvas;IIII)V // method@005f
+003d7a: d802 0801                              |04db: add-int/lit8 v2, v8, #int 1 // #01
+003d7e: 0128                                   |04dd: move v8, v2
+003d80: 2900 12fc                              |04de: goto/16 00f0 // -03ee
+003d84: 0001 0600 0100 0000 a803 0000 ce03 ... |04e0: packed-switch-data (16 units)
+      catches       : 3
+        0x0001 - 0x01c6
+          <any> -> 0x02af
+        0x01dd - 0x02ae
+          <any> -> 0x02af
+        0x02b2 - 0x04db
+          <any> -> 0x02af
+      positions     : 
+      locals        : 
+
+    #12              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'e'
+      type          : '(Z)Z'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 3
+      ins           : 2
+      outs          : 0
+      insns size    : 19 16-bit code units
+003dc0:                                        |[003dc0] com.google.android.checkers.CheckersView.e:(Z)Z
+003dd0: 1d01                                   |0000: monitor-enter v1
+003dd2: 3802 0900                              |0001: if-eqz v2, 000a // +0009
+003dd6: 5510 0600                              |0003: iget-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+003dda: 3800 0900                              |0005: if-eqz v0, 000e // +0009
+003dde: 1200                                   |0007: const/4 v0, #int 0 // #0
+003de0: 5c10 0600                              |0008: iput-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+003de4: 5510 0600                              |000a: iget-boolean v0, v1, Lcom/google/android/checkers/CheckersView;.E:Z // field@0006
+003de8: 1e01                                   |000c: monitor-exit v1
+003dea: 0f00                                   |000d: return v0
+003dec: 1210                                   |000e: const/4 v0, #int 1 // #1
+003dee: 28f9                                   |000f: goto 0008 // -0007
+003df0: 0d00                                   |0010: move-exception v0
+003df2: 1e01                                   |0011: monitor-exit v1
+003df4: 2700                                   |0012: throw v0
+      catches       : 1
+        0x0003 - 0x000c
+          <any> -> 0x0010
+      positions     : 
+      locals        : 
+
+    #13              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'onSizeChanged'
+      type          : '(IIII)V'
+      access        : 0x20004 (PROTECTED DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 8
+      ins           : 5
+      outs          : 2
+      insns size    : 52 16-bit code units
+003e04:                                        |[003e04] com.google.android.checkers.CheckersView.onSizeChanged:(IIII)V
+003e14: 1d03                                   |0000: monitor-enter v3
+003e16: 3554 2c00                              |0001: if-ge v4, v5, 002d // +002c
+003e1a: 0140                                   |0003: move v0, v4
+003e1c: db01 0018                              |0004: div-int/lit8 v1, v0, #int 24 // #18
+003e20: 8211                                   |0006: int-to-float v1, v1
+003e22: 3754 2b00                              |0007: if-le v4, v5, 0032 // +002b
+003e26: 9100 0400                              |0009: sub-int v0, v4, v0
+003e2a: db00 000a                              |000b: div-int/lit8 v0, v0, #int 10 // #0a
+003e2e: 8200                                   |000d: int-to-float v0, v0
+003e30: 2e02 0001                              |000e: cmpg-float v2, v0, v1
+003e34: 3b02 2200                              |0010: if-gez v2, 0032 // +0022
+003e38: 5431 1400                              |0012: iget-object v1, v3, Lcom/google/android/checkers/CheckersView;.b:Landroid/graphics/Paint; // field@0014
+003e3c: 6e20 2600 0100                         |0014: invoke-virtual {v1, v0}, Landroid/graphics/Paint;.setTextSize:(F)V // method@0026
+003e42: 5431 1500                              |0017: iget-object v1, v3, Lcom/google/android/checkers/CheckersView;.c:Landroid/graphics/Paint; // field@0015
+003e46: 6e20 2600 0100                         |0019: invoke-virtual {v1, v0}, Landroid/graphics/Paint;.setTextSize:(F)V // method@0026
+003e4c: 5431 1b00                              |001c: iget-object v1, v3, Lcom/google/android/checkers/CheckersView;.i:Landroid/graphics/Paint; // field@001b
+003e50: 6e20 2600 0100                         |001e: invoke-virtual {v1, v0}, Landroid/graphics/Paint;.setTextSize:(F)V // method@0026
+003e56: 5431 1800                              |0021: iget-object v1, v3, Lcom/google/android/checkers/CheckersView;.f:Landroid/graphics/Paint; // field@0018
+003e5a: 6e20 2600 0100                         |0023: invoke-virtual {v1, v0}, Landroid/graphics/Paint;.setTextSize:(F)V // method@0026
+003e60: 8700                                   |0026: float-to-int v0, v0
+003e62: d800 0001                              |0027: add-int/lit8 v0, v0, #int 1 // #01
+003e66: 5930 1d00                              |0029: iput v0, v3, Lcom/google/android/checkers/CheckersView;.k:I // field@001d
+003e6a: 1e03                                   |002b: monitor-exit v3
+003e6c: 0e00                                   |002c: return-void
+003e6e: 0150                                   |002d: move v0, v5
+003e70: 28d6                                   |002e: goto 0004 // -002a
+003e72: 0d00                                   |002f: move-exception v0
+003e74: 1e03                                   |0030: monitor-exit v3
+003e76: 2700                                   |0031: throw v0
+003e78: 0110                                   |0032: move v0, v1
+003e7a: 28df                                   |0033: goto 0012 // -0021
+      catches       : 1
+        0x0004 - 0x002b
+          <any> -> 0x002f
+      positions     : 
+      locals        : 
+
+    #14              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'onTouchEvent'
+      type          : '(Landroid/view/MotionEvent;)Z'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 8
+      ins           : 2
+      outs          : 6
+      insns size    : 41 16-bit code units
+003e88:                                        |[003e88] com.google.android.checkers.CheckersView.onTouchEvent:(Landroid/view/MotionEvent;)Z
+003e98: 1201                                   |0000: const/4 v1, #int 0 // #0
+003e9a: 6e10 3100 0700                         |0001: invoke-virtual {v7}, Landroid/view/MotionEvent;.getAction:()I // method@0031
+003ea0: 0a00                                   |0004: move-result v0
+003ea2: 3900 1f00                              |0005: if-nez v0, 0024 // +001f
+003ea6: 6e10 3200 0700                         |0007: invoke-virtual {v7}, Landroid/view/MotionEvent;.getX:()F // method@0032
+003eac: 0a00                                   |000a: move-result v0
+003eae: 6e10 3300 0700                         |000b: invoke-virtual {v7}, Landroid/view/MotionEvent;.getY:()F // method@0033
+003eb4: 0a02                                   |000e: move-result v2
+003eb6: 7030 5c00 0602                         |000f: invoke-direct {v6, v0, v2}, Lcom/google/android/checkers/CheckersView;.b:(FF)I // method@005c
+003ebc: 0a02                                   |0012: move-result v2
+003ebe: 3802 1100                              |0013: if-eqz v2, 0024 // +0011
+003ec2: 0760                                   |0015: move-object v0, v6
+003ec4: 0113                                   |0016: move v3, v1
+003ec6: 0114                                   |0017: move v4, v1
+003ec8: 0115                                   |0018: move v5, v1
+003eca: 7606 5b00 0000                         |0019: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/CheckersView;.a:(ZIIII)Z // method@005b
+003ed0: 0a00                                   |001c: move-result v0
+003ed2: 3800 0500                              |001d: if-eqz v0, 0022 // +0005
+003ed6: 6e10 6d00 0600                         |001f: invoke-virtual {v6}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+003edc: 1210                                   |0022: const/4 v0, #int 1 // #1
+003ede: 0f00                                   |0023: return v0
+003ee0: 6f20 3900 7600                         |0024: invoke-super {v6, v7}, Landroid/view/View;.onTouchEvent:(Landroid/view/MotionEvent;)Z // method@0039
+003ee6: 0a00                                   |0027: move-result v0
+003ee8: 28fb                                   |0028: goto 0023 // -0005
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #15              : (in Lcom/google/android/checkers/CheckersView;)
+      name          : 'setLevel'
+      type          : '(I)V'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 4
+      ins           : 2
+      outs          : 0
+      insns size    : 64 16-bit code units
+003eec:                                        |[003eec] com.google.android.checkers.CheckersView.setLevel:(I)V
+003efc: 1300 e803                              |0000: const/16 v0, #int 1000 // #3e8
+003f00: 1d02                                   |0002: monitor-enter v2
+003f02: 2b03 2700 0000                         |0003: packed-switch v3, 0000002a // +00000027
+003f08: 1233                                   |0006: const/4 v3, #int 3 // #3
+003f0a: 5421 2200                              |0007: iget-object v1, v2, Lcom/google/android/checkers/CheckersView;.p:Lcom/google/android/checkers/a; // field@0022
+003f0e: 5910 4100                              |0009: iput v0, v1, Lcom/google/android/checkers/a;.h:I // field@0041
+003f12: 5923 2c00                              |000b: iput v3, v2, Lcom/google/android/checkers/CheckersView;.z:I // field@002c
+003f16: 1e02                                   |000d: monitor-exit v2
+003f18: 0e00                                   |000e: return-void
+003f1a: 12f0                                   |000f: const/4 v0, #int -1 // #ff
+003f1c: 28f7                                   |0010: goto 0007 // -0009
+003f1e: 1200                                   |0011: const/4 v0, #int 0 // #0
+003f20: 28f5                                   |0012: goto 0007 // -000b
+003f22: 1300 6400                              |0013: const/16 v0, #int 100 // #64
+003f26: 28f2                                   |0015: goto 0007 // -000e
+003f28: 1300 8813                              |0016: const/16 v0, #int 5000 // #1388
+003f2c: 28ef                                   |0018: goto 0007 // -0011
+003f2e: 1300 1027                              |0019: const/16 v0, #int 10000 // #2710
+003f32: 28ec                                   |001b: goto 0007 // -0014
+003f34: 1300 983a                              |001c: const/16 v0, #int 15000 // #3a98
+003f38: 28e9                                   |001e: goto 0007 // -0017
+003f3a: 1300 3075                              |001f: const/16 v0, #int 30000 // #7530
+003f3e: 28e6                                   |0021: goto 0007 // -001a
+003f40: 1400 60ea 0000                         |0022: const v0, #float 0.000000 // #0000ea60
+003f46: 28e2                                   |0025: goto 0007 // -001e
+003f48: 0d00                                   |0026: move-exception v0
+003f4a: 1e02                                   |0027: monitor-exit v2
+003f4c: 2700                                   |0028: throw v0
+003f4e: 0000                                   |0029: nop // spacer
+003f50: 0001 0900 0000 0000 0c00 0000 0e00 ... |002a: packed-switch-data (22 units)
+      catches       : 1
+        0x0007 - 0x000d
+          <any> -> 0x0026
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #2 header:
+class_idx           : 32
+access_flags        : 17 (0x0011)
+superclass_idx      : 50
+interfaces_off      : 0 (0x000000)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 34848 (0x008820)
+static_fields_size  : 10
+instance_fields_size: 29
+direct_methods_size : 23
+virtual_methods_size: 6
+
+Class #2            -
+  Class descriptor  : 'Lcom/google/android/checkers/a;'
+  Access flags      : 0x0011 (PUBLIC FINAL)
+  Superclass        : 'Ljava/lang/Thread;'
+  Interfaces        -
+  Static fields     -
+    #0              : (in Lcom/google/android/checkers/a;)
+      name          : 'D'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #1              : (in Lcom/google/android/checkers/a;)
+      name          : 'E'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #2              : (in Lcom/google/android/checkers/a;)
+      name          : 'F'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #3              : (in Lcom/google/android/checkers/a;)
+      name          : 'G'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #4              : (in Lcom/google/android/checkers/a;)
+      name          : 'H'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #5              : (in Lcom/google/android/checkers/a;)
+      name          : 'I'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #6              : (in Lcom/google/android/checkers/a;)
+      name          : 'J'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #7              : (in Lcom/google/android/checkers/a;)
+      name          : 'K'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #8              : (in Lcom/google/android/checkers/a;)
+      name          : 'L'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+    #9              : (in Lcom/google/android/checkers/a;)
+      name          : 'M'
+      type          : '[I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/a;)
+      name          : 'A'
+      type          : '[B'
+      access        : 0x0002 (PRIVATE)
+    #1              : (in Lcom/google/android/checkers/a;)
+      name          : 'B'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #2              : (in Lcom/google/android/checkers/a;)
+      name          : 'C'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #3              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '[I'
+      access        : 0x0001 (PUBLIC)
+    #4              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '[I'
+      access        : 0x0001 (PUBLIC)
+    #5              : (in Lcom/google/android/checkers/a;)
+      name          : 'c'
+      type          : 'I'
+      access        : 0x0001 (PUBLIC)
+    #6              : (in Lcom/google/android/checkers/a;)
+      name          : 'd'
+      type          : 'I'
+      access        : 0x0001 (PUBLIC)
+    #7              : (in Lcom/google/android/checkers/a;)
+      name          : 'e'
+      type          : 'I'
+      access        : 0x0001 (PUBLIC)
+    #8              : (in Lcom/google/android/checkers/a;)
+      name          : 'f'
+      type          : 'I'
+      access        : 0x0001 (PUBLIC)
+    #9              : (in Lcom/google/android/checkers/a;)
+      name          : 'g'
+      type          : 'I'
+      access        : 0x0001 (PUBLIC)
+    #10              : (in Lcom/google/android/checkers/a;)
+      name          : 'h'
+      type          : 'I'
+      access        : 0x0041 (PUBLIC VOLATILE)
+    #11              : (in Lcom/google/android/checkers/a;)
+      name          : 'i'
+      type          : 'Ljava/util/Random;'
+      access        : 0x0002 (PRIVATE)
+    #12              : (in Lcom/google/android/checkers/a;)
+      name          : 'j'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x0002 (PRIVATE)
+    #13              : (in Lcom/google/android/checkers/a;)
+      name          : 'k'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #14              : (in Lcom/google/android/checkers/a;)
+      name          : 'l'
+      type          : 'J'
+      access        : 0x0002 (PRIVATE)
+    #15              : (in Lcom/google/android/checkers/a;)
+      name          : 'm'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #16              : (in Lcom/google/android/checkers/a;)
+      name          : 'n'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #17              : (in Lcom/google/android/checkers/a;)
+      name          : 'o'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #18              : (in Lcom/google/android/checkers/a;)
+      name          : 'p'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #19              : (in Lcom/google/android/checkers/a;)
+      name          : 'q'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #20              : (in Lcom/google/android/checkers/a;)
+      name          : 'r'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #21              : (in Lcom/google/android/checkers/a;)
+      name          : 's'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #22              : (in Lcom/google/android/checkers/a;)
+      name          : 't'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #23              : (in Lcom/google/android/checkers/a;)
+      name          : 'u'
+      type          : 'Z'
+      access        : 0x0002 (PRIVATE)
+    #24              : (in Lcom/google/android/checkers/a;)
+      name          : 'v'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #25              : (in Lcom/google/android/checkers/a;)
+      name          : 'w'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #26              : (in Lcom/google/android/checkers/a;)
+      name          : 'x'
+      type          : 'I'
+      access        : 0x0002 (PRIVATE)
+    #27              : (in Lcom/google/android/checkers/a;)
+      name          : 'y'
+      type          : '[I'
+      access        : 0x0002 (PRIVATE)
+    #28              : (in Lcom/google/android/checkers/a;)
+      name          : 'z'
+      type          : '[S'
+      access        : 0x0002 (PRIVATE)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/a;)
+      name          : '<clinit>'
+      type          : '()V'
+      access        : 0x10008 (STATIC CONSTRUCTOR)
+      code          -
+      registers     : 8
+      ins           : 0
+      outs          : 0
+      insns size    : 1390 16-bit code units
+003f88:                                        |[003f88] com.google.android.checkers.a.<clinit>:()V
+003f98: 1227                                   |0000: const/4 v7, #int 2 // #2
+003f9a: 1306 1500                              |0001: const/16 v6, #int 21 // #15
+003f9e: 1305 1000                              |0003: const/16 v5, #int 16 // #10
+003fa2: 1304 0a00                              |0005: const/16 v4, #int 10 // #a
+003fa6: 1303 2000                              |0007: const/16 v3, #int 32 // #20
+003faa: 2330 3700                              |0009: new-array v0, v3, [I // type@0037
+003fae: 1251                                   |000b: const/4 v1, #int 5 // #5
+003fb0: 1212                                   |000c: const/4 v2, #int 1 // #1
+003fb2: 4b02 0001                              |000d: aput v2, v0, v1
+003fb6: 1261                                   |000f: const/4 v1, #int 6 // #6
+003fb8: 4b07 0001                              |0010: aput v7, v0, v1
+003fbc: 1271                                   |0012: const/4 v1, #int 7 // #7
+003fbe: 1242                                   |0013: const/4 v2, #int 4 // #4
+003fc0: 4b02 0001                              |0014: aput v2, v0, v1
+003fc4: 1301 0800                              |0016: const/16 v1, #int 8 // #8
+003fc8: 4b05 0001                              |0018: aput v5, v0, v1
+003fcc: 1301 0900                              |001a: const/16 v1, #int 9 // #9
+003fd0: 4b03 0001                              |001c: aput v3, v0, v1
+003fd4: 1301 4000                              |001e: const/16 v1, #int 64 // #40
+003fd8: 4b01 0004                              |0020: aput v1, v0, v4
+003fdc: 1301 0b00                              |0022: const/16 v1, #int 11 // #b
+003fe0: 1302 8000                              |0024: const/16 v2, #int 128 // #80
+003fe4: 4b02 0001                              |0026: aput v2, v0, v1
+003fe8: 1301 0d00                              |0028: const/16 v1, #int 13 // #d
+003fec: 1302 0001                              |002a: const/16 v2, #int 256 // #100
+003ff0: 4b02 0001                              |002c: aput v2, v0, v1
+003ff4: 1301 0e00                              |002e: const/16 v1, #int 14 // #e
+003ff8: 1302 0002                              |0030: const/16 v2, #int 512 // #200
+003ffc: 4b02 0001                              |0032: aput v2, v0, v1
+004000: 1301 0f00                              |0034: const/16 v1, #int 15 // #f
+004004: 1302 0004                              |0036: const/16 v2, #int 1024 // #400
+004008: 4b02 0001                              |0038: aput v2, v0, v1
+00400c: 1301 0010                              |003a: const/16 v1, #int 4096 // #1000
+004010: 4b01 0005                              |003c: aput v1, v0, v5
+004014: 1301 1100                              |003e: const/16 v1, #int 17 // #11
+004018: 1302 0020                              |0040: const/16 v2, #int 8192 // #2000
+00401c: 4b02 0001                              |0042: aput v2, v0, v1
+004020: 1301 1200                              |0044: const/16 v1, #int 18 // #12
+004024: 1302 0040                              |0046: const/16 v2, #int 16384 // #4000
+004028: 4b02 0001                              |0048: aput v2, v0, v1
+00402c: 1301 1300                              |004a: const/16 v1, #int 19 // #13
+004030: 1402 0080 0000                         |004c: const v2, #float 0.000000 // #00008000
+004036: 4b02 0001                              |004f: aput v2, v0, v1
+00403a: 1501 0100                              |0051: const/high16 v1, #int 65536 // #1
+00403e: 4b01 0006                              |0053: aput v1, v0, v6
+004042: 1301 1600                              |0055: const/16 v1, #int 22 // #16
+004046: 1502 0200                              |0057: const/high16 v2, #int 131072 // #2
+00404a: 4b02 0001                              |0059: aput v2, v0, v1
+00404e: 1301 1700                              |005b: const/16 v1, #int 23 // #17
+004052: 1502 0400                              |005d: const/high16 v2, #int 262144 // #4
+004056: 4b02 0001                              |005f: aput v2, v0, v1
+00405a: 1301 1800                              |0061: const/16 v1, #int 24 // #18
+00405e: 1502 1000                              |0063: const/high16 v2, #int 1048576 // #10
+004062: 4b02 0001                              |0065: aput v2, v0, v1
+004066: 1301 1900                              |0067: const/16 v1, #int 25 // #19
+00406a: 1502 2000                              |0069: const/high16 v2, #int 2097152 // #20
+00406e: 4b02 0001                              |006b: aput v2, v0, v1
+004072: 1301 1a00                              |006d: const/16 v1, #int 26 // #1a
+004076: 1502 4000                              |006f: const/high16 v2, #int 4194304 // #40
+00407a: 4b02 0001                              |0071: aput v2, v0, v1
+00407e: 1301 1b00                              |0073: const/16 v1, #int 27 // #1b
+004082: 1502 8000                              |0075: const/high16 v2, #int 8388608 // #80
+004086: 4b02 0001                              |0077: aput v2, v0, v1
+00408a: 1301 1d00                              |0079: const/16 v1, #int 29 // #1d
+00408e: 1502 0001                              |007b: const/high16 v2, #int 16777216 // #100
+004092: 4b02 0001                              |007d: aput v2, v0, v1
+004096: 1301 1e00                              |007f: const/16 v1, #int 30 // #1e
+00409a: 1502 0002                              |0081: const/high16 v2, #int 33554432 // #200
+00409e: 4b02 0001                              |0083: aput v2, v0, v1
+0040a2: 1301 1f00                              |0085: const/16 v1, #int 31 // #1f
+0040a6: 1502 0004                              |0087: const/high16 v2, #int 67108864 // #400
+0040aa: 4b02 0001                              |0089: aput v2, v0, v1
+0040ae: 6900 3000                              |008b: sput-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+0040b2: 2330 3700                              |008d: new-array v0, v3, [I // type@0037
+0040b6: 1301 0900                              |008f: const/16 v1, #int 9 // #9
+0040ba: 1212                                   |0091: const/4 v2, #int 1 // #1
+0040bc: 4b02 0001                              |0092: aput v2, v0, v1
+0040c0: 4b07 0004                              |0094: aput v7, v0, v4
+0040c4: 1301 0b00                              |0096: const/16 v1, #int 11 // #b
+0040c8: 1242                                   |0098: const/4 v2, #int 4 // #4
+0040ca: 4b02 0001                              |0099: aput v2, v0, v1
+0040ce: 1301 0d00                              |009b: const/16 v1, #int 13 // #d
+0040d2: 4b05 0001                              |009d: aput v5, v0, v1
+0040d6: 1301 0e00                              |009f: const/16 v1, #int 14 // #e
+0040da: 4b03 0001                              |00a1: aput v3, v0, v1
+0040de: 1301 0f00                              |00a3: const/16 v1, #int 15 // #f
+0040e2: 1302 4000                              |00a5: const/16 v2, #int 64 // #40
+0040e6: 4b02 0001                              |00a7: aput v2, v0, v1
+0040ea: 1301 1100                              |00a9: const/16 v1, #int 17 // #11
+0040ee: 1302 0001                              |00ab: const/16 v2, #int 256 // #100
+0040f2: 4b02 0001                              |00ad: aput v2, v0, v1
+0040f6: 1301 1200                              |00af: const/16 v1, #int 18 // #12
+0040fa: 1302 0002                              |00b1: const/16 v2, #int 512 // #200
+0040fe: 4b02 0001                              |00b3: aput v2, v0, v1
+004102: 1301 1300                              |00b5: const/16 v1, #int 19 // #13
+004106: 1302 0004                              |00b7: const/16 v2, #int 1024 // #400
+00410a: 4b02 0001                              |00b9: aput v2, v0, v1
+00410e: 1301 0010                              |00bb: const/16 v1, #int 4096 // #1000
+004112: 4b01 0006                              |00bd: aput v1, v0, v6
+004116: 1301 1600                              |00bf: const/16 v1, #int 22 // #16
+00411a: 1302 0020                              |00c1: const/16 v2, #int 8192 // #2000
+00411e: 4b02 0001                              |00c3: aput v2, v0, v1
+004122: 1301 1700                              |00c5: const/16 v1, #int 23 // #17
+004126: 1302 0040                              |00c7: const/16 v2, #int 16384 // #4000
+00412a: 4b02 0001                              |00c9: aput v2, v0, v1
+00412e: 1301 1900                              |00cb: const/16 v1, #int 25 // #19
+004132: 1502 0100                              |00cd: const/high16 v2, #int 65536 // #1
+004136: 4b02 0001                              |00cf: aput v2, v0, v1
+00413a: 1301 1a00                              |00d1: const/16 v1, #int 26 // #1a
+00413e: 1502 0200                              |00d3: const/high16 v2, #int 131072 // #2
+004142: 4b02 0001                              |00d5: aput v2, v0, v1
+004146: 1301 1b00                              |00d7: const/16 v1, #int 27 // #1b
+00414a: 1502 0400                              |00d9: const/high16 v2, #int 262144 // #4
+00414e: 4b02 0001                              |00db: aput v2, v0, v1
+004152: 1301 1d00                              |00dd: const/16 v1, #int 29 // #1d
+004156: 1502 1000                              |00df: const/high16 v2, #int 1048576 // #10
+00415a: 4b02 0001                              |00e1: aput v2, v0, v1
+00415e: 1301 1e00                              |00e3: const/16 v1, #int 30 // #1e
+004162: 1502 2000                              |00e5: const/high16 v2, #int 2097152 // #20
+004166: 4b02 0001                              |00e7: aput v2, v0, v1
+00416a: 1301 1f00                              |00e9: const/16 v1, #int 31 // #1f
+00416e: 1502 4000                              |00eb: const/high16 v2, #int 4194304 // #40
+004172: 4b02 0001                              |00ed: aput v2, v0, v1
+004176: 6900 3100                              |00ef: sput-object v0, Lcom/google/android/checkers/a;.E:[I // field@0031
+00417a: 2330 3700                              |00f1: new-array v0, v3, [I // type@0037
+00417e: 1241                                   |00f3: const/4 v1, #int 4 // #4
+004180: 1212                                   |00f4: const/4 v2, #int 1 // #1
+004182: 4b02 0001                              |00f5: aput v2, v0, v1
+004186: 1251                                   |00f7: const/4 v1, #int 5 // #5
+004188: 4b07 0001                              |00f8: aput v7, v0, v1
+00418c: 1261                                   |00fa: const/4 v1, #int 6 // #6
+00418e: 1242                                   |00fb: const/4 v2, #int 4 // #4
+004190: 4b02 0001                              |00fc: aput v2, v0, v1
+004194: 1271                                   |00fe: const/4 v1, #int 7 // #7
+004196: 1302 0800                              |00ff: const/16 v2, #int 8 // #8
+00419a: 4b02 0001                              |0101: aput v2, v0, v1
+00419e: 1301 0800                              |0103: const/16 v1, #int 8 // #8
+0041a2: 4b03 0001                              |0105: aput v3, v0, v1
+0041a6: 1301 0900                              |0107: const/16 v1, #int 9 // #9
+0041aa: 1302 4000                              |0109: const/16 v2, #int 64 // #40
+0041ae: 4b02 0001                              |010b: aput v2, v0, v1
+0041b2: 1301 8000                              |010d: const/16 v1, #int 128 // #80
+0041b6: 4b01 0004                              |010f: aput v1, v0, v4
+0041ba: 1301 0c00                              |0111: const/16 v1, #int 12 // #c
+0041be: 1302 0001                              |0113: const/16 v2, #int 256 // #100
+0041c2: 4b02 0001                              |0115: aput v2, v0, v1
+0041c6: 1301 0d00                              |0117: const/16 v1, #int 13 // #d
+0041ca: 1302 0002                              |0119: const/16 v2, #int 512 // #200
+0041ce: 4b02 0001                              |011b: aput v2, v0, v1
+0041d2: 1301 0e00                              |011d: const/16 v1, #int 14 // #e
+0041d6: 1302 0004                              |011f: const/16 v2, #int 1024 // #400
+0041da: 4b02 0001                              |0121: aput v2, v0, v1
+0041de: 1301 0f00                              |0123: const/16 v1, #int 15 // #f
+0041e2: 1302 0008                              |0125: const/16 v2, #int 2048 // #800
+0041e6: 4b02 0001                              |0127: aput v2, v0, v1
+0041ea: 1301 0020                              |0129: const/16 v1, #int 8192 // #2000
+0041ee: 4b01 0005                              |012b: aput v1, v0, v5
+0041f2: 1301 1100                              |012d: const/16 v1, #int 17 // #11
+0041f6: 1302 0040                              |012f: const/16 v2, #int 16384 // #4000
+0041fa: 4b02 0001                              |0131: aput v2, v0, v1
+0041fe: 1301 1200                              |0133: const/16 v1, #int 18 // #12
+004202: 1402 0080 0000                         |0135: const v2, #float 0.000000 // #00008000
+004208: 4b02 0001                              |0138: aput v2, v0, v1
+00420c: 1301 1400                              |013a: const/16 v1, #int 20 // #14
+004210: 1502 0100                              |013c: const/high16 v2, #int 65536 // #1
+004214: 4b02 0001                              |013e: aput v2, v0, v1
+004218: 1501 0200                              |0140: const/high16 v1, #int 131072 // #2
+00421c: 4b01 0006                              |0142: aput v1, v0, v6
+004220: 1301 1600                              |0144: const/16 v1, #int 22 // #16
+004224: 1502 0400                              |0146: const/high16 v2, #int 262144 // #4
+004228: 4b02 0001                              |0148: aput v2, v0, v1
+00422c: 1301 1700                              |014a: const/16 v1, #int 23 // #17
+004230: 1502 0800                              |014c: const/high16 v2, #int 524288 // #8
+004234: 4b02 0001                              |014e: aput v2, v0, v1
+004238: 1301 1800                              |0150: const/16 v1, #int 24 // #18
+00423c: 1502 2000                              |0152: const/high16 v2, #int 2097152 // #20
+004240: 4b02 0001                              |0154: aput v2, v0, v1
+004244: 1301 1900                              |0156: const/16 v1, #int 25 // #19
+004248: 1502 4000                              |0158: const/high16 v2, #int 4194304 // #40
+00424c: 4b02 0001                              |015a: aput v2, v0, v1
+004250: 1301 1a00                              |015c: const/16 v1, #int 26 // #1a
+004254: 1502 8000                              |015e: const/high16 v2, #int 8388608 // #80
+004258: 4b02 0001                              |0160: aput v2, v0, v1
+00425c: 1301 1c00                              |0162: const/16 v1, #int 28 // #1c
+004260: 1502 0001                              |0164: const/high16 v2, #int 16777216 // #100
+004264: 4b02 0001                              |0166: aput v2, v0, v1
+004268: 1301 1d00                              |0168: const/16 v1, #int 29 // #1d
+00426c: 1502 0002                              |016a: const/high16 v2, #int 33554432 // #200
+004270: 4b02 0001                              |016c: aput v2, v0, v1
+004274: 1301 1e00                              |016e: const/16 v1, #int 30 // #1e
+004278: 1502 0004                              |0170: const/high16 v2, #int 67108864 // #400
+00427c: 4b02 0001                              |0172: aput v2, v0, v1
+004280: 1301 1f00                              |0174: const/16 v1, #int 31 // #1f
+004284: 1502 0008                              |0176: const/high16 v2, #int 134217728 // #800
+004288: 4b02 0001                              |0178: aput v2, v0, v1
+00428c: 6900 3200                              |017a: sput-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+004290: 2330 3700                              |017c: new-array v0, v3, [I // type@0037
+004294: 1301 0800                              |017e: const/16 v1, #int 8 // #8
+004298: 4b07 0001                              |0180: aput v7, v0, v1
+00429c: 1301 0900                              |0182: const/16 v1, #int 9 // #9
+0042a0: 1242                                   |0184: const/4 v2, #int 4 // #4
+0042a2: 4b02 0001                              |0185: aput v2, v0, v1
+0042a6: 1301 0800                              |0187: const/16 v1, #int 8 // #8
+0042aa: 4b01 0004                              |0189: aput v1, v0, v4
+0042ae: 1301 0c00                              |018b: const/16 v1, #int 12 // #c
+0042b2: 4b03 0001                              |018d: aput v3, v0, v1
+0042b6: 1301 0d00                              |018f: const/16 v1, #int 13 // #d
+0042ba: 1302 4000                              |0191: const/16 v2, #int 64 // #40
+0042be: 4b02 0001                              |0193: aput v2, v0, v1
+0042c2: 1301 0e00                              |0195: const/16 v1, #int 14 // #e
+0042c6: 1302 8000                              |0197: const/16 v2, #int 128 // #80
+0042ca: 4b02 0001                              |0199: aput v2, v0, v1
+0042ce: 1301 0002                              |019b: const/16 v1, #int 512 // #200
+0042d2: 4b01 0005                              |019d: aput v1, v0, v5
+0042d6: 1301 1100                              |019f: const/16 v1, #int 17 // #11
+0042da: 1302 0004                              |01a1: const/16 v2, #int 1024 // #400
+0042de: 4b02 0001                              |01a3: aput v2, v0, v1
+0042e2: 1301 1200                              |01a5: const/16 v1, #int 18 // #12
+0042e6: 1302 0008                              |01a7: const/16 v2, #int 2048 // #800
+0042ea: 4b02 0001                              |01a9: aput v2, v0, v1
+0042ee: 1301 1400                              |01ab: const/16 v1, #int 20 // #14
+0042f2: 1302 0020                              |01ad: const/16 v2, #int 8192 // #2000
+0042f6: 4b02 0001                              |01af: aput v2, v0, v1
+0042fa: 1301 0040                              |01b1: const/16 v1, #int 16384 // #4000
+0042fe: 4b01 0006                              |01b3: aput v1, v0, v6
+004302: 1301 1600                              |01b5: const/16 v1, #int 22 // #16
+004306: 1402 0080 0000                         |01b7: const v2, #float 0.000000 // #00008000
+00430c: 4b02 0001                              |01ba: aput v2, v0, v1
+004310: 1301 1800                              |01bc: const/16 v1, #int 24 // #18
+004314: 1502 0200                              |01be: const/high16 v2, #int 131072 // #2
+004318: 4b02 0001                              |01c0: aput v2, v0, v1
+00431c: 1301 1900                              |01c2: const/16 v1, #int 25 // #19
+004320: 1502 0400                              |01c4: const/high16 v2, #int 262144 // #4
+004324: 4b02 0001                              |01c6: aput v2, v0, v1
+004328: 1301 1a00                              |01c8: const/16 v1, #int 26 // #1a
+00432c: 1502 0800                              |01ca: const/high16 v2, #int 524288 // #8
+004330: 4b02 0001                              |01cc: aput v2, v0, v1
+004334: 1301 1c00                              |01ce: const/16 v1, #int 28 // #1c
+004338: 1502 2000                              |01d0: const/high16 v2, #int 2097152 // #20
+00433c: 4b02 0001                              |01d2: aput v2, v0, v1
+004340: 1301 1d00                              |01d4: const/16 v1, #int 29 // #1d
+004344: 1502 4000                              |01d6: const/high16 v2, #int 4194304 // #40
+004348: 4b02 0001                              |01d8: aput v2, v0, v1
+00434c: 1301 1e00                              |01da: const/16 v1, #int 30 // #1e
+004350: 1502 8000                              |01dc: const/high16 v2, #int 8388608 // #80
+004354: 4b02 0001                              |01de: aput v2, v0, v1
+004358: 6900 3300                              |01e0: sput-object v0, Lcom/google/android/checkers/a;.G:[I // field@0033
+00435c: 2330 3700                              |01e2: new-array v0, v3, [I // type@0037
+004360: 1201                                   |01e4: const/4 v1, #int 0 // #0
+004362: 4b05 0001                              |01e5: aput v5, v0, v1
+004366: 1211                                   |01e7: const/4 v1, #int 1 // #1
+004368: 4b03 0001                              |01e8: aput v3, v0, v1
+00436c: 1301 4000                              |01ea: const/16 v1, #int 64 // #40
+004370: 4b01 0007                              |01ec: aput v1, v0, v7
+004374: 1231                                   |01ee: const/4 v1, #int 3 // #3
+004376: 1302 8000                              |01ef: const/16 v2, #int 128 // #80
+00437a: 4b02 0001                              |01f1: aput v2, v0, v1
+00437e: 1251                                   |01f3: const/4 v1, #int 5 // #5
+004380: 1302 0001                              |01f4: const/16 v2, #int 256 // #100
+004384: 4b02 0001                              |01f6: aput v2, v0, v1
+004388: 1261                                   |01f8: const/4 v1, #int 6 // #6
+00438a: 1302 0002                              |01f9: const/16 v2, #int 512 // #200
+00438e: 4b02 0001                              |01fb: aput v2, v0, v1
+004392: 1271                                   |01fd: const/4 v1, #int 7 // #7
+004394: 1302 0004                              |01fe: const/16 v2, #int 1024 // #400
+004398: 4b02 0001                              |0200: aput v2, v0, v1
+00439c: 1301 0800                              |0202: const/16 v1, #int 8 // #8
+0043a0: 1302 0010                              |0204: const/16 v2, #int 4096 // #1000
+0043a4: 4b02 0001                              |0206: aput v2, v0, v1
+0043a8: 1301 0900                              |0208: const/16 v1, #int 9 // #9
+0043ac: 1302 0020                              |020a: const/16 v2, #int 8192 // #2000
+0043b0: 4b02 0001                              |020c: aput v2, v0, v1
+0043b4: 1301 0040                              |020e: const/16 v1, #int 16384 // #4000
+0043b8: 4b01 0004                              |0210: aput v1, v0, v4
+0043bc: 1301 0b00                              |0212: const/16 v1, #int 11 // #b
+0043c0: 1402 0080 0000                         |0214: const v2, #float 0.000000 // #00008000
+0043c6: 4b02 0001                              |0217: aput v2, v0, v1
+0043ca: 1301 0d00                              |0219: const/16 v1, #int 13 // #d
+0043ce: 1502 0100                              |021b: const/high16 v2, #int 65536 // #1
+0043d2: 4b02 0001                              |021d: aput v2, v0, v1
+0043d6: 1301 0e00                              |021f: const/16 v1, #int 14 // #e
+0043da: 1502 0200                              |0221: const/high16 v2, #int 131072 // #2
+0043de: 4b02 0001                              |0223: aput v2, v0, v1
+0043e2: 1301 0f00                              |0225: const/16 v1, #int 15 // #f
+0043e6: 1502 0400                              |0227: const/high16 v2, #int 262144 // #4
+0043ea: 4b02 0001                              |0229: aput v2, v0, v1
+0043ee: 1501 1000                              |022b: const/high16 v1, #int 1048576 // #10
+0043f2: 4b01 0005                              |022d: aput v1, v0, v5
+0043f6: 1301 1100                              |022f: const/16 v1, #int 17 // #11
+0043fa: 1502 2000                              |0231: const/high16 v2, #int 2097152 // #20
+0043fe: 4b02 0001                              |0233: aput v2, v0, v1
+004402: 1301 1200                              |0235: const/16 v1, #int 18 // #12
+004406: 1502 4000                              |0237: const/high16 v2, #int 4194304 // #40
+00440a: 4b02 0001                              |0239: aput v2, v0, v1
+00440e: 1301 1300                              |023b: const/16 v1, #int 19 // #13
+004412: 1502 8000                              |023d: const/high16 v2, #int 8388608 // #80
+004416: 4b02 0001                              |023f: aput v2, v0, v1
+00441a: 1501 0001                              |0241: const/high16 v1, #int 16777216 // #100
+00441e: 4b01 0006                              |0243: aput v1, v0, v6
+004422: 1301 1600                              |0245: const/16 v1, #int 22 // #16
+004426: 1502 0002                              |0247: const/high16 v2, #int 33554432 // #200
+00442a: 4b02 0001                              |0249: aput v2, v0, v1
+00442e: 1301 1700                              |024b: const/16 v1, #int 23 // #17
+004432: 1502 0004                              |024d: const/high16 v2, #int 67108864 // #400
+004436: 4b02 0001                              |024f: aput v2, v0, v1
+00443a: 1301 1800                              |0251: const/16 v1, #int 24 // #18
+00443e: 1502 0010                              |0253: const/high16 v2, #int 268435456 // #1000
+004442: 4b02 0001                              |0255: aput v2, v0, v1
+004446: 1301 1900                              |0257: const/16 v1, #int 25 // #19
+00444a: 1502 0020                              |0259: const/high16 v2, #int 536870912 // #2000
+00444e: 4b02 0001                              |025b: aput v2, v0, v1
+004452: 1301 1a00                              |025d: const/16 v1, #int 26 // #1a
+004456: 1502 0040                              |025f: const/high16 v2, #int 1073741824 // #4000
+00445a: 4b02 0001                              |0261: aput v2, v0, v1
+00445e: 1301 1b00                              |0263: const/16 v1, #int 27 // #1b
+004462: 1502 0080                              |0265: const/high16 v2, #int -2147483648 // #8000
+004466: 4b02 0001                              |0267: aput v2, v0, v1
+00446a: 6900 3400                              |0269: sput-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+00446e: 2330 3700                              |026b: new-array v0, v3, [I // type@0037
+004472: 1211                                   |026d: const/4 v1, #int 1 // #1
+004474: 1302 0001                              |026e: const/16 v2, #int 256 // #100
+004478: 4b02 0001                              |0270: aput v2, v0, v1
+00447c: 1301 0002                              |0272: const/16 v1, #int 512 // #200
+004480: 4b01 0007                              |0274: aput v1, v0, v7
+004484: 1231                                   |0276: const/4 v1, #int 3 // #3
+004486: 1302 0004                              |0277: const/16 v2, #int 1024 // #400
+00448a: 4b02 0001                              |0279: aput v2, v0, v1
+00448e: 1251                                   |027b: const/4 v1, #int 5 // #5
+004490: 1302 0010                              |027c: const/16 v2, #int 4096 // #1000
+004494: 4b02 0001                              |027e: aput v2, v0, v1
+004498: 1261                                   |0280: const/4 v1, #int 6 // #6
+00449a: 1302 0020                              |0281: const/16 v2, #int 8192 // #2000
+00449e: 4b02 0001                              |0283: aput v2, v0, v1
+0044a2: 1271                                   |0285: const/4 v1, #int 7 // #7
+0044a4: 1302 0040                              |0286: const/16 v2, #int 16384 // #4000
+0044a8: 4b02 0001                              |0288: aput v2, v0, v1
+0044ac: 1301 0900                              |028a: const/16 v1, #int 9 // #9
+0044b0: 1502 0100                              |028c: const/high16 v2, #int 65536 // #1
+0044b4: 4b02 0001                              |028e: aput v2, v0, v1
+0044b8: 1501 0200                              |0290: const/high16 v1, #int 131072 // #2
+0044bc: 4b01 0004                              |0292: aput v1, v0, v4
+0044c0: 1301 0b00                              |0294: const/16 v1, #int 11 // #b
+0044c4: 1502 0400                              |0296: const/high16 v2, #int 262144 // #4
+0044c8: 4b02 0001                              |0298: aput v2, v0, v1
+0044cc: 1301 0d00                              |029a: const/16 v1, #int 13 // #d
+0044d0: 1502 1000                              |029c: const/high16 v2, #int 1048576 // #10
+0044d4: 4b02 0001                              |029e: aput v2, v0, v1
+0044d8: 1301 0e00                              |02a0: const/16 v1, #int 14 // #e
+0044dc: 1502 2000                              |02a2: const/high16 v2, #int 2097152 // #20
+0044e0: 4b02 0001                              |02a4: aput v2, v0, v1
+0044e4: 1301 0f00                              |02a6: const/16 v1, #int 15 // #f
+0044e8: 1502 4000                              |02a8: const/high16 v2, #int 4194304 // #40
+0044ec: 4b02 0001                              |02aa: aput v2, v0, v1
+0044f0: 1301 1100                              |02ac: const/16 v1, #int 17 // #11
+0044f4: 1502 0001                              |02ae: const/high16 v2, #int 16777216 // #100
+0044f8: 4b02 0001                              |02b0: aput v2, v0, v1
+0044fc: 1301 1200                              |02b2: const/16 v1, #int 18 // #12
+004500: 1502 0002                              |02b4: const/high16 v2, #int 33554432 // #200
+004504: 4b02 0001                              |02b6: aput v2, v0, v1
+004508: 1301 1300                              |02b8: const/16 v1, #int 19 // #13
+00450c: 1502 0004                              |02ba: const/high16 v2, #int 67108864 // #400
+004510: 4b02 0001                              |02bc: aput v2, v0, v1
+004514: 1501 0010                              |02be: const/high16 v1, #int 268435456 // #1000
+004518: 4b01 0006                              |02c0: aput v1, v0, v6
+00451c: 1301 1600                              |02c2: const/16 v1, #int 22 // #16
+004520: 1502 0020                              |02c4: const/high16 v2, #int 536870912 // #2000
+004524: 4b02 0001                              |02c6: aput v2, v0, v1
+004528: 1301 1700                              |02c8: const/16 v1, #int 23 // #17
+00452c: 1502 0040                              |02ca: const/high16 v2, #int 1073741824 // #4000
+004530: 4b02 0001                              |02cc: aput v2, v0, v1
+004534: 6900 3500                              |02ce: sput-object v0, Lcom/google/android/checkers/a;.I:[I // field@0035
+004538: 2330 3700                              |02d0: new-array v0, v3, [I // type@0037
+00453c: 1201                                   |02d2: const/4 v1, #int 0 // #0
+00453e: 4b03 0001                              |02d3: aput v3, v0, v1
+004542: 1211                                   |02d5: const/4 v1, #int 1 // #1
+004544: 1302 4000                              |02d6: const/16 v2, #int 64 // #40
+004548: 4b02 0001                              |02d8: aput v2, v0, v1
+00454c: 1301 8000                              |02da: const/16 v1, #int 128 // #80
+004550: 4b01 0007                              |02dc: aput v1, v0, v7
+004554: 1241                                   |02de: const/4 v1, #int 4 // #4
+004556: 1302 0001                              |02df: const/16 v2, #int 256 // #100
+00455a: 4b02 0001                              |02e1: aput v2, v0, v1
+00455e: 1251                                   |02e3: const/4 v1, #int 5 // #5
+004560: 1302 0002                              |02e4: const/16 v2, #int 512 // #200
+004564: 4b02 0001                              |02e6: aput v2, v0, v1
+004568: 1261                                   |02e8: const/4 v1, #int 6 // #6
+00456a: 1302 0004                              |02e9: const/16 v2, #int 1024 // #400
+00456e: 4b02 0001                              |02eb: aput v2, v0, v1
+004572: 1271                                   |02ed: const/4 v1, #int 7 // #7
+004574: 1302 0008                              |02ee: const/16 v2, #int 2048 // #800
+004578: 4b02 0001                              |02f0: aput v2, v0, v1
+00457c: 1301 0800                              |02f2: const/16 v1, #int 8 // #8
+004580: 1302 0020                              |02f4: const/16 v2, #int 8192 // #2000
+004584: 4b02 0001                              |02f6: aput v2, v0, v1
+004588: 1301 0900                              |02f8: const/16 v1, #int 9 // #9
+00458c: 1302 0040                              |02fa: const/16 v2, #int 16384 // #4000
+004590: 4b02 0001                              |02fc: aput v2, v0, v1
+004594: 1401 0080 0000                         |02fe: const v1, #float 0.000000 // #00008000
+00459a: 4b01 0004                              |0301: aput v1, v0, v4
+00459e: 1301 0c00                              |0303: const/16 v1, #int 12 // #c
+0045a2: 1502 0100                              |0305: const/high16 v2, #int 65536 // #1
+0045a6: 4b02 0001                              |0307: aput v2, v0, v1
+0045aa: 1301 0d00                              |0309: const/16 v1, #int 13 // #d
+0045ae: 1502 0200                              |030b: const/high16 v2, #int 131072 // #2
+0045b2: 4b02 0001                              |030d: aput v2, v0, v1
+0045b6: 1301 0e00                              |030f: const/16 v1, #int 14 // #e
+0045ba: 1502 0400                              |0311: const/high16 v2, #int 262144 // #4
+0045be: 4b02 0001                              |0313: aput v2, v0, v1
+0045c2: 1301 0f00                              |0315: const/16 v1, #int 15 // #f
+0045c6: 1502 0800                              |0317: const/high16 v2, #int 524288 // #8
+0045ca: 4b02 0001                              |0319: aput v2, v0, v1
+0045ce: 1501 2000                              |031b: const/high16 v1, #int 2097152 // #20
+0045d2: 4b01 0005                              |031d: aput v1, v0, v5
+0045d6: 1301 1100                              |031f: const/16 v1, #int 17 // #11
+0045da: 1502 4000                              |0321: const/high16 v2, #int 4194304 // #40
+0045de: 4b02 0001                              |0323: aput v2, v0, v1
+0045e2: 1301 1200                              |0325: const/16 v1, #int 18 // #12
+0045e6: 1502 8000                              |0327: const/high16 v2, #int 8388608 // #80
+0045ea: 4b02 0001                              |0329: aput v2, v0, v1
+0045ee: 1301 1400                              |032b: const/16 v1, #int 20 // #14
+0045f2: 1502 0001                              |032d: const/high16 v2, #int 16777216 // #100
+0045f6: 4b02 0001                              |032f: aput v2, v0, v1
+0045fa: 1501 0002                              |0331: const/high16 v1, #int 33554432 // #200
+0045fe: 4b01 0006                              |0333: aput v1, v0, v6
+004602: 1301 1600                              |0335: const/16 v1, #int 22 // #16
+004606: 1502 0004                              |0337: const/high16 v2, #int 67108864 // #400
+00460a: 4b02 0001                              |0339: aput v2, v0, v1
+00460e: 1301 1700                              |033b: const/16 v1, #int 23 // #17
+004612: 1502 0008                              |033d: const/high16 v2, #int 134217728 // #800
+004616: 4b02 0001                              |033f: aput v2, v0, v1
+00461a: 1301 1800                              |0341: const/16 v1, #int 24 // #18
+00461e: 1502 0020                              |0343: const/high16 v2, #int 536870912 // #2000
+004622: 4b02 0001                              |0345: aput v2, v0, v1
+004626: 1301 1900                              |0347: const/16 v1, #int 25 // #19
+00462a: 1502 0040                              |0349: const/high16 v2, #int 1073741824 // #4000
+00462e: 4b02 0001                              |034b: aput v2, v0, v1
+004632: 1301 1a00                              |034d: const/16 v1, #int 26 // #1a
+004636: 1502 0080                              |034f: const/high16 v2, #int -2147483648 // #8000
+00463a: 4b02 0001                              |0351: aput v2, v0, v1
+00463e: 6900 3600                              |0353: sput-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+004642: 2330 3700                              |0355: new-array v0, v3, [I // type@0037
+004646: 1201                                   |0357: const/4 v1, #int 0 // #0
+004648: 1302 0002                              |0358: const/16 v2, #int 512 // #200
+00464c: 4b02 0001                              |035a: aput v2, v0, v1
+004650: 1211                                   |035c: const/4 v1, #int 1 // #1
+004652: 1302 0004                              |035d: const/16 v2, #int 1024 // #400
+004656: 4b02 0001                              |035f: aput v2, v0, v1
+00465a: 1301 0008                              |0361: const/16 v1, #int 2048 // #800
+00465e: 4b01 0007                              |0363: aput v1, v0, v7
+004662: 1241                                   |0365: const/4 v1, #int 4 // #4
+004664: 1302 0020                              |0366: const/16 v2, #int 8192 // #2000
+004668: 4b02 0001                              |0368: aput v2, v0, v1
+00466c: 1251                                   |036a: const/4 v1, #int 5 // #5
+00466e: 1302 0040                              |036b: const/16 v2, #int 16384 // #4000
+004672: 4b02 0001                              |036d: aput v2, v0, v1
+004676: 1261                                   |036f: const/4 v1, #int 6 // #6
+004678: 1402 0080 0000                         |0370: const v2, #float 0.000000 // #00008000
+00467e: 4b02 0001                              |0373: aput v2, v0, v1
+004682: 1301 0800                              |0375: const/16 v1, #int 8 // #8
+004686: 1502 0200                              |0377: const/high16 v2, #int 131072 // #2
+00468a: 4b02 0001                              |0379: aput v2, v0, v1
+00468e: 1301 0900                              |037b: const/16 v1, #int 9 // #9
+004692: 1502 0400                              |037d: const/high16 v2, #int 262144 // #4
+004696: 4b02 0001                              |037f: aput v2, v0, v1
+00469a: 1501 0800                              |0381: const/high16 v1, #int 524288 // #8
+00469e: 4b01 0004                              |0383: aput v1, v0, v4
+0046a2: 1301 0c00                              |0385: const/16 v1, #int 12 // #c
+0046a6: 1502 2000                              |0387: const/high16 v2, #int 2097152 // #20
+0046aa: 4b02 0001                              |0389: aput v2, v0, v1
+0046ae: 1301 0d00                              |038b: const/16 v1, #int 13 // #d
+0046b2: 1502 4000                              |038d: const/high16 v2, #int 4194304 // #40
+0046b6: 4b02 0001                              |038f: aput v2, v0, v1
+0046ba: 1301 0e00                              |0391: const/16 v1, #int 14 // #e
+0046be: 1502 8000                              |0393: const/high16 v2, #int 8388608 // #80
+0046c2: 4b02 0001                              |0395: aput v2, v0, v1
+0046c6: 1501 0002                              |0397: const/high16 v1, #int 33554432 // #200
+0046ca: 4b01 0005                              |0399: aput v1, v0, v5
+0046ce: 1301 1100                              |039b: const/16 v1, #int 17 // #11
+0046d2: 1502 0004                              |039d: const/high16 v2, #int 67108864 // #400
+0046d6: 4b02 0001                              |039f: aput v2, v0, v1
+0046da: 1301 1200                              |03a1: const/16 v1, #int 18 // #12
+0046de: 1502 0008                              |03a3: const/high16 v2, #int 134217728 // #800
+0046e2: 4b02 0001                              |03a5: aput v2, v0, v1
+0046e6: 1301 1400                              |03a7: const/16 v1, #int 20 // #14
+0046ea: 1502 0020                              |03a9: const/high16 v2, #int 536870912 // #2000
+0046ee: 4b02 0001                              |03ab: aput v2, v0, v1
+0046f2: 1501 0040                              |03ad: const/high16 v1, #int 1073741824 // #4000
+0046f6: 4b01 0006                              |03af: aput v1, v0, v6
+0046fa: 1301 1600                              |03b1: const/16 v1, #int 22 // #16
+0046fe: 1502 0080                              |03b3: const/high16 v2, #int -2147483648 // #8000
+004702: 4b02 0001                              |03b5: aput v2, v0, v1
+004706: 6900 3700                              |03b7: sput-object v0, Lcom/google/android/checkers/a;.K:[I // field@0037
+00470a: 2330 3700                              |03b9: new-array v0, v3, [I // type@0037
+00470e: 1211                                   |03bb: const/4 v1, #int 1 // #1
+004710: 4b01 0007                              |03bc: aput v1, v0, v7
+004714: 1231                                   |03be: const/4 v1, #int 3 // #3
+004716: 1232                                   |03bf: const/4 v2, #int 3 // #3
+004718: 4b02 0001                              |03c0: aput v2, v0, v1
+00471c: 1241                                   |03c2: const/4 v1, #int 4 // #4
+00471e: 1262                                   |03c3: const/4 v2, #int 6 // #6
+004720: 4b02 0001                              |03c4: aput v2, v0, v1
+004724: 1251                                   |03c6: const/4 v1, #int 5 // #5
+004726: 4b04 0001                              |03c7: aput v4, v0, v1
+00472a: 1261                                   |03c9: const/4 v1, #int 6 // #6
+00472c: 1302 0f00                              |03ca: const/16 v2, #int 15 // #f
+004730: 4b02 0001                              |03cc: aput v2, v0, v1
+004734: 1271                                   |03ce: const/4 v1, #int 7 // #7
+004736: 4b06 0001                              |03cf: aput v6, v0, v1
+00473a: 1301 0800                              |03d1: const/16 v1, #int 8 // #8
+00473e: 1302 1c00                              |03d3: const/16 v2, #int 28 // #1c
+004742: 4b02 0001                              |03d5: aput v2, v0, v1
+004746: 1301 0900                              |03d7: const/16 v1, #int 9 // #9
+00474a: 1302 2400                              |03d9: const/16 v2, #int 36 // #24
+00474e: 4b02 0001                              |03db: aput v2, v0, v1
+004752: 1301 2d00                              |03dd: const/16 v1, #int 45 // #2d
+004756: 4b01 0004                              |03df: aput v1, v0, v4
+00475a: 1301 0b00                              |03e1: const/16 v1, #int 11 // #b
+00475e: 1302 3700                              |03e3: const/16 v2, #int 55 // #37
+004762: 4b02 0001                              |03e5: aput v2, v0, v1
+004766: 1301 0c00                              |03e7: const/16 v1, #int 12 // #c
+00476a: 1302 4200                              |03e9: const/16 v2, #int 66 // #42
+00476e: 4b02 0001                              |03eb: aput v2, v0, v1
+004772: 1301 0d00                              |03ed: const/16 v1, #int 13 // #d
+004776: 1302 4e00                              |03ef: const/16 v2, #int 78 // #4e
+00477a: 4b02 0001                              |03f1: aput v2, v0, v1
+00477e: 1301 0e00                              |03f3: const/16 v1, #int 14 // #e
+004782: 1302 5b00                              |03f5: const/16 v2, #int 91 // #5b
+004786: 4b02 0001                              |03f7: aput v2, v0, v1
+00478a: 1301 0f00                              |03f9: const/16 v1, #int 15 // #f
+00478e: 1302 6900                              |03fb: const/16 v2, #int 105 // #69
+004792: 4b02 0001                              |03fd: aput v2, v0, v1
+004796: 1301 7800                              |03ff: const/16 v1, #int 120 // #78
+00479a: 4b01 0005                              |0401: aput v1, v0, v5
+00479e: 1301 1100                              |0403: const/16 v1, #int 17 // #11
+0047a2: 1302 8800                              |0405: const/16 v2, #int 136 // #88
+0047a6: 4b02 0001                              |0407: aput v2, v0, v1
+0047aa: 1301 1200                              |0409: const/16 v1, #int 18 // #12
+0047ae: 1302 9900                              |040b: const/16 v2, #int 153 // #99
+0047b2: 4b02 0001                              |040d: aput v2, v0, v1
+0047b6: 1301 1300                              |040f: const/16 v1, #int 19 // #13
+0047ba: 1302 ab00                              |0411: const/16 v2, #int 171 // #ab
+0047be: 4b02 0001                              |0413: aput v2, v0, v1
+0047c2: 1301 1400                              |0415: const/16 v1, #int 20 // #14
+0047c6: 1302 be00                              |0417: const/16 v2, #int 190 // #be
+0047ca: 4b02 0001                              |0419: aput v2, v0, v1
+0047ce: 1301 d200                              |041b: const/16 v1, #int 210 // #d2
+0047d2: 4b01 0006                              |041d: aput v1, v0, v6
+0047d6: 1301 1600                              |041f: const/16 v1, #int 22 // #16
+0047da: 1302 e700                              |0421: const/16 v2, #int 231 // #e7
+0047de: 4b02 0001                              |0423: aput v2, v0, v1
+0047e2: 1301 1700                              |0425: const/16 v1, #int 23 // #17
+0047e6: 1302 fd00                              |0427: const/16 v2, #int 253 // #fd
+0047ea: 4b02 0001                              |0429: aput v2, v0, v1
+0047ee: 1301 1800                              |042b: const/16 v1, #int 24 // #18
+0047f2: 1302 1401                              |042d: const/16 v2, #int 276 // #114
+0047f6: 4b02 0001                              |042f: aput v2, v0, v1
+0047fa: 1301 1900                              |0431: const/16 v1, #int 25 // #19
+0047fe: 1302 2c01                              |0433: const/16 v2, #int 300 // #12c
+004802: 4b02 0001                              |0435: aput v2, v0, v1
+004806: 1301 1a00                              |0437: const/16 v1, #int 26 // #1a
+00480a: 1302 4501                              |0439: const/16 v2, #int 325 // #145
+00480e: 4b02 0001                              |043b: aput v2, v0, v1
+004812: 1301 1b00                              |043d: const/16 v1, #int 27 // #1b
+004816: 1302 5f01                              |043f: const/16 v2, #int 351 // #15f
+00481a: 4b02 0001                              |0441: aput v2, v0, v1
+00481e: 1301 1c00                              |0443: const/16 v1, #int 28 // #1c
+004822: 1302 7a01                              |0445: const/16 v2, #int 378 // #17a
+004826: 4b02 0001                              |0447: aput v2, v0, v1
+00482a: 1301 1d00                              |0449: const/16 v1, #int 29 // #1d
+00482e: 1302 9601                              |044b: const/16 v2, #int 406 // #196
+004832: 4b02 0001                              |044d: aput v2, v0, v1
+004836: 1301 1e00                              |044f: const/16 v1, #int 30 // #1e
+00483a: 1302 b301                              |0451: const/16 v2, #int 435 // #1b3
+00483e: 4b02 0001                              |0453: aput v2, v0, v1
+004842: 1301 1f00                              |0455: const/16 v1, #int 31 // #1f
+004846: 1302 d101                              |0457: const/16 v2, #int 465 // #1d1
+00484a: 4b02 0001                              |0459: aput v2, v0, v1
+00484e: 6900 3800                              |045b: sput-object v0, Lcom/google/android/checkers/a;.L:[I // field@0038
+004852: 1300 8100                              |045d: const/16 v0, #int 129 // #81
+004856: 2300 3700                              |045f: new-array v0, v0, [I // type@0037
+00485a: 2600 0700 0000                         |0461: fill-array-data v0, 00000468 // +00000007
+004860: 6900 3900                              |0464: sput-object v0, Lcom/google/android/checkers/a;.M:[I // field@0039
+004864: 0e00                                   |0466: return-void
+004866: 0000                                   |0467: nop // spacer
+004868: 0003 0400 8100 0000 6745 68ba ff5c ... |0468: array-data (262 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #1              : (in Lcom/google/android/checkers/a;)
+      name          : '<init>'
+      type          : '(Lcom/google/android/checkers/CheckersView;)V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 7
+      ins           : 2
+      outs          : 1
+      insns size    : 94 16-bit code units
+004a74:                                        |[004a74] com.google.android.checkers.a.<init>:(Lcom/google/android/checkers/CheckersView;)V
+004a84: 1304 4000                              |0000: const/16 v4, #int 64 // #40
+004a88: 1203                                   |0002: const/4 v3, #int 0 // #0
+004a8a: 1302 0010                              |0003: const/16 v2, #int 4096 // #1000
+004a8e: 1200                                   |0005: const/4 v0, #int 0 // #0
+004a90: 7010 ad00 0500                         |0006: invoke-direct {v5}, Ljava/lang/Thread;.<init>:()V // method@00ad
+004a96: 1301 e803                              |0009: const/16 v1, #int 1000 // #3e8
+004a9a: 5951 4100                              |000b: iput v1, v5, Lcom/google/android/checkers/a;.h:I // field@0041
+004a9e: 2201 3300                              |000d: new-instance v1, Ljava/util/Random; // type@0033
+004aa2: 7010 af00 0100                         |000f: invoke-direct {v1}, Ljava/util/Random;.<init>:()V // method@00af
+004aa8: 5b51 4200                              |0012: iput-object v1, v5, Lcom/google/android/checkers/a;.i:Ljava/util/Random; // field@0042
+004aac: 5b56 4300                              |0014: iput-object v6, v5, Lcom/google/android/checkers/a;.j:Lcom/google/android/checkers/CheckersView; // field@0043
+004ab0: 5c50 4400                              |0016: iput-boolean v0, v5, Lcom/google/android/checkers/a;.k:Z // field@0044
+004ab4: 2321 3700                              |0018: new-array v1, v2, [I // type@0037
+004ab8: 5b51 4800                              |001a: iput-object v1, v5, Lcom/google/android/checkers/a;.o:[I // field@0048
+004abc: 2321 3700                              |001c: new-array v1, v2, [I // type@0037
+004ac0: 5b51 3a00                              |001e: iput-object v1, v5, Lcom/google/android/checkers/a;.a:[I // field@003a
+004ac4: 2321 3700                              |0020: new-array v1, v2, [I // type@0037
+004ac8: 5b51 4900                              |0022: iput-object v1, v5, Lcom/google/android/checkers/a;.p:[I // field@0049
+004acc: 2341 3700                              |0024: new-array v1, v4, [I // type@0037
+004ad0: 5b51 3b00                              |0026: iput-object v1, v5, Lcom/google/android/checkers/a;.b:[I // field@003b
+004ad4: 2341 3700                              |0028: new-array v1, v4, [I // type@0037
+004ad8: 5b51 4a00                              |002a: iput-object v1, v5, Lcom/google/android/checkers/a;.q:[I // field@004a
+004adc: 5c50 4c00                              |002c: iput-boolean v0, v5, Lcom/google/android/checkers/a;.s:Z // field@004c
+004ae0: 1501 1000                              |002e: const/high16 v1, #int 1048576 // #10
+004ae4: 2311 3700                              |0030: new-array v1, v1, [I // type@0037
+004ae8: 5b51 5200                              |0032: iput-object v1, v5, Lcom/google/android/checkers/a;.y:[I // field@0052
+004aec: 1501 1000                              |0034: const/high16 v1, #int 1048576 // #10
+004af0: 2311 3900                              |0036: new-array v1, v1, [S // type@0039
+004af4: 5b51 5300                              |0038: iput-object v1, v5, Lcom/google/android/checkers/a;.z:[S // field@0053
+004af8: 1501 1000                              |003a: const/high16 v1, #int 1048576 // #10
+004afc: 2311 3600                              |003c: new-array v1, v1, [B // type@0036
+004b00: 5b51 2d00                              |003e: iput-object v1, v5, Lcom/google/android/checkers/a;.A:[B // field@002d
+004b04: 5451 5200                              |0040: iget-object v1, v5, Lcom/google/android/checkers/a;.y:[I // field@0052
+004b08: 3801 0b00                              |0042: if-eqz v1, 004d // +000b
+004b0c: 5451 5300                              |0044: iget-object v1, v5, Lcom/google/android/checkers/a;.z:[S // field@0053
+004b10: 3801 0700                              |0046: if-eqz v1, 004d // +0007
+004b14: 5451 2d00                              |0048: iget-object v1, v5, Lcom/google/android/checkers/a;.A:[B // field@002d
+004b18: 3801 0300                              |004a: if-eqz v1, 004d // +0003
+004b1c: 1210                                   |004c: const/4 v0, #int 1 // #1
+004b1e: 5c50 2e00                              |004d: iput-boolean v0, v5, Lcom/google/android/checkers/a;.B:Z // field@002e
+004b22: 6e10 7b00 0500                         |004f: invoke-virtual {v5}, Lcom/google/android/checkers/a;.a:()V // method@007b
+004b28: 6e10 8e00 0500                         |0052: invoke-virtual {v5}, Lcom/google/android/checkers/a;.start:()V // method@008e
+004b2e: 0e00                                   |0055: return-void
+004b30: 0d01                                   |0056: move-exception v1
+004b32: 5b53 5200                              |0057: iput-object v3, v5, Lcom/google/android/checkers/a;.y:[I // field@0052
+004b36: 5b53 5300                              |0059: iput-object v3, v5, Lcom/google/android/checkers/a;.z:[S // field@0053
+004b3a: 5b53 2d00                              |005b: iput-object v3, v5, Lcom/google/android/checkers/a;.A:[B // field@002d
+004b3e: 28e3                                   |005d: goto 0040 // -001d
+      catches       : 1
+        0x0030 - 0x0040
+          Ljava/lang/Exception; -> 0x0056
+      positions     : 
+      locals        : 
+
+    #2              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(II)I'
+      access        : 0x001a (PRIVATE STATIC FINAL)
+      code          -
+      registers     : 3
+      ins           : 2
+      outs          : 0
+      insns size    : 14 16-bit code units
+004b4c:                                        |[004b4c] com.google.android.checkers.a.a:(II)I
+004b5c: 3d01 0600                              |0000: if-lez v1, 0006 // +0006
+004b60: d010 757e                              |0002: add-int/lit16 v0, v1, #int 32373 // #7e75
+004b64: b120                                   |0004: sub-int/2addr v0, v2
+004b66: 0f00                                   |0005: return v0
+004b68: 3b01 0600                              |0006: if-gez v1, 000c // +0006
+004b6c: d010 8b81                              |0008: add-int/lit16 v0, v1, #int -32373 // #818b
+004b70: b020                                   |000a: add-int/2addr v0, v2
+004b72: 28fa                                   |000b: goto 0005 // -0006
+004b74: 1200                                   |000c: const/4 v0, #int 0 // #0
+004b76: 28f8                                   |000d: goto 0005 // -0008
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #3              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IIIIIZ)I'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 31
+      ins           : 7
+      outs          : 7
+      insns size    : 1296 16-bit code units
+004b78:                                        |[004b78] com.google.android.checkers.a.a:(IIIIIZ)I
+004b88: 0800 1800                              |0000: move-object/from16 v0, v24
+004b8c: 5203 2f00                              |0002: iget v3, v0, Lcom/google/android/checkers/a;.C:I // field@002f
+004b90: d803 0301                              |0004: add-int/lit8 v3, v3, #int 1 // #01
+004b94: 0800 1800                              |0006: move-object/from16 v0, v24
+004b98: 5903 2f00                              |0008: iput v3, v0, Lcom/google/android/checkers/a;.C:I // field@002f
+004b9c: 0800 1800                              |000a: move-object/from16 v0, v24
+004ba0: 5203 4f00                              |000c: iget v3, v0, Lcom/google/android/checkers/a;.v:I // field@004f
+004ba4: 3803 0800                              |000e: if-eqz v3, 0016 // +0008
+004ba8: 0800 1800                              |0010: move-object/from16 v0, v24
+004bac: 5203 5000                              |0012: iget v3, v0, Lcom/google/android/checkers/a;.w:I // field@0050
+004bb0: 3903 0700                              |0014: if-nez v3, 001b // +0007
+004bb4: 0200 1b00                              |0016: move/from16 v0, v27
+004bb8: d004 0c81                              |0018: add-int/lit16 v4, v0, #int -32500 // #810c
+004bbc: 0f04                                   |001a: return v4
+004bbe: 0800 1800                              |001b: move-object/from16 v0, v24
+004bc2: 5503 4e00                              |001d: iget-boolean v3, v0, Lcom/google/android/checkers/a;.u:Z // field@004e
+004bc6: 3803 0e00                              |001f: if-eqz v3, 002d // +000e
+004bca: 0800 1800                              |0021: move-object/from16 v0, v24
+004bce: 5203 4f00                              |0023: iget v3, v0, Lcom/google/android/checkers/a;.v:I // field@004f
+004bd2: 0800 1800                              |0025: move-object/from16 v0, v24
+004bd6: 5204 5000                              |0027: iget v4, v0, Lcom/google/android/checkers/a;.w:I // field@0050
+004bda: b043                                   |0029: add-int/2addr v3, v4
+004bdc: 2b03 c004 0000                         |002a: packed-switch v3, 000004ea // +000004c0
+004be2: 1303 4000                              |002d: const/16 v3, #int 64 // #40
+004be6: 0200 1c00                              |002f: move/from16 v0, v28
+004bea: 3530 b404                              |0031: if-ge v0, v3, 04e5 // +04b4
+004bee: 1303 6400                              |0033: const/16 v3, #int 100 // #64
+004bf2: 0200 1d00                              |0035: move/from16 v0, v29
+004bf6: 3430 ae04                              |0037: if-lt v0, v3, 04e5 // +04ae
+004bfa: d81d 1d9c                              |0039: add-int/lit8 v29, v29, #int -100 // #9c
+004bfe: d81c 1c01                              |003b: add-int/lit8 v28, v28, #int 1 // #01
+004c02: 0207 1c00                              |003d: move/from16 v7, v28
+004c06: 0200 1b00                              |003f: move/from16 v0, v27
+004c0a: 3570 8103                              |0041: if-ge v0, v7, 03c2 // +0381
+004c0e: 0800 1800                              |0043: move-object/from16 v0, v24
+004c12: 5503 2e00                              |0045: iget-boolean v3, v0, Lcom/google/android/checkers/a;.B:Z // field@002e
+004c16: 3803 3400                              |0047: if-eqz v3, 007b // +0034
+004c1a: 0800 1800                              |0049: move-object/from16 v0, v24
+004c1e: 5203 5100                              |004b: iget v3, v0, Lcom/google/android/checkers/a;.x:I // field@0051
+004c22: 1404 ffff 0f00                         |004d: const v4, #float 0.000000 // #000fffff
+004c28: b534                                   |0050: and-int/2addr v4, v3
+004c2a: 0800 1800                              |0051: move-object/from16 v0, v24
+004c2e: 5405 5200                              |0053: iget-object v5, v0, Lcom/google/android/checkers/a;.y:[I // field@0052
+004c32: 4405 0504                              |0055: aget v5, v5, v4
+004c36: 3335 d702                              |0057: if-ne v5, v3, 032e // +02d7
+004c3a: 0800 1800                              |0059: move-object/from16 v0, v24
+004c3e: 5403 2d00                              |005b: iget-object v3, v0, Lcom/google/android/checkers/a;.A:[B // field@002d
+004c42: 4803 0304                              |005d: aget-byte v3, v3, v4
+004c46: dd03 033f                              |005f: and-int/lit8 v3, v3, #int 63 // #3f
+004c4a: 9105 071b                              |0061: sub-int v5, v7, v27
+004c4e: 3453 cb02                              |0063: if-lt v3, v5, 032e // +02cb
+004c52: 0800 1800                              |0065: move-object/from16 v0, v24
+004c56: 5403 2d00                              |0067: iget-object v3, v0, Lcom/google/android/checkers/a;.A:[B // field@002d
+004c5a: 4803 0304                              |0069: aget-byte v3, v3, v4
+004c5e: d533 c000                              |006b: and-int/lit16 v3, v3, #int 192 // #00c0
+004c62: 0800 1800                              |006d: move-object/from16 v0, v24
+004c66: 5405 5300                              |006f: iget-object v5, v0, Lcom/google/android/checkers/a;.z:[S // field@0053
+004c6a: 4a04 0504                              |0071: aget-short v4, v5, v4
+004c6e: 2c03 8104 0000                         |0073: sparse-switch v3, 000004f4 // +00000481
+004c74: 1403 3f42 0f00                         |0076: const v3, #float 0.000000 // #000f423f
+004c7a: 3334 a1ff                              |0079: if-ne v4, v3, 001a // -005f
+004c7e: 0800 1800                              |007b: move-object/from16 v0, v24
+004c82: 0201 1b00                              |007d: move/from16 v1, v27
+004c86: 0202 1e00                              |007f: move/from16 v2, v30
+004c8a: 7030 7500 1002                         |0081: invoke-direct {v0, v1, v2}, Lcom/google/android/checkers/a;.a:(IZ)I // method@0075
+004c90: 0a03                                   |0084: move-result v3
+004c92: 2b03 7904 0000                         |0085: packed-switch v3, 000004fe // +00000479
+004c98: 0800 1800                              |0088: move-object/from16 v0, v24
+004c9c: 520d 3c00                              |008a: iget v13, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+004ca0: 0800 1800                              |008c: move-object/from16 v0, v24
+004ca4: 520e 4b00                              |008e: iget v14, v0, Lcom/google/android/checkers/a;.r:I // field@004b
+004ca8: 0800 1800                              |0090: move-object/from16 v0, v24
+004cac: 520f 3d00                              |0092: iget v15, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004cb0: 0800 1800                              |0094: move-object/from16 v0, v24
+004cb4: 5200 3e00                              |0096: iget v0, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004cb8: 0210 0000                              |0098: move/from16 v16, v0
+004cbc: 0800 1800                              |009a: move-object/from16 v0, v24
+004cc0: 5200 3f00                              |009c: iget v0, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004cc4: 0211 0000                              |009e: move/from16 v17, v0
+004cc8: 0800 1800                              |00a0: move-object/from16 v0, v24
+004ccc: 5200 4000                              |00a2: iget v0, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004cd0: 0212 0000                              |00a4: move/from16 v18, v0
+004cd4: 0800 1800                              |00a6: move-object/from16 v0, v24
+004cd8: 5200 4f00                              |00a8: iget v0, v0, Lcom/google/android/checkers/a;.v:I // field@004f
+004cdc: 0213 0000                              |00aa: move/from16 v19, v0
+004ce0: 0800 1800                              |00ac: move-object/from16 v0, v24
+004ce4: 5200 5000                              |00ae: iget v0, v0, Lcom/google/android/checkers/a;.w:I // field@0050
+004ce8: 0214 0000                              |00b0: move/from16 v20, v0
+004cec: 0800 1800                              |00b2: move-object/from16 v0, v24
+004cf0: 5200 5100                              |00b4: iget v0, v0, Lcom/google/android/checkers/a;.x:I // field@0051
+004cf4: 0215 0000                              |00b6: move/from16 v21, v0
+004cf8: 2b0d 4e04 0000                         |00b8: packed-switch v13, 00000506 // +0000044e
+004cfe: 1208                                   |00bb: const/4 v8, #int 0 // #0
+004d00: 130a 4000                              |00bc: const/16 v10, #int 64 // #40
+004d04: 1203                                   |00be: const/4 v3, #int 0 // #0
+004d06: 013c                                   |00bf: move v12, v3
+004d08: 020b 1900                              |00c0: move/from16 v11, v25
+004d0c: 34dc 9602                              |00c2: if-lt v12, v13, 0358 // +0296
+004d10: 0800 1800                              |00c4: move-object/from16 v0, v24
+004d14: 5503 2e00                              |00c6: iget-boolean v3, v0, Lcom/google/android/checkers/a;.B:Z // field@002e
+004d18: 3803 0900                              |00c8: if-eqz v3, 00d1 // +0009
+004d1c: 0800 1800                              |00ca: move-object/from16 v0, v24
+004d20: 0201 1b00                              |00cc: move/from16 v1, v27
+004d24: 705b 7d00 10a7                         |00ce: invoke-direct {v0, v1, v7, v10, v11}, Lcom/google/android/checkers/a;.a:(IIII)V // method@007d
+004d2a: 01b4                                   |00d1: move v4, v11
+004d2c: 2900 48ff                              |00d2: goto/16 001a // -00b8
+004d30: 0800 1800                              |00d4: move-object/from16 v0, v24
+004d34: 5203 3d00                              |00d6: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004d38: 3803 3800                              |00d8: if-eqz v3, 0110 // +0038
+004d3c: 0800 1800                              |00da: move-object/from16 v0, v24
+004d40: 5203 3f00                              |00dc: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004d44: 3803 3200                              |00de: if-eqz v3, 0110 // +0032
+004d48: 0800 1800                              |00e0: move-object/from16 v0, v24
+004d4c: 5203 3d00                              |00e2: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004d50: 0800 1800                              |00e4: move-object/from16 v0, v24
+004d54: 5205 3f00                              |00e6: iget v5, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004d58: 381e 1b00                              |00e8: if-eqz v30, 0103 // +001b
+004d5c: 7110 9f00 0300                         |00ea: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004d62: 0a04                                   |00ed: move-result v4
+004d64: 7110 9f00 0500                         |00ee: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004d6a: 0a03                                   |00f1: move-result v3
+004d6c: d803 03fc                              |00f2: add-int/lit8 v3, v3, #int -4 // #fc
+004d70: 6205 5c00                              |00f4: sget-object v5, Lcom/google/android/checkers/g;.d:[B // field@005c
+004d74: da03 031c                              |00f6: mul-int/lit8 v3, v3, #int 28 // #1c
+004d78: b043                                   |00f8: add-int/2addr v3, v4
+004d7a: 4803 0503                              |00f9: aget-byte v3, v5, v3
+004d7e: 0200 1b00                              |00fb: move/from16 v0, v27
+004d82: 7120 7300 0300                         |00fd: invoke-static {v3, v0}, Lcom/google/android/checkers/a;.a:(II)I // method@0073
+004d88: 0a04                                   |0100: move-result v4
+004d8a: 2900 19ff                              |0101: goto/16 001a // -00e7
+004d8e: 7110 9f00 0500                         |0103: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004d94: 0a04                                   |0106: move-result v4
+004d96: d904 041f                              |0107: rsub-int/lit8 v4, v4, #int 31 // #1f
+004d9a: 7110 9f00 0300                         |0109: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004da0: 0a03                                   |010c: move-result v3
+004da2: d903 031f                              |010d: rsub-int/lit8 v3, v3, #int 31 // #1f
+004da6: 28e3                                   |010f: goto 00f2 // -001d
+004da8: 0800 1800                              |0110: move-object/from16 v0, v24
+004dac: 5203 3f00                              |0112: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004db0: 3803 1200                              |0114: if-eqz v3, 0126 // +0012
+004db4: 0800 1800                              |0116: move-object/from16 v0, v24
+004db8: 5203 3e00                              |0118: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004dbc: 0800 1800                              |011a: move-object/from16 v0, v24
+004dc0: 5204 3f00                              |011c: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004dc4: 1205                                   |011e: const/4 v5, #int 0 // #0
+004dc6: 0200 1e00                              |011f: move/from16 v0, v30
+004dca: 7140 7900 3054                         |0121: invoke-static {v0, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(ZIIZ)I // method@0079
+004dd0: 0a03                                   |0124: move-result v3
+004dd2: 28d6                                   |0125: goto 00fb // -002a
+004dd4: 0800 1800                              |0126: move-object/from16 v0, v24
+004dd8: 5203 3d00                              |0128: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004ddc: 3803 1500                              |012a: if-eqz v3, 013f // +0015
+004de0: 381e 1100                              |012c: if-eqz v30, 013d // +0011
+004de4: 1203                                   |012e: const/4 v3, #int 0 // #0
+004de6: 0800 1800                              |012f: move-object/from16 v0, v24
+004dea: 5204 4000                              |0131: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004dee: 0800 1800                              |0133: move-object/from16 v0, v24
+004df2: 5205 3d00                              |0135: iget v5, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004df6: 1216                                   |0137: const/4 v6, #int 1 // #1
+004df8: 7140 7900 4365                         |0138: invoke-static {v3, v4, v5, v6}, Lcom/google/android/checkers/a;.a:(ZIIZ)I // method@0079
+004dfe: 0a03                                   |013b: move-result v3
+004e00: 28bf                                   |013c: goto 00fb // -0041
+004e02: 1213                                   |013d: const/4 v3, #int 1 // #1
+004e04: 28f1                                   |013e: goto 012f // -000f
+004e06: 0800 1800                              |013f: move-object/from16 v0, v24
+004e0a: 5203 3e00                              |0141: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004e0e: 0800 1800                              |0143: move-object/from16 v0, v24
+004e12: 5205 4000                              |0145: iget v5, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004e16: 381e 1a00                              |0147: if-eqz v30, 0161 // +001a
+004e1a: 7110 9f00 0300                         |0149: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004e20: 0a04                                   |014c: move-result v4
+004e22: 7110 9f00 0500                         |014d: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004e28: 0a03                                   |0150: move-result v3
+004e2a: 1305 1000                              |0151: const/16 v5, #int 16 // #10
+004e2e: 3454 0600                              |0153: if-lt v4, v5, 0159 // +0006
+004e32: d904 041f                              |0155: rsub-int/lit8 v4, v4, #int 31 // #1f
+004e36: d903 031f                              |0157: rsub-int/lit8 v3, v3, #int 31 // #1f
+004e3a: 6205 5900                              |0159: sget-object v5, Lcom/google/android/checkers/g;.a:[B // field@0059
+004e3e: da03 0310                              |015b: mul-int/lit8 v3, v3, #int 16 // #10
+004e42: b043                                   |015d: add-int/2addr v3, v4
+004e44: 4803 0503                              |015e: aget-byte v3, v5, v3
+004e48: 289b                                   |0160: goto 00fb // -0065
+004e4a: 7110 9f00 0500                         |0161: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004e50: 0a04                                   |0164: move-result v4
+004e52: 7110 9f00 0300                         |0165: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+004e58: 0a03                                   |0168: move-result v3
+004e5a: 28e8                                   |0169: goto 0151 // -0018
+004e5c: 0800 1800                              |016a: move-object/from16 v0, v24
+004e60: 5203 4f00                              |016c: iget v3, v0, Lcom/google/android/checkers/a;.v:I // field@004f
+004e64: 1214                                   |016e: const/4 v4, #int 1 // #1
+004e66: 3343 a000                              |016f: if-ne v3, v4, 020f // +00a0
+004e6a: 0800 1800                              |0171: move-object/from16 v0, v24
+004e6e: 5203 3d00                              |0173: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004e72: 3803 5200                              |0175: if-eqz v3, 01c7 // +0052
+004e76: 0800 1800                              |0177: move-object/from16 v0, v24
+004e7a: 5203 4000                              |0179: iget v3, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004e7e: 3903 1c00                              |017b: if-nez v3, 0197 // +001c
+004e82: 381e 1800                              |017d: if-eqz v30, 0195 // +0018
+004e86: 1203                                   |017f: const/4 v3, #int 0 // #0
+004e88: 0800 1800                              |0180: move-object/from16 v0, v24
+004e8c: 5204 3f00                              |0182: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004e90: 0800 1800                              |0184: move-object/from16 v0, v24
+004e94: 5205 3d00                              |0186: iget v5, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004e98: 1216                                   |0188: const/4 v6, #int 1 // #1
+004e9a: 7140 8c00 4365                         |0189: invoke-static {v3, v4, v5, v6}, Lcom/google/android/checkers/a;.d:(ZIIZ)I // method@008c
+004ea0: 0a03                                   |018c: move-result v3
+004ea2: 0200 1b00                              |018d: move/from16 v0, v27
+004ea6: 7120 7300 0300                         |018f: invoke-static {v3, v0}, Lcom/google/android/checkers/a;.a:(II)I // method@0073
+004eac: 0a04                                   |0192: move-result v4
+004eae: 2900 87fe                              |0193: goto/16 001a // -0179
+004eb2: 1213                                   |0195: const/4 v3, #int 1 // #1
+004eb4: 28ea                                   |0196: goto 0180 // -0016
+004eb6: 0800 1800                              |0197: move-object/from16 v0, v24
+004eba: 5203 3f00                              |0199: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004ebe: 3803 1900                              |019b: if-eqz v3, 01b4 // +0019
+004ec2: 381e 1500                              |019d: if-eqz v30, 01b2 // +0015
+004ec6: 1203                                   |019f: const/4 v3, #int 0 // #0
+004ec8: 0800 1800                              |01a0: move-object/from16 v0, v24
+004ecc: 5204 3f00                              |01a2: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004ed0: 0800 1800                              |01a4: move-object/from16 v0, v24
+004ed4: 5205 4000                              |01a6: iget v5, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004ed8: 0800 1800                              |01a8: move-object/from16 v0, v24
+004edc: 5206 3d00                              |01aa: iget v6, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004ee0: 1217                                   |01ac: const/4 v7, #int 1 // #1
+004ee2: 7157 8200 4365                         |01ad: invoke-static {v3, v4, v5, v6, v7}, Lcom/google/android/checkers/a;.b:(ZIIIZ)I // method@0082
+004ee8: 0a03                                   |01b0: move-result v3
+004eea: 28dc                                   |01b1: goto 018d // -0024
+004eec: 1213                                   |01b2: const/4 v3, #int 1 // #1
+004eee: 28ed                                   |01b3: goto 01a0 // -0013
+004ef0: 381e 1100                              |01b4: if-eqz v30, 01c5 // +0011
+004ef4: 1203                                   |01b6: const/4 v3, #int 0 // #0
+004ef6: 0800 1800                              |01b7: move-object/from16 v0, v24
+004efa: 5204 4000                              |01b9: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004efe: 0800 1800                              |01bb: move-object/from16 v0, v24
+004f02: 5205 3d00                              |01bd: iget v5, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004f06: 1216                                   |01bf: const/4 v6, #int 1 // #1
+004f08: 7140 8300 4365                         |01c0: invoke-static {v3, v4, v5, v6}, Lcom/google/android/checkers/a;.b:(ZIIZ)I // method@0083
+004f0e: 0a03                                   |01c3: move-result v3
+004f10: 28c9                                   |01c4: goto 018d // -0037
+004f12: 1213                                   |01c5: const/4 v3, #int 1 // #1
+004f14: 28f1                                   |01c6: goto 01b7 // -000f
+004f16: 0800 1800                              |01c7: move-object/from16 v0, v24
+004f1a: 5203 4000                              |01c9: iget v3, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004f1e: 3903 1500                              |01cb: if-nez v3, 01e0 // +0015
+004f22: 381e 1100                              |01cd: if-eqz v30, 01de // +0011
+004f26: 1203                                   |01cf: const/4 v3, #int 0 // #0
+004f28: 0800 1800                              |01d0: move-object/from16 v0, v24
+004f2c: 5204 3f00                              |01d2: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004f30: 0800 1800                              |01d4: move-object/from16 v0, v24
+004f34: 5205 3e00                              |01d6: iget v5, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004f38: 1216                                   |01d8: const/4 v6, #int 1 // #1
+004f3a: 7140 8900 4365                         |01d9: invoke-static {v3, v4, v5, v6}, Lcom/google/android/checkers/a;.c:(ZIIZ)I // method@0089
+004f40: 0a03                                   |01dc: move-result v3
+004f42: 28b0                                   |01dd: goto 018d // -0050
+004f44: 1213                                   |01de: const/4 v3, #int 1 // #1
+004f46: 28f1                                   |01df: goto 01d0 // -000f
+004f48: 0800 1800                              |01e0: move-object/from16 v0, v24
+004f4c: 5203 3f00                              |01e2: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004f50: 3803 1900                              |01e4: if-eqz v3, 01fd // +0019
+004f54: 381e 1500                              |01e6: if-eqz v30, 01fb // +0015
+004f58: 1203                                   |01e8: const/4 v3, #int 0 // #0
+004f5a: 0800 1800                              |01e9: move-object/from16 v0, v24
+004f5e: 5204 3f00                              |01eb: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004f62: 0800 1800                              |01ed: move-object/from16 v0, v24
+004f66: 5205 4000                              |01ef: iget v5, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004f6a: 0800 1800                              |01f1: move-object/from16 v0, v24
+004f6e: 5206 3e00                              |01f3: iget v6, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004f72: 1217                                   |01f5: const/4 v7, #int 1 // #1
+004f74: 7157 7800 4365                         |01f6: invoke-static {v3, v4, v5, v6, v7}, Lcom/google/android/checkers/a;.a:(ZIIIZ)I // method@0078
+004f7a: 0a03                                   |01f9: move-result v3
+004f7c: 2893                                   |01fa: goto 018d // -006d
+004f7e: 1213                                   |01fb: const/4 v3, #int 1 // #1
+004f80: 28ed                                   |01fc: goto 01e9 // -0013
+004f82: 381e 1000                              |01fd: if-eqz v30, 020d // +0010
+004f86: 1203                                   |01ff: const/4 v3, #int 0 // #0
+004f88: 0800 1800                              |0200: move-object/from16 v0, v24
+004f8c: 5204 4000                              |0202: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+004f90: 0800 1800                              |0204: move-object/from16 v0, v24
+004f94: 5205 3e00                              |0206: iget v5, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004f98: 7130 7700 4305                         |0208: invoke-static {v3, v4, v5}, Lcom/google/android/checkers/a;.a:(ZII)I // method@0077
+004f9e: 0a03                                   |020b: move-result v3
+004fa0: 2881                                   |020c: goto 018d // -007f
+004fa2: 1213                                   |020d: const/4 v3, #int 1 // #1
+004fa4: 28f2                                   |020e: goto 0200 // -000e
+004fa6: 0800 1800                              |020f: move-object/from16 v0, v24
+004faa: 5203 3f00                              |0211: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004fae: 3803 4500                              |0213: if-eqz v3, 0258 // +0045
+004fb2: 0800 1800                              |0215: move-object/from16 v0, v24
+004fb6: 5203 3e00                              |0217: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004fba: 3903 1300                              |0219: if-nez v3, 022c // +0013
+004fbe: 0800 1800                              |021b: move-object/from16 v0, v24
+004fc2: 5203 3d00                              |021d: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004fc6: 0800 1800                              |021f: move-object/from16 v0, v24
+004fca: 5204 3f00                              |0221: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+004fce: 1205                                   |0223: const/4 v5, #int 0 // #0
+004fd0: 0200 1e00                              |0224: move/from16 v0, v30
+004fd4: 7140 8c00 3054                         |0226: invoke-static {v0, v3, v4, v5}, Lcom/google/android/checkers/a;.d:(ZIIZ)I // method@008c
+004fda: 0a03                                   |0229: move-result v3
+004fdc: 2900 63ff                              |022a: goto/16 018d // -009d
+004fe0: 0800 1800                              |022c: move-object/from16 v0, v24
+004fe4: 5203 3d00                              |022e: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004fe8: 3803 1700                              |0230: if-eqz v3, 0247 // +0017
+004fec: 0800 1800                              |0232: move-object/from16 v0, v24
+004ff0: 5203 3d00                              |0234: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+004ff4: 0800 1800                              |0236: move-object/from16 v0, v24
+004ff8: 5204 3e00                              |0238: iget v4, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+004ffc: 0800 1800                              |023a: move-object/from16 v0, v24
+005000: 5205 3f00                              |023c: iget v5, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+005004: 1206                                   |023e: const/4 v6, #int 0 // #0
+005006: 0200 1e00                              |023f: move/from16 v0, v30
+00500a: 7156 8200 3054                         |0241: invoke-static {v0, v3, v4, v5, v6}, Lcom/google/android/checkers/a;.b:(ZIIIZ)I // method@0082
+005010: 0a03                                   |0244: move-result v3
+005012: 2900 48ff                              |0245: goto/16 018d // -00b8
+005016: 0800 1800                              |0247: move-object/from16 v0, v24
+00501a: 5203 3e00                              |0249: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+00501e: 0800 1800                              |024b: move-object/from16 v0, v24
+005022: 5204 3f00                              |024d: iget v4, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+005026: 1205                                   |024f: const/4 v5, #int 0 // #0
+005028: 0200 1e00                              |0250: move/from16 v0, v30
+00502c: 7140 8300 3054                         |0252: invoke-static {v0, v3, v4, v5}, Lcom/google/android/checkers/a;.b:(ZIIZ)I // method@0083
+005032: 0a03                                   |0255: move-result v3
+005034: 2900 37ff                              |0256: goto/16 018d // -00c9
+005038: 0800 1800                              |0258: move-object/from16 v0, v24
+00503c: 5203 3e00                              |025a: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005040: 3903 1300                              |025c: if-nez v3, 026f // +0013
+005044: 0800 1800                              |025e: move-object/from16 v0, v24
+005048: 5203 3d00                              |0260: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+00504c: 0800 1800                              |0262: move-object/from16 v0, v24
+005050: 5204 4000                              |0264: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005054: 1205                                   |0266: const/4 v5, #int 0 // #0
+005056: 0200 1e00                              |0267: move/from16 v0, v30
+00505a: 7140 8900 3054                         |0269: invoke-static {v0, v3, v4, v5}, Lcom/google/android/checkers/a;.c:(ZIIZ)I // method@0089
+005060: 0a03                                   |026c: move-result v3
+005062: 2900 20ff                              |026d: goto/16 018d // -00e0
+005066: 0800 1800                              |026f: move-object/from16 v0, v24
+00506a: 5203 3d00                              |0271: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+00506e: 3803 1700                              |0273: if-eqz v3, 028a // +0017
+005072: 0800 1800                              |0275: move-object/from16 v0, v24
+005076: 5203 3d00                              |0277: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+00507a: 0800 1800                              |0279: move-object/from16 v0, v24
+00507e: 5204 3e00                              |027b: iget v4, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005082: 0800 1800                              |027d: move-object/from16 v0, v24
+005086: 5205 4000                              |027f: iget v5, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+00508a: 1206                                   |0281: const/4 v6, #int 0 // #0
+00508c: 0200 1e00                              |0282: move/from16 v0, v30
+005090: 7156 7800 3054                         |0284: invoke-static {v0, v3, v4, v5, v6}, Lcom/google/android/checkers/a;.a:(ZIIIZ)I // method@0078
+005096: 0a03                                   |0287: move-result v3
+005098: 2900 05ff                              |0288: goto/16 018d // -00fb
+00509c: 0800 1800                              |028a: move-object/from16 v0, v24
+0050a0: 5203 3e00                              |028c: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+0050a4: 0800 1800                              |028e: move-object/from16 v0, v24
+0050a8: 5204 4000                              |0290: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+0050ac: 0200 1e00                              |0292: move/from16 v0, v30
+0050b0: 7130 7700 3004                         |0294: invoke-static {v0, v3, v4}, Lcom/google/android/checkers/a;.a:(ZII)I // method@0077
+0050b6: 0a03                                   |0297: move-result v3
+0050b8: 2900 f5fe                              |0298: goto/16 018d // -010b
+0050bc: 0800 1800                              |029a: move-object/from16 v0, v24
+0050c0: 5203 4f00                              |029c: iget v3, v0, Lcom/google/android/checkers/a;.v:I // field@004f
+0050c4: 1224                                   |029e: const/4 v4, #int 2 // #2
+0050c6: 3343 8efd                              |029f: if-ne v3, v4, 002d // -0272
+0050ca: 0800 1800                              |02a1: move-object/from16 v0, v24
+0050ce: 5203 5000                              |02a3: iget v3, v0, Lcom/google/android/checkers/a;.w:I // field@0050
+0050d2: 1224                                   |02a5: const/4 v4, #int 2 // #2
+0050d4: 3343 87fd                              |02a6: if-ne v3, v4, 002d // -0279
+0050d8: 0800 1800                              |02a8: move-object/from16 v0, v24
+0050dc: 5203 3d00                              |02aa: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+0050e0: 3903 81fd                              |02ac: if-nez v3, 002d // -027f
+0050e4: 0800 1800                              |02ae: move-object/from16 v0, v24
+0050e8: 5203 3f00                              |02b0: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+0050ec: 3903 7bfd                              |02b2: if-nez v3, 002d // -0285
+0050f0: 0800 1800                              |02b4: move-object/from16 v0, v24
+0050f4: 5203 3e00                              |02b6: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+0050f8: 0800 1800                              |02b8: move-object/from16 v0, v24
+0050fc: 5207 4000                              |02ba: iget v7, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005100: 381e 4000                              |02bc: if-eqz v30, 02fc // +0040
+005104: 7110 9f00 0300                         |02be: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+00510a: 0a06                                   |02c1: move-result v6
+00510c: d804 03ff                              |02c2: add-int/lit8 v4, v3, #int -1 // #ff
+005110: b543                                   |02c4: and-int/2addr v3, v4
+005112: 7110 9f00 0300                         |02c5: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005118: 0a05                                   |02c8: move-result v5
+00511a: 7110 9f00 0700                         |02c9: invoke-static {v7}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005120: 0a04                                   |02cc: move-result v4
+005122: d803 07ff                              |02cd: add-int/lit8 v3, v7, #int -1 // #ff
+005126: b573                                   |02cf: and-int/2addr v3, v7
+005128: 7110 9f00 0300                         |02d0: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+00512e: 0a03                                   |02d3: move-result v3
+005130: 0216 0300                              |02d4: move/from16 v22, v3
+005134: 0153                                   |02d6: move v3, v5
+005136: 0205 1600                              |02d7: move/from16 v5, v22
+00513a: 0217 0400                              |02d9: move/from16 v23, v4
+00513e: 0164                                   |02db: move v4, v6
+005140: 0206 1700                              |02dc: move/from16 v6, v23
+005144: 3534 3f00                              |02de: if-ge v4, v3, 031d // +003f
+005148: 6207 3800                              |02e0: sget-object v7, Lcom/google/android/checkers/a;.L:[I // field@0038
+00514c: 4403 0703                              |02e2: aget v3, v7, v3
+005150: b043                                   |02e4: add-int/2addr v3, v4
+005152: 0134                                   |02e5: move v4, v3
+005154: 3556 3e00                              |02e6: if-ge v6, v5, 0324 // +003e
+005158: 6203 3800                              |02e8: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+00515c: 4403 0305                              |02ea: aget v3, v3, v5
+005160: b063                                   |02ec: add-int/2addr v3, v6
+005162: 6205 6900                              |02ed: sget-object v5, Lcom/google/android/checkers/g;.q:[B // field@0069
+005166: d244 f001                              |02ef: mul-int/lit16 v4, v4, #int 496 // #01f0
+00516a: b043                                   |02f1: add-int/2addr v3, v4
+00516c: 4803 0503                              |02f2: aget-byte v3, v5, v3
+005170: 0200 1b00                              |02f4: move/from16 v0, v27
+005174: 7120 7300 0300                         |02f6: invoke-static {v3, v0}, Lcom/google/android/checkers/a;.a:(II)I // method@0073
+00517a: 0a04                                   |02f9: move-result v4
+00517c: 2900 20fd                              |02fa: goto/16 001a // -02e0
+005180: 7110 9f00 0700                         |02fc: invoke-static {v7}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005186: 0a06                                   |02ff: move-result v6
+005188: d804 07ff                              |0300: add-int/lit8 v4, v7, #int -1 // #ff
+00518c: b574                                   |0302: and-int/2addr v4, v7
+00518e: 7110 9f00 0400                         |0303: invoke-static {v4}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005194: 0a05                                   |0306: move-result v5
+005196: 7110 9f00 0300                         |0307: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+00519c: 0a04                                   |030a: move-result v4
+00519e: d807 03ff                              |030b: add-int/lit8 v7, v3, #int -1 // #ff
+0051a2: b573                                   |030d: and-int/2addr v3, v7
+0051a4: 7110 9f00 0300                         |030e: invoke-static {v3}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0051aa: 0a03                                   |0311: move-result v3
+0051ac: 0216 0300                              |0312: move/from16 v22, v3
+0051b0: 0153                                   |0314: move v3, v5
+0051b2: 0205 1600                              |0315: move/from16 v5, v22
+0051b6: 0217 0400                              |0317: move/from16 v23, v4
+0051ba: 0164                                   |0319: move v4, v6
+0051bc: 0206 1700                              |031a: move/from16 v6, v23
+0051c0: 28c2                                   |031c: goto 02de // -003e
+0051c2: 6207 3800                              |031d: sget-object v7, Lcom/google/android/checkers/a;.L:[I // field@0038
+0051c6: 4404 0704                              |031f: aget v4, v7, v4
+0051ca: b043                                   |0321: add-int/2addr v3, v4
+0051cc: 0134                                   |0322: move v4, v3
+0051ce: 28c3                                   |0323: goto 02e6 // -003d
+0051d0: 6203 3800                              |0324: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+0051d4: 4403 0306                              |0326: aget v3, v3, v6
+0051d8: b053                                   |0328: add-int/2addr v3, v5
+0051da: 28c4                                   |0329: goto 02ed // -003c
+0051dc: 0200 1900                              |032a: move/from16 v0, v25
+0051e0: 3704 4afd                              |032c: if-le v4, v0, 0076 // -02b6
+0051e4: 1404 3f42 0f00                         |032e: const v4, #float 0.000000 // #000f423f
+0051ea: 2900 45fd                              |0331: goto/16 0076 // -02bb
+0051ee: 0200 1a00                              |0333: move/from16 v0, v26
+0051f2: 3404 f9ff                              |0335: if-lt v4, v0, 032e // -0007
+0051f6: 2900 3ffd                              |0337: goto/16 0076 // -02c1
+0051fa: 0200 1b00                              |0339: move/from16 v0, v27
+0051fe: d004 0c81                              |033b: add-int/lit16 v4, v0, #int -32500 // #810c
+005202: 2900 ddfc                              |033d: goto/16 001a // -0323
+005206: 9103 071b                              |033f: sub-int v3, v7, v27
+00520a: 1214                                   |0341: const/4 v4, #int 1 // #1
+00520c: 3643 46fd                              |0342: if-gt v3, v4, 0088 // -02ba
+005210: 1303 4000                              |0344: const/16 v3, #int 64 // #40
+005214: 3537 42fd                              |0346: if-ge v7, v3, 0088 // -02be
+005218: d807 0701                              |0348: add-int/lit8 v7, v7, #int 1 // #01
+00521c: 2900 3efd                              |034a: goto/16 0088 // -02c2
+005220: d808 1d1e                              |034c: add-int/lit8 v8, v29, #int 30 // #1e
+005224: 2900 6efd                              |034e: goto/16 00bc // -0292
+005228: d808 1d0a                              |0350: add-int/lit8 v8, v29, #int 10 // #0a
+00522c: 2900 6afd                              |0352: goto/16 00bc // -0296
+005230: d808 1d05                              |0354: add-int/lit8 v8, v29, #int 5 // #05
+005234: 2900 66fd                              |0356: goto/16 00bc // -029a
+005238: 9003 0e0c                              |0358: add-int v3, v14, v12
+00523c: 0800 1800                              |035a: move-object/from16 v0, v24
+005240: 7020 8500 3000                         |035c: invoke-direct {v0, v3}, Lcom/google/android/checkers/a;.b:(I)V // method@0085
+005246: 0200 1a00                              |035f: move/from16 v0, v26
+00524a: 7b04                                   |0361: neg-int v4, v0
+00524c: 7bb5                                   |0362: neg-int v5, v11
+00524e: d806 1b01                              |0363: add-int/lit8 v6, v27, #int 1 // #01
+005252: 381e 3b00                              |0365: if-eqz v30, 03a0 // +003b
+005256: 1209                                   |0367: const/4 v9, #int 0 // #0
+005258: 0803 1800                              |0368: move-object/from16 v3, v24
+00525c: 7607 7400 0300                         |036a: invoke-direct/range {v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/a;.a:(IIIIIZ)I // method@0074
+005262: 0a03                                   |036d: move-result v3
+005264: 7b34                                   |036e: neg-int v4, v3
+005266: 0800 1800                              |036f: move-object/from16 v0, v24
+00526a: 590f 3d00                              |0371: iput v15, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+00526e: 0200 1000                              |0373: move/from16 v0, v16
+005272: 0801 1800                              |0375: move-object/from16 v1, v24
+005276: 5910 3e00                              |0377: iput v0, v1, Lcom/google/android/checkers/a;.e:I // field@003e
+00527a: 0200 1100                              |0379: move/from16 v0, v17
+00527e: 0801 1800                              |037b: move-object/from16 v1, v24
+005282: 5910 3f00                              |037d: iput v0, v1, Lcom/google/android/checkers/a;.f:I // field@003f
+005286: 0200 1200                              |037f: move/from16 v0, v18
+00528a: 0801 1800                              |0381: move-object/from16 v1, v24
+00528e: 5910 4000                              |0383: iput v0, v1, Lcom/google/android/checkers/a;.g:I // field@0040
+005292: 0200 1300                              |0385: move/from16 v0, v19
+005296: 0801 1800                              |0387: move-object/from16 v1, v24
+00529a: 5910 4f00                              |0389: iput v0, v1, Lcom/google/android/checkers/a;.v:I // field@004f
+00529e: 0200 1400                              |038b: move/from16 v0, v20
+0052a2: 0801 1800                              |038d: move-object/from16 v1, v24
+0052a6: 5910 5000                              |038f: iput v0, v1, Lcom/google/android/checkers/a;.w:I // field@0050
+0052aa: 0200 1500                              |0391: move/from16 v0, v21
+0052ae: 0801 1800                              |0393: move-object/from16 v1, v24
+0052b2: 5910 5100                              |0395: iput v0, v1, Lcom/google/android/checkers/a;.x:I // field@0051
+0052b6: 0800 1800                              |0397: move-object/from16 v0, v24
+0052ba: 5503 4600                              |0399: iget-boolean v3, v0, Lcom/google/android/checkers/a;.m:Z // field@0046
+0052be: 3803 0700                              |039b: if-eqz v3, 03a2 // +0007
+0052c2: 1204                                   |039d: const/4 v4, #int 0 // #0
+0052c4: 2900 7cfc                              |039e: goto/16 001a // -0384
+0052c8: 1219                                   |03a0: const/4 v9, #int 1 // #1
+0052ca: 28c7                                   |03a1: goto 0368 // -0039
+0052cc: 37b4 3f01                              |03a2: if-le v4, v11, 04e1 // +013f
+0052d0: 0200 1a00                              |03a4: move/from16 v0, v26
+0052d4: 3404 1300                              |03a6: if-lt v4, v0, 03b9 // +0013
+0052d8: 0800 1800                              |03a8: move-object/from16 v0, v24
+0052dc: 5503 2e00                              |03aa: iget-boolean v3, v0, Lcom/google/android/checkers/a;.B:Z // field@002e
+0052e0: 3803 6efc                              |03ac: if-eqz v3, 001a // -0392
+0052e4: 1303 8000                              |03ae: const/16 v3, #int 128 // #80
+0052e8: 0800 1800                              |03b0: move-object/from16 v0, v24
+0052ec: 0201 1b00                              |03b2: move/from16 v1, v27
+0052f0: 7054 7d00 1037                         |03b4: invoke-direct {v0, v1, v7, v3, v4}, Lcom/google/android/checkers/a;.a:(IIII)V // method@007d
+0052f6: 2900 63fc                              |03b7: goto/16 001a // -039d
+0052fa: 1303 c000                              |03b9: const/16 v3, #int 192 // #c0
+0052fe: d805 0c01                              |03bb: add-int/lit8 v5, v12, #int 1 // #01
+005302: 015c                                   |03bd: move v12, v5
+005304: 013a                                   |03be: move v10, v3
+005306: 014b                                   |03bf: move v11, v4
+005308: 2900 02fd                              |03c0: goto/16 00c2 // -02fe
+00530c: 0800 1800                              |03c2: move-object/from16 v0, v24
+005310: 5203 4700                              |03c4: iget v3, v0, Lcom/google/android/checkers/a;.n:I // field@0047
+005314: d804 0301                              |03c6: add-int/lit8 v4, v3, #int 1 // #01
+005318: 0800 1800                              |03c8: move-object/from16 v0, v24
+00531c: 5904 4700                              |03ca: iput v4, v0, Lcom/google/android/checkers/a;.n:I // field@0047
+005320: 1304 8813                              |03cc: const/16 v4, #int 5000 // #1388
+005324: 3743 2100                              |03ce: if-le v3, v4, 03ef // +0021
+005328: 1203                                   |03d0: const/4 v3, #int 0 // #0
+00532a: 0800 1800                              |03d1: move-object/from16 v0, v24
+00532e: 5903 4700                              |03d3: iput v3, v0, Lcom/google/android/checkers/a;.n:I // field@0047
+005332: 7100 ab00 0000                         |03d5: invoke-static {}, Ljava/lang/System;.currentTimeMillis:()J // method@00ab
+005338: 0b03                                   |03d8: move-result-wide v3
+00533a: 0800 1800                              |03d9: move-object/from16 v0, v24
+00533e: 5305 4500                              |03db: iget-wide v5, v0, Lcom/google/android/checkers/a;.l:J // field@0045
+005342: 0800 1800                              |03dd: move-object/from16 v0, v24
+005346: 5207 4100                              |03df: iget v7, v0, Lcom/google/android/checkers/a;.h:I // field@0041
+00534a: 8177                                   |03e1: int-to-long v7, v7
+00534c: bb75                                   |03e2: add-long/2addr v5, v7
+00534e: 3103 0305                              |03e3: cmp-long v3, v3, v5
+005352: 3d03 0a00                              |03e5: if-lez v3, 03ef // +000a
+005356: 1213                                   |03e7: const/4 v3, #int 1 // #1
+005358: 0800 1800                              |03e8: move-object/from16 v0, v24
+00535c: 5c03 4600                              |03ea: iput-boolean v3, v0, Lcom/google/android/checkers/a;.m:Z // field@0046
+005360: 1204                                   |03ec: const/4 v4, #int 0 // #0
+005362: 2900 2dfc                              |03ed: goto/16 001a // -03d3
+005366: 1204                                   |03ef: const/4 v4, #int 0 // #0
+005368: 0800 1800                              |03f0: move-object/from16 v0, v24
+00536c: 5203 3d00                              |03f2: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+005370: 3903 ad00                              |03f4: if-nez v3, 04a1 // +00ad
+005374: 0800 1800                              |03f6: move-object/from16 v0, v24
+005378: 5203 3e00                              |03f8: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+00537c: 0145                                   |03fa: move v5, v4
+00537e: 3903 ad00                              |03fb: if-nez v3, 04a8 // +00ad
+005382: 1204                                   |03fd: const/4 v4, #int 0 // #0
+005384: 0800 1800                              |03fe: move-object/from16 v0, v24
+005388: 5203 3f00                              |0400: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+00538c: 3903 ae00                              |0402: if-nez v3, 04b0 // +00ae
+005390: 0800 1800                              |0404: move-object/from16 v0, v24
+005394: 5203 4000                              |0406: iget v3, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005398: 3903 af00                              |0408: if-nez v3, 04b7 // +00af
+00539c: 3345 b400                              |040a: if-ne v5, v4, 04be // +00b4
+0053a0: 1203                                   |040c: const/4 v3, #int 0 // #0
+0053a2: 3545 bd00                              |040d: if-ge v5, v4, 04ca // +00bd
+0053a6: 0800 1800                              |040f: move-object/from16 v0, v24
+0053aa: 5204 3e00                              |0411: iget v4, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+0053ae: 1405 1100 0088                         |0413: const v5, #float -0.000000 // #88000011
+0053b4: b554                                   |0416: and-int/2addr v4, v5
+0053b6: 3804 0900                              |0417: if-eqz v4, 0420 // +0009
+0053ba: 7110 9e00 0400                         |0419: invoke-static {v4}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+0053c0: 0a04                                   |041c: move-result v4
+0053c2: e004 0403                              |041d: shl-int/lit8 v4, v4, #int 3 // #03
+0053c6: b043                                   |041f: add-int/2addr v3, v4
+0053c8: 0800 1800                              |0420: move-object/from16 v0, v24
+0053cc: 5204 3d00                              |0422: iget v4, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+0053d0: 0800 1800                              |0424: move-object/from16 v0, v24
+0053d4: 5205 3e00                              |0426: iget v5, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+0053d8: b654                                   |0428: or-int/2addr v4, v5
+0053da: 0800 1800                              |0429: move-object/from16 v0, v24
+0053de: 5205 3f00                              |042b: iget v5, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+0053e2: 0800 1800                              |042d: move-object/from16 v0, v24
+0053e6: 5206 4000                              |042f: iget v6, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+0053ea: b665                                   |0431: or-int/2addr v5, v6
+0053ec: 0800 1800                              |0432: move-object/from16 v0, v24
+0053f0: 5206 3f00                              |0434: iget v6, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+0053f4: 3806 0900                              |0436: if-eqz v6, 043f // +0009
+0053f8: dd06 0405                              |0438: and-int/lit8 v6, v4, #int 5 // #05
+0053fc: 1257                                   |043a: const/4 v7, #int 5 // #5
+0053fe: 3376 0400                              |043b: if-ne v6, v7, 043f // +0004
+005402: d803 030c                              |043d: add-int/lit8 v3, v3, #int 12 // #0c
+005406: 0800 1800                              |043f: move-object/from16 v0, v24
+00540a: 5206 3d00                              |0441: iget v6, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+00540e: 3806 0b00                              |0443: if-eqz v6, 044e // +000b
+005412: 1506 00a0                              |0445: const/high16 v6, #int -1610612736 // #a000
+005416: b556                                   |0447: and-int/2addr v6, v5
+005418: 1507 00a0                              |0448: const/high16 v7, #int -1610612736 // #a000
+00541c: 3376 0400                              |044a: if-ne v6, v7, 044e // +0004
+005420: d803 03f4                              |044c: add-int/lit8 v3, v3, #int -12 // #f4
+005424: 1406 0066 6600                         |044e: const v6, #float 0.000000 // #00666600
+00542a: b564                                   |0451: and-int/2addr v4, v6
+00542c: 7110 9e00 0400                         |0452: invoke-static {v4}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+005432: 0a04                                   |0455: move-result v4
+005434: 1406 0066 6600                         |0456: const v6, #float 0.000000 // #00666600
+00543a: b565                                   |0459: and-int/2addr v5, v6
+00543c: 7110 9e00 0500                         |045a: invoke-static {v5}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+005442: 0a05                                   |045d: move-result v5
+005444: b154                                   |045e: sub-int/2addr v4, v5
+005446: b043                                   |045f: add-int/2addr v3, v4
+005448: 0800 1800                              |0460: move-object/from16 v0, v24
+00544c: 5204 3d00                              |0462: iget v4, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+005450: 1405 1818 1818                         |0464: const v5, #float 0.000000 // #18181818
+005456: b554                                   |0467: and-int/2addr v4, v5
+005458: 7110 9e00 0400                         |0468: invoke-static {v4}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+00545e: 0a04                                   |046b: move-result v4
+005460: 0800 1800                              |046c: move-object/from16 v0, v24
+005464: 5205 3f00                              |046e: iget v5, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+005468: 1406 1818 1818                         |0470: const v6, #float 0.000000 // #18181818
+00546e: b565                                   |0473: and-int/2addr v5, v6
+005470: 7110 9e00 0500                         |0474: invoke-static {v5}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+005476: 0a05                                   |0477: move-result v5
+005478: b154                                   |0478: sub-int/2addr v4, v5
+00547a: b143                                   |0479: sub-int/2addr v3, v4
+00547c: 0800 1800                              |047a: move-object/from16 v0, v24
+005480: 5204 3e00                              |047c: iget v4, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005484: 1405 0800 0010                         |047e: const v5, #float 0.000000 // #10000008
+00548a: b554                                   |0481: and-int/2addr v4, v5
+00548c: 3804 0900                              |0482: if-eqz v4, 048b // +0009
+005490: 7110 9e00 0400                         |0484: invoke-static {v4}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+005496: 0a04                                   |0487: move-result v4
+005498: e004 0405                              |0488: shl-int/lit8 v4, v4, #int 5 // #05
+00549c: b143                                   |048a: sub-int/2addr v3, v4
+00549e: 0800 1800                              |048b: move-object/from16 v0, v24
+0054a2: 5204 4000                              |048d: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+0054a6: 1405 0800 0010                         |048f: const v5, #float 0.000000 // #10000008
+0054ac: b554                                   |0492: and-int/2addr v4, v5
+0054ae: 3804 4c00                              |0493: if-eqz v4, 04df // +004c
+0054b2: 7110 9e00 0400                         |0495: invoke-static {v4}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+0054b8: 0a04                                   |0498: move-result v4
+0054ba: e004 0405                              |0499: shl-int/lit8 v4, v4, #int 5 // #05
+0054be: b034                                   |049b: add-int/2addr v4, v3
+0054c0: 391e 7efb                              |049c: if-nez v30, 001a // -0482
+0054c4: 7b44                                   |049e: neg-int v4, v4
+0054c6: 2900 7bfb                              |049f: goto/16 001a // -0485
+0054ca: d804 0464                              |04a1: add-int/lit8 v4, v4, #int 100 // #64
+0054ce: d805 03ff                              |04a3: add-int/lit8 v5, v3, #int -1 // #ff
+0054d2: b553                                   |04a5: and-int/2addr v3, v5
+0054d4: 2900 4eff                              |04a6: goto/16 03f4 // -00b2
+0054d8: d054 8600                              |04a8: add-int/lit16 v4, v5, #int 134 // #0086
+0054dc: d805 03ff                              |04aa: add-int/lit8 v5, v3, #int -1 // #ff
+0054e0: b553                                   |04ac: and-int/2addr v3, v5
+0054e2: 0145                                   |04ad: move v5, v4
+0054e4: 2900 4dff                              |04ae: goto/16 03fb // -00b3
+0054e8: d804 0464                              |04b0: add-int/lit8 v4, v4, #int 100 // #64
+0054ec: d806 03ff                              |04b2: add-int/lit8 v6, v3, #int -1 // #ff
+0054f0: b563                                   |04b4: and-int/2addr v3, v6
+0054f2: 2900 4dff                              |04b5: goto/16 0402 // -00b3
+0054f6: d044 8600                              |04b7: add-int/lit16 v4, v4, #int 134 // #0086
+0054fa: d806 03ff                              |04b9: add-int/lit8 v6, v3, #int -1 // #ff
+0054fe: b563                                   |04bb: and-int/2addr v3, v6
+005500: 2900 4cff                              |04bc: goto/16 0408 // -00b4
+005504: 9103 0504                              |04be: sub-int v3, v5, v4
+005508: 9106 0504                              |04c0: sub-int v6, v5, v4
+00550c: e006 0608                              |04c2: shl-int/lit8 v6, v6, #int 8 // #08
+005510: 9007 0504                              |04c4: add-int v7, v5, v4
+005514: b376                                   |04c6: div-int/2addr v6, v7
+005516: b063                                   |04c7: add-int/2addr v3, v6
+005518: 2900 45ff                              |04c8: goto/16 040d // -00bb
+00551c: 3745 56ff                              |04ca: if-le v5, v4, 0420 // -00aa
+005520: 0800 1800                              |04cc: move-object/from16 v0, v24
+005524: 5204 4000                              |04ce: iget v4, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005528: 1405 1100 0088                         |04d0: const v5, #float -0.000000 // #88000011
+00552e: b554                                   |04d3: and-int/2addr v4, v5
+005530: 3804 4cff                              |04d4: if-eqz v4, 0420 // -00b4
+005534: 7110 9e00 0400                         |04d6: invoke-static {v4}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+00553a: 0a04                                   |04d9: move-result v4
+00553c: e004 0403                              |04da: shl-int/lit8 v4, v4, #int 3 // #03
+005540: b143                                   |04dc: sub-int/2addr v3, v4
+005542: 2900 43ff                              |04dd: goto/16 0420 // -00bd
+005546: 0134                                   |04df: move v4, v3
+005548: 28bc                                   |04e0: goto 049c // -0044
+00554a: 01a3                                   |04e1: move v3, v10
+00554c: 01b4                                   |04e2: move v4, v11
+00554e: 2900 d8fe                              |04e3: goto/16 03bb // -0128
+005552: 0207 1c00                              |04e5: move/from16 v7, v28
+005556: 2900 58fb                              |04e7: goto/16 003f // -04a8
+00555a: 0000                                   |04e9: nop // spacer
+00555c: 0001 0300 0200 0000 aa00 0000 4001 ... |04ea: packed-switch-data (10 units)
+005570: 0002 0200 4000 0000 8000 0000 b702 ... |04f4: sparse-switch-data (10 units)
+005584: 0001 0200 0000 0000 b402 0000 ba02 ... |04fe: packed-switch-data (8 units)
+005594: 0001 0300 0100 0000 9402 0000 9802 ... |0506: packed-switch-data (10 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #4              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IZ)I'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 7
+      ins           : 3
+      outs          : 4
+      insns size    : 55 16-bit code units
+0055a8:                                        |[0055a8] com.google.android.checkers.a.a:(IZ)I
+0055b8: 1221                                   |0000: const/4 v1, #int 2 // #2
+0055ba: 1200                                   |0001: const/4 v0, #int 0 // #0
+0055bc: 5940 3c00                              |0002: iput v0, v4, Lcom/google/android/checkers/a;.c:I // field@003c
+0055c0: da02 0540                              |0004: mul-int/lit8 v2, v5, #int 64 // #40
+0055c4: 5942 4b00                              |0006: iput v2, v4, Lcom/google/android/checkers/a;.r:I // field@004b
+0055c8: 5242 3d00                              |0008: iget v2, v4, Lcom/google/android/checkers/a;.d:I // field@003d
+0055cc: 5243 3e00                              |000a: iget v3, v4, Lcom/google/android/checkers/a;.e:I // field@003e
+0055d0: b632                                   |000c: or-int/2addr v2, v3
+0055d2: 5243 3f00                              |000d: iget v3, v4, Lcom/google/android/checkers/a;.f:I // field@003f
+0055d6: b632                                   |000f: or-int/2addr v2, v3
+0055d8: 5243 4000                              |0010: iget v3, v4, Lcom/google/android/checkers/a;.g:I // field@0040
+0055dc: b632                                   |0012: or-int/2addr v2, v3
+0055de: df02 02ff                              |0013: xor-int/lit8 v2, v2, #int -1 // #ff
+0055e2: 5543 4c00                              |0015: iget-boolean v3, v4, Lcom/google/android/checkers/a;.s:Z // field@004c
+0055e6: 3803 1000                              |0017: if-eqz v3, 0027 // +0010
+0055ea: 7040 8100 5426                         |0019: invoke-direct {v4, v5, v6, v2}, Lcom/google/android/checkers/a;.a:(IZI)Z // method@0081
+0055f0: 0a03                                   |001c: move-result v3
+0055f2: 7040 8800 5426                         |001d: invoke-direct {v4, v5, v6, v2}, Lcom/google/android/checkers/a;.b:(IZI)Z // method@0088
+0055f8: 0a02                                   |0020: move-result v2
+0055fa: 3903 0400                              |0021: if-nez v3, 0025 // +0004
+0055fe: 3802 0300                              |0023: if-eqz v2, 0026 // +0003
+005602: 0110                                   |0025: move v0, v1
+005604: 0f00                                   |0026: return v0
+005606: 7040 8100 5426                         |0027: invoke-direct {v4, v5, v6, v2}, Lcom/google/android/checkers/a;.a:(IZI)Z // method@0081
+00560c: 0a03                                   |002a: move-result v3
+00560e: 3803 0400                              |002b: if-eqz v3, 002f // +0004
+005612: 1210                                   |002d: const/4 v0, #int 1 // #1
+005614: 28f8                                   |002e: goto 0026 // -0008
+005616: 7040 8800 5426                         |002f: invoke-direct {v4, v5, v6, v2}, Lcom/google/android/checkers/a;.b:(IZI)Z // method@0088
+00561c: 0a02                                   |0032: move-result v2
+00561e: 3802 f3ff                              |0033: if-eqz v2, 0026 // -000d
+005622: 0110                                   |0035: move v0, v1
+005624: 28f0                                   |0036: goto 0026 // -0010
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #5              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(Z)I'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 7
+      ins           : 2
+      outs          : 1
+      insns size    : 98 16-bit code units
+005628:                                        |[005628] com.google.android.checkers.a.a:(Z)I
+005638: 3806 1700                              |0000: if-eqz v6, 0017 // +0017
+00563c: 1200                                   |0002: const/4 v0, #int 0 // #0
+00563e: 5251 3d00                              |0003: iget v1, v5, Lcom/google/android/checkers/a;.d:I // field@003d
+005642: 0114                                   |0005: move v4, v1
+005644: 0101                                   |0006: move v1, v0
+005646: 0140                                   |0007: move v0, v4
+005648: 3900 1600                              |0008: if-nez v0, 001e // +0016
+00564c: 5250 3e00                              |000a: iget v0, v5, Lcom/google/android/checkers/a;.e:I // field@003e
+005650: 3900 2300                              |000c: if-nez v0, 002f // +0023
+005654: 5250 3f00                              |000e: iget v0, v5, Lcom/google/android/checkers/a;.f:I // field@003f
+005658: 3900 3000                              |0010: if-nez v0, 0040 // +0030
+00565c: 5250 4000                              |0012: iget v0, v5, Lcom/google/android/checkers/a;.g:I // field@0040
+005660: 3900 3d00                              |0014: if-nez v0, 0051 // +003d
+005664: 0f01                                   |0016: return v1
+005666: 6200 3900                              |0017: sget-object v0, Lcom/google/android/checkers/a;.M:[I // field@0039
+00566a: 1301 8000                              |0019: const/16 v1, #int 128 // #80
+00566e: 4400 0001                              |001b: aget v0, v0, v1
+005672: 28e6                                   |001d: goto 0003 // -001a
+005674: 6202 3900                              |001e: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+005678: 7110 9f00 0000                         |0020: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+00567e: 0a03                                   |0023: move-result v3
+005680: da03 0304                              |0024: mul-int/lit8 v3, v3, #int 4 // #04
+005684: d803 0300                              |0026: add-int/lit8 v3, v3, #int 0 // #00
+005688: 4402 0203                              |0028: aget v2, v2, v3
+00568c: b721                                   |002a: xor-int/2addr v1, v2
+00568e: d802 00ff                              |002b: add-int/lit8 v2, v0, #int -1 // #ff
+005692: b520                                   |002d: and-int/2addr v0, v2
+005694: 28da                                   |002e: goto 0008 // -0026
+005696: 6202 3900                              |002f: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+00569a: 7110 9f00 0000                         |0031: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0056a0: 0a03                                   |0034: move-result v3
+0056a2: da03 0304                              |0035: mul-int/lit8 v3, v3, #int 4 // #04
+0056a6: d803 0301                              |0037: add-int/lit8 v3, v3, #int 1 // #01
+0056aa: 4402 0203                              |0039: aget v2, v2, v3
+0056ae: b721                                   |003b: xor-int/2addr v1, v2
+0056b0: d802 00ff                              |003c: add-int/lit8 v2, v0, #int -1 // #ff
+0056b4: b520                                   |003e: and-int/2addr v0, v2
+0056b6: 28cd                                   |003f: goto 000c // -0033
+0056b8: 6202 3900                              |0040: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+0056bc: 7110 9f00 0000                         |0042: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0056c2: 0a03                                   |0045: move-result v3
+0056c4: da03 0304                              |0046: mul-int/lit8 v3, v3, #int 4 // #04
+0056c8: d803 0302                              |0048: add-int/lit8 v3, v3, #int 2 // #02
+0056cc: 4402 0203                              |004a: aget v2, v2, v3
+0056d0: b721                                   |004c: xor-int/2addr v1, v2
+0056d2: d802 00ff                              |004d: add-int/lit8 v2, v0, #int -1 // #ff
+0056d6: b520                                   |004f: and-int/2addr v0, v2
+0056d8: 28c0                                   |0050: goto 0010 // -0040
+0056da: 6202 3900                              |0051: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+0056de: 7110 9f00 0000                         |0053: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0056e4: 0a03                                   |0056: move-result v3
+0056e6: da03 0304                              |0057: mul-int/lit8 v3, v3, #int 4 // #04
+0056ea: d803 0303                              |0059: add-int/lit8 v3, v3, #int 3 // #03
+0056ee: 4402 0203                              |005b: aget v2, v2, v3
+0056f2: b721                                   |005d: xor-int/2addr v1, v2
+0056f4: d802 00ff                              |005e: add-int/lit8 v2, v0, #int -1 // #ff
+0056f8: b520                                   |0060: and-int/2addr v0, v2
+0056fa: 28b3                                   |0061: goto 0014 // -004d
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #6              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(ZII)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 7
+      ins           : 3
+      outs          : 1
+      insns size    : 56 16-bit code units
+0056fc:                                        |[0056fc] com.google.android.checkers.a.a:(ZII)I
+00570c: 7110 9f00 0500                         |0000: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005712: 0a00                                   |0003: move-result v0
+005714: d801 05ff                              |0004: add-int/lit8 v1, v5, #int -1 // #ff
+005718: b551                                   |0006: and-int/2addr v1, v5
+00571a: 7110 9f00 0100                         |0007: invoke-static {v1}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005720: 0a02                                   |000a: move-result v2
+005722: 7110 9f00 0600                         |000b: invoke-static {v6}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005728: 0a01                                   |000e: move-result v1
+00572a: 1303 1000                              |000f: const/16 v3, #int 16 // #10
+00572e: 3431 0800                              |0011: if-lt v1, v3, 0019 // +0008
+005732: d900 001f                              |0013: rsub-int/lit8 v0, v0, #int 31 // #1f
+005736: d902 021f                              |0015: rsub-int/lit8 v2, v2, #int 31 // #1f
+00573a: d901 011f                              |0017: rsub-int/lit8 v1, v1, #int 31 // #1f
+00573e: 3520 1100                              |0019: if-ge v0, v2, 002a // +0011
+005742: 6203 3800                              |001b: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+005746: 4402 0302                              |001d: aget v2, v3, v2
+00574a: b020                                   |001f: add-int/2addr v0, v2
+00574c: 3804 1000                              |0020: if-eqz v4, 0030 // +0010
+005750: 6202 5d00                              |0022: sget-object v2, Lcom/google/android/checkers/g;.e:[B // field@005d
+005754: da00 0010                              |0024: mul-int/lit8 v0, v0, #int 16 // #10
+005758: b010                                   |0026: add-int/2addr v0, v1
+00575a: 4800 0200                              |0027: aget-byte v0, v2, v0
+00575e: 0f00                                   |0029: return v0
+005760: 6203 3800                              |002a: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+005764: 4400 0300                              |002c: aget v0, v3, v0
+005768: b020                                   |002e: add-int/2addr v0, v2
+00576a: 28f1                                   |002f: goto 0020 // -000f
+00576c: 6202 5e00                              |0030: sget-object v2, Lcom/google/android/checkers/g;.f:[B // field@005e
+005770: da00 0010                              |0032: mul-int/lit8 v0, v0, #int 16 // #10
+005774: b010                                   |0034: add-int/2addr v0, v1
+005776: 4800 0200                              |0035: aget-byte v0, v2, v0
+00577a: 28f2                                   |0037: goto 0029 // -000e
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #7              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(ZIIIZ)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 9
+      ins           : 5
+      outs          : 1
+      insns size    : 44 16-bit code units
+00577c:                                        |[00577c] com.google.android.checkers.a.a:(ZIIIZ)I
+00578c: 7110 9f00 0500                         |0000: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005792: 0a02                                   |0003: move-result v2
+005794: 7110 9f00 0600                         |0004: invoke-static {v6}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+00579a: 0a01                                   |0007: move-result v1
+00579c: 7110 9f00 0700                         |0008: invoke-static {v7}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0057a2: 0a00                                   |000b: move-result v0
+0057a4: 3808 0800                              |000c: if-eqz v8, 0014 // +0008
+0057a8: d902 021f                              |000e: rsub-int/lit8 v2, v2, #int 31 // #1f
+0057ac: d901 011f                              |0010: rsub-int/lit8 v1, v1, #int 31 // #1f
+0057b0: d900 001f                              |0012: rsub-int/lit8 v0, v0, #int 31 // #1f
+0057b4: 3804 0d00                              |0014: if-eqz v4, 0021 // +000d
+0057b8: 6203 6100                              |0016: sget-object v3, Lcom/google/android/checkers/g;.i:[B // field@0061
+0057bc: d222 0004                              |0018: mul-int/lit16 v2, v2, #int 1024 // #0400
+0057c0: da01 0120                              |001a: mul-int/lit8 v1, v1, #int 32 // #20
+0057c4: b021                                   |001c: add-int/2addr v1, v2
+0057c6: b010                                   |001d: add-int/2addr v0, v1
+0057c8: 4800 0300                              |001e: aget-byte v0, v3, v0
+0057cc: 0f00                                   |0020: return v0
+0057ce: 6203 6200                              |0021: sget-object v3, Lcom/google/android/checkers/g;.j:[B // field@0062
+0057d2: d222 0004                              |0023: mul-int/lit16 v2, v2, #int 1024 // #0400
+0057d6: da01 0120                              |0025: mul-int/lit8 v1, v1, #int 32 // #20
+0057da: b021                                   |0027: add-int/2addr v1, v2
+0057dc: b010                                   |0028: add-int/2addr v0, v1
+0057de: 4800 0300                              |0029: aget-byte v0, v3, v0
+0057e2: 28f5                                   |002b: goto 0020 // -000b
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #8              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(ZIIZ)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 7
+      ins           : 4
+      outs          : 1
+      insns size    : 34 16-bit code units
+0057e4:                                        |[0057e4] com.google.android.checkers.a.a:(ZIIZ)I
+0057f4: 7110 9f00 0400                         |0000: invoke-static {v4}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0057fa: 0a01                                   |0003: move-result v1
+0057fc: 7110 9f00 0500                         |0004: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005802: 0a00                                   |0007: move-result v0
+005804: 3806 0600                              |0008: if-eqz v6, 000e // +0006
+005808: d901 011f                              |000a: rsub-int/lit8 v1, v1, #int 31 // #1f
+00580c: d900 001f                              |000c: rsub-int/lit8 v0, v0, #int 31 // #1f
+005810: d800 00fc                              |000e: add-int/lit8 v0, v0, #int -4 // #fc
+005814: 3803 0a00                              |0010: if-eqz v3, 001a // +000a
+005818: 6202 5a00                              |0012: sget-object v2, Lcom/google/android/checkers/g;.b:[B // field@005a
+00581c: da00 0020                              |0014: mul-int/lit8 v0, v0, #int 32 // #20
+005820: b010                                   |0016: add-int/2addr v0, v1
+005822: 4800 0200                              |0017: aget-byte v0, v2, v0
+005826: 0f00                                   |0019: return v0
+005828: 6202 5b00                              |001a: sget-object v2, Lcom/google/android/checkers/g;.c:[B // field@005b
+00582c: da00 0020                              |001c: mul-int/lit8 v0, v0, #int 32 // #20
+005830: b010                                   |001e: add-int/2addr v0, v1
+005832: 4800 0200                              |001f: aget-byte v0, v2, v0
+005836: 28f8                                   |0021: goto 0019 // -0008
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #9              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 9
+      ins           : 5
+      outs          : 0
+      insns size    : 76 16-bit code units
+005838:                                        |[005838] com.google.android.checkers.a.a:(IIII)V
+005848: 1301 007d                              |0000: const/16 v1, #int 32000 // #7d00
+00584c: 1302 3f00                              |0002: const/16 v2, #int 63 // #3f
+005850: 1203                                   |0004: const/4 v3, #int 0 // #0
+005852: 1300 0083                              |0005: const/16 v0, #int -32000 // #8300
+005856: 3608 2300                              |0007: if-gt v8, v0, 002a // +0023
+00585a: 2c07 2f00 0000                         |0009: sparse-switch v7, 00000038 // +0000002f
+005860: 0e00                                   |000c: return-void
+005862: 1307 4000                              |000d: const/16 v7, #int 64 // #40
+005866: 0108                                   |000f: move v8, v0
+005868: 0126                                   |0010: move v6, v2
+00586a: 0135                                   |0011: move v5, v3
+00586c: 5240 5100                              |0012: iget v0, v4, Lcom/google/android/checkers/a;.x:I // field@0051
+005870: 1401 ffff 0f00                         |0014: const v1, #float 0.000000 // #000fffff
+005876: b501                                   |0017: and-int/2addr v1, v0
+005878: 5442 5200                              |0018: iget-object v2, v4, Lcom/google/android/checkers/a;.y:[I // field@0052
+00587c: 4b00 0201                              |001a: aput v0, v2, v1
+005880: 5440 5300                              |001c: iget-object v0, v4, Lcom/google/android/checkers/a;.z:[S // field@0053
+005884: 8f82                                   |001e: int-to-short v2, v8
+005886: 5102 0001                              |001f: aput-short v2, v0, v1
+00588a: 5440 2d00                              |0021: iget-object v0, v4, Lcom/google/android/checkers/a;.A:[B // field@002d
+00588e: 9102 0605                              |0023: sub-int v2, v6, v5
+005892: b672                                   |0025: or-int/2addr v2, v7
+005894: 8d22                                   |0026: int-to-byte v2, v2
+005896: 4f02 0001                              |0027: aput-byte v2, v0, v1
+00589a: 28e3                                   |0029: goto 000c // -001d
+00589c: 3418 e8ff                              |002a: if-lt v8, v1, 0012 // -0018
+0058a0: 2c07 1600 0000                         |002c: sparse-switch v7, 00000042 // +00000016
+0058a6: 28dd                                   |002f: goto 000c // -0023
+0058a8: 0118                                   |0030: move v8, v1
+0058aa: 0126                                   |0031: move v6, v2
+0058ac: 0135                                   |0032: move v5, v3
+0058ae: 28df                                   |0033: goto 0012 // -0021
+0058b0: 1307 8000                              |0034: const/16 v7, #int 128 // #80
+0058b4: 28fa                                   |0036: goto 0030 // -0006
+0058b6: 0000                                   |0037: nop // spacer
+0058b8: 0002 0200 4000 0000 c000 0000 0600 ... |0038: sparse-switch-data (10 units)
+0058cc: 0002 0200 8000 0000 c000 0000 0400 ... |0042: sparse-switch-data (10 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #10              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IIIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 10
+      ins           : 6
+      outs          : 0
+      insns size    : 39 16-bit code units
+0058e0:                                        |[0058e0] com.google.android.checkers.a.a:(IIIII)V
+0058f0: 5240 3c00                              |0000: iget v0, v4, Lcom/google/android/checkers/a;.c:I // field@003c
+0058f4: 1301 4000                              |0002: const/16 v1, #int 64 // #40
+0058f8: 3410 0300                              |0004: if-lt v0, v1, 0007 // +0003
+0058fc: 0e00                                   |0006: return-void
+0058fe: 5240 3c00                              |0007: iget v0, v4, Lcom/google/android/checkers/a;.c:I // field@003c
+005902: d801 0001                              |0009: add-int/lit8 v1, v0, #int 1 // #01
+005906: 5941 3c00                              |000b: iput v1, v4, Lcom/google/android/checkers/a;.c:I // field@003c
+00590a: 5241 4b00                              |000d: iget v1, v4, Lcom/google/android/checkers/a;.r:I // field@004b
+00590e: 5442 4800                              |000f: iget-object v2, v4, Lcom/google/android/checkers/a;.o:[I // field@0048
+005912: 9003 0100                              |0011: add-int v3, v1, v0
+005916: 4b06 0203                              |0013: aput v6, v2, v3
+00591a: 5442 3a00                              |0015: iget-object v2, v4, Lcom/google/android/checkers/a;.a:[I // field@003a
+00591e: 9003 0100                              |0017: add-int v3, v1, v0
+005922: 4b07 0203                              |0019: aput v7, v2, v3
+005926: 5442 4900                              |001b: iget-object v2, v4, Lcom/google/android/checkers/a;.p:[I // field@0049
+00592a: b001                                   |001d: add-int/2addr v1, v0
+00592c: 4b08 0201                              |001e: aput v8, v2, v1
+005930: 3905 e6ff                              |0020: if-nez v5, 0006 // -001a
+005934: 5441 3b00                              |0022: iget-object v1, v4, Lcom/google/android/checkers/a;.b:[I // field@003b
+005938: 4b09 0100                              |0024: aput v9, v1, v0
+00593c: 28e0                                   |0026: goto 0006 // -0020
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #11              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IIIIIIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 18
+      ins           : 9
+      outs          : 9
+      insns size    : 99 16-bit code units
+005940:                                        |[005940] com.google.android.checkers.a.a:(IIIIIIII)V
+005950: 1210                                   |0000: const/4 v0, #int 1 // #1
+005952: 6201 3000                              |0001: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005956: 4401 010d                              |0003: aget v1, v1, v13
+00595a: b5c1                                   |0005: and-int/2addr v1, v12
+00595c: 3801 2500                              |0006: if-eqz v1, 002b // +0025
+005960: 6201 3100                              |0008: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005964: 4401 010d                              |000a: aget v1, v1, v13
+005968: b5b1                                   |000c: and-int/2addr v1, v11
+00596a: 3801 1e00                              |000d: if-eqz v1, 002b // +001e
+00596e: d804 0df7                              |000f: add-int/lit8 v4, v13, #int -9 // #f7
+005972: 6200 3100                              |0011: sget-object v0, Lcom/google/android/checkers/a;.E:[I // field@0031
+005976: 4405 000d                              |0013: aget v5, v0, v13
+00597a: 6200 3000                              |0015: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+00597e: 4400 000d                              |0017: aget v0, v0, v13
+005982: 9606 0f00                              |0019: or-int v6, v15, v0
+005986: d807 1001                              |001b: add-int/lit8 v7, v16, #int 1 // #01
+00598a: 6200 3100                              |001d: sget-object v0, Lcom/google/android/checkers/a;.E:[I // field@0031
+00598e: 4400 000d                              |001f: aget v0, v0, v13
+005992: 9608 1100                              |0021: or-int v8, v17, v0
+005996: 0790                                   |0023: move-object v0, v9
+005998: 01a1                                   |0024: move v1, v10
+00599a: 01b2                                   |0025: move v2, v11
+00599c: 01c3                                   |0026: move v3, v12
+00599e: 7609 7f00 0000                         |0027: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.a:(IIIIIIII)V // method@007f
+0059a4: 1200                                   |002a: const/4 v0, #int 0 // #0
+0059a6: 6201 3200                              |002b: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+0059aa: 4401 010d                              |002d: aget v1, v1, v13
+0059ae: b5c1                                   |002f: and-int/2addr v1, v12
+0059b0: 3801 2500                              |0030: if-eqz v1, 0055 // +0025
+0059b4: 6201 3300                              |0032: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+0059b8: 4401 010d                              |0034: aget v1, v1, v13
+0059bc: b5b1                                   |0036: and-int/2addr v1, v11
+0059be: 3801 1e00                              |0037: if-eqz v1, 0055 // +001e
+0059c2: d804 0df9                              |0039: add-int/lit8 v4, v13, #int -7 // #f9
+0059c6: 6200 3300                              |003b: sget-object v0, Lcom/google/android/checkers/a;.G:[I // field@0033
+0059ca: 4405 000d                              |003d: aget v5, v0, v13
+0059ce: 6200 3200                              |003f: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+0059d2: 4400 000d                              |0041: aget v0, v0, v13
+0059d6: 9606 0f00                              |0043: or-int v6, v15, v0
+0059da: d807 1001                              |0045: add-int/lit8 v7, v16, #int 1 // #01
+0059de: 6200 3300                              |0047: sget-object v0, Lcom/google/android/checkers/a;.G:[I // field@0033
+0059e2: 4400 000d                              |0049: aget v0, v0, v13
+0059e6: 9608 1100                              |004b: or-int v8, v17, v0
+0059ea: 0790                                   |004d: move-object v0, v9
+0059ec: 01a1                                   |004e: move v1, v10
+0059ee: 01b2                                   |004f: move v2, v11
+0059f0: 01c3                                   |0050: move v3, v12
+0059f2: 7609 7f00 0000                         |0051: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.a:(IIIIIIII)V // method@007f
+0059f8: 1200                                   |0054: const/4 v0, #int 0 // #0
+0059fa: 3800 0d00                              |0055: if-eqz v0, 0062 // +000d
+0059fe: 0790                                   |0057: move-object v0, v9
+005a00: 01a1                                   |0058: move v1, v10
+005a02: 01e2                                   |0059: move v2, v14
+005a04: 01f3                                   |005a: move v3, v15
+005a06: 0204 1000                              |005b: move/from16 v4, v16
+005a0a: 0205 1100                              |005d: move/from16 v5, v17
+005a0e: 7606 7e00 0000                         |005f: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+005a14: 0e00                                   |0062: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #12              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IZI)Z'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 21
+      ins           : 4
+      outs          : 9
+      insns size    : 875 16-bit code units
+005a18:                                        |[005a18] com.google.android.checkers.a.a:(IZI)Z
+005a28: 3813 b901                              |0000: if-eqz v19, 01b9 // +01b9
+005a2c: 0800 1100                              |0002: move-object/from16 v0, v17
+005a30: 5201 3e00                              |0004: iget v1, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005a34: 0800 1100                              |0006: move-object/from16 v0, v17
+005a38: 5202 3d00                              |0008: iget v2, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+005a3c: b612                                   |000a: or-int/2addr v2, v1
+005a3e: 0800 1100                              |000b: move-object/from16 v0, v17
+005a42: 5201 4000                              |000d: iget v1, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005a46: 0800 1100                              |000f: move-object/from16 v0, v17
+005a4a: 5203 3f00                              |0011: iget v3, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+005a4e: 9604 0103                              |0013: or-int v4, v1, v3
+005a52: 1201                                   |0015: const/4 v1, #int 0 // #0
+005a54: e203 1404                              |0016: ushr-int/lit8 v3, v20, #int 4 // #04
+005a58: b543                                   |0018: and-int/2addr v3, v4
+005a5a: 3803 1200                              |0019: if-eqz v3, 002b // +0012
+005a5e: 1401 e0e0 e0e0                         |001b: const v1, #float -129633581999069331456.000000 // #e0e0e0e0
+005a64: b531                                   |001e: and-int/2addr v1, v3
+005a66: e201 0105                              |001f: ushr-int/lit8 v1, v1, #int 5 // #05
+005a6a: 1405 0007 0707                         |0021: const v5, #float 0.000000 // #07070700
+005a70: b553                                   |0024: and-int/2addr v3, v5
+005a72: e203 0303                              |0025: ushr-int/lit8 v3, v3, #int 3 // #03
+005a76: b631                                   |0027: or-int/2addr v1, v3
+005a78: b521                                   |0028: and-int/2addr v1, v2
+005a7a: de01 0100                              |0029: or-int/lit8 v1, v1, #int 0 // #00
+005a7e: 1403 e0e0 e0e0                         |002b: const v3, #float -129633581999069331456.000000 // #e0e0e0e0
+005a84: 9503 0314                              |002e: and-int v3, v3, v20
+005a88: e203 0305                              |0030: ushr-int/lit8 v3, v3, #int 5 // #05
+005a8c: 1405 0007 0707                         |0032: const v5, #float 0.000000 // #07070700
+005a92: 9505 0514                              |0035: and-int v5, v5, v20
+005a96: e205 0503                              |0037: ushr-int/lit8 v5, v5, #int 3 // #03
+005a9a: b653                                   |0039: or-int/2addr v3, v5
+005a9c: b543                                   |003a: and-int/2addr v3, v4
+005a9e: 3803 0600                              |003b: if-eqz v3, 0041 // +0006
+005aa2: e203 0304                              |003d: ushr-int/lit8 v3, v3, #int 4 // #04
+005aa6: b532                                   |003f: and-int/2addr v2, v3
+005aa8: b621                                   |0040: or-int/2addr v1, v2
+005aaa: 0800 1100                              |0041: move-object/from16 v0, v17
+005aae: 5202 3e00                              |0043: iget v2, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005ab2: 3802 3400                              |0045: if-eqz v2, 0079 // +0034
+005ab6: e002 1404                              |0047: shl-int/lit8 v2, v20, #int 4 // #04
+005aba: b542                                   |0049: and-int/2addr v2, v4
+005abc: 3802 1500                              |004a: if-eqz v2, 005f // +0015
+005ac0: 0800 1100                              |004c: move-object/from16 v0, v17
+005ac4: 5203 3e00                              |004e: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005ac8: 1405 0707 0707                         |0050: const v5, #float 0.000000 // #07070707
+005ace: b525                                   |0053: and-int/2addr v5, v2
+005ad0: e005 0505                              |0054: shl-int/lit8 v5, v5, #int 5 // #05
+005ad4: 1406 e0e0 e000                         |0056: const v6, #float 0.000000 // #00e0e0e0
+005ada: b562                                   |0059: and-int/2addr v2, v6
+005adc: e002 0203                              |005a: shl-int/lit8 v2, v2, #int 3 // #03
+005ae0: b652                                   |005c: or-int/2addr v2, v5
+005ae2: b532                                   |005d: and-int/2addr v2, v3
+005ae4: b621                                   |005e: or-int/2addr v1, v2
+005ae6: 1402 0707 0707                         |005f: const v2, #float 0.000000 // #07070707
+005aec: 9502 0214                              |0062: and-int v2, v2, v20
+005af0: e002 0205                              |0064: shl-int/lit8 v2, v2, #int 5 // #05
+005af4: 1403 e0e0 e000                         |0066: const v3, #float 0.000000 // #00e0e0e0
+005afa: 9503 0314                              |0069: and-int v3, v3, v20
+005afe: e003 0303                              |006b: shl-int/lit8 v3, v3, #int 3 // #03
+005b02: b632                                   |006d: or-int/2addr v2, v3
+005b04: b542                                   |006e: and-int/2addr v2, v4
+005b06: 3802 0a00                              |006f: if-eqz v2, 0079 // +000a
+005b0a: 0800 1100                              |0071: move-object/from16 v0, v17
+005b0e: 5203 3e00                              |0073: iget v3, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005b12: e002 0204                              |0075: shl-int/lit8 v2, v2, #int 4 // #04
+005b16: b532                                   |0077: and-int/2addr v2, v3
+005b18: b621                                   |0078: or-int/2addr v1, v2
+005b1a: 3901 0a00                              |0079: if-nez v1, 0083 // +000a
+005b1e: 0800 1100                              |007b: move-object/from16 v0, v17
+005b22: 5201 3c00                              |007d: iget v1, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+005b26: 3801 e902                              |007f: if-eqz v1, 0368 // +02e9
+005b2a: 1211                                   |0081: const/4 v1, #int 1 // #1
+005b2c: 0f01                                   |0082: return v1
+005b2e: 7110 9f00 0100                         |0083: invoke-static {v1}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005b34: 0a0f                                   |0086: move-result v15
+005b36: 1212                                   |0087: const/4 v2, #int 1 // #1
+005b38: 9810 020f                              |0088: shl-int v16, v2, v15
+005b3c: 970e 0110                              |008a: xor-int v14, v1, v16
+005b40: 0800 1100                              |008c: move-object/from16 v0, v17
+005b44: 5201 3e00                              |008e: iget v1, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005b48: 9501 0110                              |0090: and-int v1, v1, v16
+005b4c: 3901 5c00                              |0092: if-nez v1, 00ee // +005c
+005b50: 6201 3400                              |0094: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+005b54: 4401 010f                              |0096: aget v1, v1, v15
+005b58: b541                                   |0098: and-int/2addr v1, v4
+005b5a: 3801 2700                              |0099: if-eqz v1, 00c0 // +0027
+005b5e: 6201 3500                              |009b: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+005b62: 4401 010f                              |009d: aget v1, v1, v15
+005b66: 9501 0114                              |009f: and-int v1, v1, v20
+005b6a: 3801 1f00                              |00a1: if-eqz v1, 00c0 // +001f
+005b6e: d805 0f07                              |00a3: add-int/lit8 v5, v15, #int 7 // #07
+005b72: 6201 3500                              |00a5: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+005b76: 4406 010f                              |00a7: aget v6, v1, v15
+005b7a: 6201 3400                              |00a9: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+005b7e: 4401 010f                              |00ab: aget v1, v1, v15
+005b82: 9607 1001                              |00ad: or-int v7, v16, v1
+005b86: 1308 0101                              |00af: const/16 v8, #int 257 // #101
+005b8a: 6201 3500                              |00b1: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+005b8e: 4401 010f                              |00b3: aget v1, v1, v15
+005b92: 9609 1001                              |00b5: or-int v9, v16, v1
+005b96: 0801 1100                              |00b7: move-object/from16 v1, v17
+005b9a: 0202 1200                              |00b9: move/from16 v2, v18
+005b9e: 0203 1400                              |00bb: move/from16 v3, v20
+005ba2: 7609 8600 0100                         |00bd: invoke-direct/range {v1, v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/a;.b:(IIIIIIII)V // method@0086
+005ba8: 6201 3600                              |00c0: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+005bac: 4401 010f                              |00c2: aget v1, v1, v15
+005bb0: b541                                   |00c4: and-int/2addr v1, v4
+005bb2: 3801 f100                              |00c5: if-eqz v1, 01b6 // +00f1
+005bb6: 6201 3700                              |00c7: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+005bba: 4401 010f                              |00c9: aget v1, v1, v15
+005bbe: 9501 0114                              |00cb: and-int v1, v1, v20
+005bc2: 3801 e900                              |00cd: if-eqz v1, 01b6 // +00e9
+005bc6: d805 0f09                              |00cf: add-int/lit8 v5, v15, #int 9 // #09
+005bca: 6201 3700                              |00d1: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+005bce: 4406 010f                              |00d3: aget v6, v1, v15
+005bd2: 6201 3600                              |00d5: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+005bd6: 4401 010f                              |00d7: aget v1, v1, v15
+005bda: 9607 1001                              |00d9: or-int v7, v16, v1
+005bde: 1308 0101                              |00db: const/16 v8, #int 257 // #101
+005be2: 6201 3700                              |00dd: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+005be6: 4401 010f                              |00df: aget v1, v1, v15
+005bea: 9609 1001                              |00e1: or-int v9, v16, v1
+005bee: 0801 1100                              |00e3: move-object/from16 v1, v17
+005bf2: 0202 1200                              |00e5: move/from16 v2, v18
+005bf6: 0203 1400                              |00e7: move/from16 v3, v20
+005bfa: 7609 8600 0100                         |00e9: invoke-direct/range {v1, v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/a;.b:(IIIIIIII)V // method@0086
+005c00: 01e1                                   |00ec: move v1, v14
+005c02: 288c                                   |00ed: goto 0079 // -0074
+005c04: 6201 3000                              |00ee: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005c08: 4401 010f                              |00f0: aget v1, v1, v15
+005c0c: b541                                   |00f2: and-int/2addr v1, v4
+005c0e: 3801 2d00                              |00f3: if-eqz v1, 0120 // +002d
+005c12: 6201 3100                              |00f5: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005c16: 4401 010f                              |00f7: aget v1, v1, v15
+005c1a: 9501 0114                              |00f9: and-int v1, v1, v20
+005c1e: 3801 2500                              |00fb: if-eqz v1, 0120 // +0025
+005c22: 9607 1410                              |00fd: or-int v7, v20, v16
+005c26: 6201 3000                              |00ff: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005c2a: 4401 010f                              |0101: aget v1, v1, v15
+005c2e: 9708 0401                              |0103: xor-int v8, v4, v1
+005c32: d809 0ff7                              |0105: add-int/lit8 v9, v15, #int -9 // #f7
+005c36: 6201 3100                              |0107: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005c3a: 440a 010f                              |0109: aget v10, v1, v15
+005c3e: 6201 3000                              |010b: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005c42: 4401 010f                              |010d: aget v1, v1, v15
+005c46: 960b 1001                              |010f: or-int v11, v16, v1
+005c4a: 130c 0102                              |0111: const/16 v12, #int 513 // #201
+005c4e: 6201 3100                              |0113: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005c52: 4401 010f                              |0115: aget v1, v1, v15
+005c56: 960d 1001                              |0117: or-int v13, v16, v1
+005c5a: 0805 1100                              |0119: move-object/from16 v5, v17
+005c5e: 0206 1200                              |011b: move/from16 v6, v18
+005c62: 7609 8b00 0500                         |011d: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+005c68: 6201 3200                              |0120: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005c6c: 4401 010f                              |0122: aget v1, v1, v15
+005c70: b541                                   |0124: and-int/2addr v1, v4
+005c72: 3801 2d00                              |0125: if-eqz v1, 0152 // +002d
+005c76: 6201 3300                              |0127: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005c7a: 4401 010f                              |0129: aget v1, v1, v15
+005c7e: 9501 0114                              |012b: and-int v1, v1, v20
+005c82: 3801 2500                              |012d: if-eqz v1, 0152 // +0025
+005c86: 9607 1410                              |012f: or-int v7, v20, v16
+005c8a: 6201 3200                              |0131: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005c8e: 4401 010f                              |0133: aget v1, v1, v15
+005c92: 9708 0401                              |0135: xor-int v8, v4, v1
+005c96: d809 0ff9                              |0137: add-int/lit8 v9, v15, #int -7 // #f9
+005c9a: 6201 3300                              |0139: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005c9e: 440a 010f                              |013b: aget v10, v1, v15
+005ca2: 6201 3200                              |013d: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005ca6: 4401 010f                              |013f: aget v1, v1, v15
+005caa: 960b 1001                              |0141: or-int v11, v16, v1
+005cae: 130c 0102                              |0143: const/16 v12, #int 513 // #201
+005cb2: 6201 3300                              |0145: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005cb6: 4401 010f                              |0147: aget v1, v1, v15
+005cba: 960d 1001                              |0149: or-int v13, v16, v1
+005cbe: 0805 1100                              |014b: move-object/from16 v5, v17
+005cc2: 0206 1200                              |014d: move/from16 v6, v18
+005cc6: 7609 8b00 0500                         |014f: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+005ccc: 6201 3400                              |0152: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+005cd0: 4401 010f                              |0154: aget v1, v1, v15
+005cd4: b541                                   |0156: and-int/2addr v1, v4
+005cd6: 3801 2d00                              |0157: if-eqz v1, 0184 // +002d
+005cda: 6201 3500                              |0159: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+005cde: 4401 010f                              |015b: aget v1, v1, v15
+005ce2: 9501 0114                              |015d: and-int v1, v1, v20
+005ce6: 3801 2500                              |015f: if-eqz v1, 0184 // +0025
+005cea: 9607 1410                              |0161: or-int v7, v20, v16
+005cee: 6201 3400                              |0163: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+005cf2: 4401 010f                              |0165: aget v1, v1, v15
+005cf6: 9708 0401                              |0167: xor-int v8, v4, v1
+005cfa: d809 0f07                              |0169: add-int/lit8 v9, v15, #int 7 // #07
+005cfe: 6201 3500                              |016b: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+005d02: 440a 010f                              |016d: aget v10, v1, v15
+005d06: 6201 3400                              |016f: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+005d0a: 4401 010f                              |0171: aget v1, v1, v15
+005d0e: 960b 1001                              |0173: or-int v11, v16, v1
+005d12: 130c 0102                              |0175: const/16 v12, #int 513 // #201
+005d16: 6201 3500                              |0177: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+005d1a: 4401 010f                              |0179: aget v1, v1, v15
+005d1e: 960d 1001                              |017b: or-int v13, v16, v1
+005d22: 0805 1100                              |017d: move-object/from16 v5, v17
+005d26: 0206 1200                              |017f: move/from16 v6, v18
+005d2a: 7609 8b00 0500                         |0181: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+005d30: 6201 3600                              |0184: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+005d34: 4401 010f                              |0186: aget v1, v1, v15
+005d38: b541                                   |0188: and-int/2addr v1, v4
+005d3a: 3801 2d00                              |0189: if-eqz v1, 01b6 // +002d
+005d3e: 6201 3700                              |018b: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+005d42: 4401 010f                              |018d: aget v1, v1, v15
+005d46: 9501 0114                              |018f: and-int v1, v1, v20
+005d4a: 3801 2500                              |0191: if-eqz v1, 01b6 // +0025
+005d4e: 9607 1410                              |0193: or-int v7, v20, v16
+005d52: 6201 3600                              |0195: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+005d56: 4401 010f                              |0197: aget v1, v1, v15
+005d5a: 9708 0401                              |0199: xor-int v8, v4, v1
+005d5e: d809 0f09                              |019b: add-int/lit8 v9, v15, #int 9 // #09
+005d62: 6201 3700                              |019d: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+005d66: 440a 010f                              |019f: aget v10, v1, v15
+005d6a: 6201 3600                              |01a1: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+005d6e: 4401 010f                              |01a3: aget v1, v1, v15
+005d72: 960b 1001                              |01a5: or-int v11, v16, v1
+005d76: 130c 0102                              |01a7: const/16 v12, #int 513 // #201
+005d7a: 6201 3700                              |01a9: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+005d7e: 4401 010f                              |01ab: aget v1, v1, v15
+005d82: 960d 1001                              |01ad: or-int v13, v16, v1
+005d86: 0805 1100                              |01af: move-object/from16 v5, v17
+005d8a: 0206 1200                              |01b1: move/from16 v6, v18
+005d8e: 7609 8b00 0500                         |01b3: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+005d94: 01e1                                   |01b6: move v1, v14
+005d96: 2900 c2fe                              |01b7: goto/16 0079 // -013e
+005d9a: 0800 1100                              |01b9: move-object/from16 v0, v17
+005d9e: 5201 4000                              |01bb: iget v1, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005da2: 0800 1100                              |01bd: move-object/from16 v0, v17
+005da6: 5202 3f00                              |01bf: iget v2, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+005daa: b612                                   |01c1: or-int/2addr v2, v1
+005dac: 0800 1100                              |01c2: move-object/from16 v0, v17
+005db0: 5201 3e00                              |01c4: iget v1, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+005db4: 0800 1100                              |01c6: move-object/from16 v0, v17
+005db8: 5203 3d00                              |01c8: iget v3, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+005dbc: 9604 0103                              |01ca: or-int v4, v1, v3
+005dc0: 1201                                   |01cc: const/4 v1, #int 0 // #0
+005dc2: 0800 1100                              |01cd: move-object/from16 v0, v17
+005dc6: 5203 4000                              |01cf: iget v3, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005dca: 3803 3500                              |01d1: if-eqz v3, 0206 // +0035
+005dce: e203 1404                              |01d3: ushr-int/lit8 v3, v20, #int 4 // #04
+005dd2: b543                                   |01d5: and-int/2addr v3, v4
+005dd4: 3803 1600                              |01d6: if-eqz v3, 01ec // +0016
+005dd8: 0800 1100                              |01d8: move-object/from16 v0, v17
+005ddc: 5201 4000                              |01da: iget v1, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005de0: 1405 e0e0 e0e0                         |01dc: const v5, #float -129633581999069331456.000000 // #e0e0e0e0
+005de6: b535                                   |01df: and-int/2addr v5, v3
+005de8: e205 0505                              |01e0: ushr-int/lit8 v5, v5, #int 5 // #05
+005dec: 1406 0007 0707                         |01e2: const v6, #float 0.000000 // #07070700
+005df2: b563                                   |01e5: and-int/2addr v3, v6
+005df4: e203 0303                              |01e6: ushr-int/lit8 v3, v3, #int 3 // #03
+005df8: b653                                   |01e8: or-int/2addr v3, v5
+005dfa: b531                                   |01e9: and-int/2addr v1, v3
+005dfc: de01 0100                              |01ea: or-int/lit8 v1, v1, #int 0 // #00
+005e00: 1403 e0e0 e0e0                         |01ec: const v3, #float -129633581999069331456.000000 // #e0e0e0e0
+005e06: 9503 0314                              |01ef: and-int v3, v3, v20
+005e0a: e203 0305                              |01f1: ushr-int/lit8 v3, v3, #int 5 // #05
+005e0e: 1405 0007 0707                         |01f3: const v5, #float 0.000000 // #07070700
+005e14: 9505 0514                              |01f6: and-int v5, v5, v20
+005e18: e205 0503                              |01f8: ushr-int/lit8 v5, v5, #int 3 // #03
+005e1c: b653                                   |01fa: or-int/2addr v3, v5
+005e1e: b543                                   |01fb: and-int/2addr v3, v4
+005e20: 3803 0a00                              |01fc: if-eqz v3, 0206 // +000a
+005e24: 0800 1100                              |01fe: move-object/from16 v0, v17
+005e28: 5205 4000                              |0200: iget v5, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005e2c: e203 0304                              |0202: ushr-int/lit8 v3, v3, #int 4 // #04
+005e30: b553                                   |0204: and-int/2addr v3, v5
+005e32: b631                                   |0205: or-int/2addr v1, v3
+005e34: e003 1404                              |0206: shl-int/lit8 v3, v20, #int 4 // #04
+005e38: b543                                   |0208: and-int/2addr v3, v4
+005e3a: 3803 1100                              |0209: if-eqz v3, 021a // +0011
+005e3e: 1405 0707 0707                         |020b: const v5, #float 0.000000 // #07070707
+005e44: b535                                   |020e: and-int/2addr v5, v3
+005e46: e005 0505                              |020f: shl-int/lit8 v5, v5, #int 5 // #05
+005e4a: 1406 e0e0 e000                         |0211: const v6, #float 0.000000 // #00e0e0e0
+005e50: b563                                   |0214: and-int/2addr v3, v6
+005e52: e003 0303                              |0215: shl-int/lit8 v3, v3, #int 3 // #03
+005e56: b653                                   |0217: or-int/2addr v3, v5
+005e58: b523                                   |0218: and-int/2addr v3, v2
+005e5a: b631                                   |0219: or-int/2addr v1, v3
+005e5c: 1403 0707 0707                         |021a: const v3, #float 0.000000 // #07070707
+005e62: 9503 0314                              |021d: and-int v3, v3, v20
+005e66: e003 0305                              |021f: shl-int/lit8 v3, v3, #int 5 // #05
+005e6a: 1405 e0e0 e000                         |0221: const v5, #float 0.000000 // #00e0e0e0
+005e70: 9505 0514                              |0224: and-int v5, v5, v20
+005e74: e005 0503                              |0226: shl-int/lit8 v5, v5, #int 3 // #03
+005e78: b653                                   |0228: or-int/2addr v3, v5
+005e7a: b543                                   |0229: and-int/2addr v3, v4
+005e7c: 3803 0600                              |022a: if-eqz v3, 0230 // +0006
+005e80: e003 0304                              |022c: shl-int/lit8 v3, v3, #int 4 // #04
+005e84: b532                                   |022e: and-int/2addr v2, v3
+005e86: b621                                   |022f: or-int/2addr v1, v2
+005e88: 3801 4bfe                              |0230: if-eqz v1, 007b // -01b5
+005e8c: 7110 9f00 0100                         |0232: invoke-static {v1}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+005e92: 0a0f                                   |0235: move-result v15
+005e94: 1212                                   |0236: const/4 v2, #int 1 // #1
+005e96: 9810 020f                              |0237: shl-int v16, v2, v15
+005e9a: 970e 0110                              |0239: xor-int v14, v1, v16
+005e9e: 0800 1100                              |023b: move-object/from16 v0, v17
+005ea2: 5201 4000                              |023d: iget v1, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+005ea6: 9501 0110                              |023f: and-int v1, v1, v16
+005eaa: 3901 5c00                              |0241: if-nez v1, 029d // +005c
+005eae: 6201 3000                              |0243: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005eb2: 4401 010f                              |0245: aget v1, v1, v15
+005eb6: b541                                   |0247: and-int/2addr v1, v4
+005eb8: 3801 2700                              |0248: if-eqz v1, 026f // +0027
+005ebc: 6201 3100                              |024a: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005ec0: 4401 010f                              |024c: aget v1, v1, v15
+005ec4: 9501 0114                              |024e: and-int v1, v1, v20
+005ec8: 3801 1f00                              |0250: if-eqz v1, 026f // +001f
+005ecc: d805 0ff7                              |0252: add-int/lit8 v5, v15, #int -9 // #f7
+005ed0: 6201 3100                              |0254: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005ed4: 4406 010f                              |0256: aget v6, v1, v15
+005ed8: 6201 3000                              |0258: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005edc: 4401 010f                              |025a: aget v1, v1, v15
+005ee0: 9607 1001                              |025c: or-int v7, v16, v1
+005ee4: 1308 0104                              |025e: const/16 v8, #int 1025 // #401
+005ee8: 6201 3100                              |0260: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005eec: 4401 010f                              |0262: aget v1, v1, v15
+005ef0: 9609 1001                              |0264: or-int v9, v16, v1
+005ef4: 0801 1100                              |0266: move-object/from16 v1, v17
+005ef8: 0202 1200                              |0268: move/from16 v2, v18
+005efc: 0203 1400                              |026a: move/from16 v3, v20
+005f00: 7609 7f00 0100                         |026c: invoke-direct/range {v1, v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/a;.a:(IIIIIIII)V // method@007f
+005f06: 6201 3200                              |026f: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005f0a: 4401 010f                              |0271: aget v1, v1, v15
+005f0e: b541                                   |0273: and-int/2addr v1, v4
+005f10: 3801 f100                              |0274: if-eqz v1, 0365 // +00f1
+005f14: 6201 3300                              |0276: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005f18: 4401 010f                              |0278: aget v1, v1, v15
+005f1c: 9501 0114                              |027a: and-int v1, v1, v20
+005f20: 3801 e900                              |027c: if-eqz v1, 0365 // +00e9
+005f24: d805 0ff9                              |027e: add-int/lit8 v5, v15, #int -7 // #f9
+005f28: 6201 3300                              |0280: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005f2c: 4406 010f                              |0282: aget v6, v1, v15
+005f30: 6201 3200                              |0284: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005f34: 4401 010f                              |0286: aget v1, v1, v15
+005f38: 9607 1001                              |0288: or-int v7, v16, v1
+005f3c: 1308 0104                              |028a: const/16 v8, #int 1025 // #401
+005f40: 6201 3300                              |028c: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005f44: 4401 010f                              |028e: aget v1, v1, v15
+005f48: 9609 1001                              |0290: or-int v9, v16, v1
+005f4c: 0801 1100                              |0292: move-object/from16 v1, v17
+005f50: 0202 1200                              |0294: move/from16 v2, v18
+005f54: 0203 1400                              |0296: move/from16 v3, v20
+005f58: 7609 7f00 0100                         |0298: invoke-direct/range {v1, v2, v3, v4, v5, v6, v7, v8, v9}, Lcom/google/android/checkers/a;.a:(IIIIIIII)V // method@007f
+005f5e: 01e1                                   |029b: move v1, v14
+005f60: 2894                                   |029c: goto 0230 // -006c
+005f62: 6201 3000                              |029d: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005f66: 4401 010f                              |029f: aget v1, v1, v15
+005f6a: b541                                   |02a1: and-int/2addr v1, v4
+005f6c: 3801 2d00                              |02a2: if-eqz v1, 02cf // +002d
+005f70: 6201 3100                              |02a4: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005f74: 4401 010f                              |02a6: aget v1, v1, v15
+005f78: 9501 0114                              |02a8: and-int v1, v1, v20
+005f7c: 3801 2500                              |02aa: if-eqz v1, 02cf // +0025
+005f80: 9607 1410                              |02ac: or-int v7, v20, v16
+005f84: 6201 3000                              |02ae: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005f88: 4401 010f                              |02b0: aget v1, v1, v15
+005f8c: 9708 0401                              |02b2: xor-int v8, v4, v1
+005f90: d809 0ff7                              |02b4: add-int/lit8 v9, v15, #int -9 // #f7
+005f94: 6201 3100                              |02b6: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005f98: 440a 010f                              |02b8: aget v10, v1, v15
+005f9c: 6201 3000                              |02ba: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+005fa0: 4401 010f                              |02bc: aget v1, v1, v15
+005fa4: 960b 1001                              |02be: or-int v11, v16, v1
+005fa8: 130c 0108                              |02c0: const/16 v12, #int 2049 // #801
+005fac: 6201 3100                              |02c2: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+005fb0: 4401 010f                              |02c4: aget v1, v1, v15
+005fb4: 960d 1001                              |02c6: or-int v13, v16, v1
+005fb8: 0805 1100                              |02c8: move-object/from16 v5, v17
+005fbc: 0206 1200                              |02ca: move/from16 v6, v18
+005fc0: 7609 8b00 0500                         |02cc: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+005fc6: 6201 3200                              |02cf: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005fca: 4401 010f                              |02d1: aget v1, v1, v15
+005fce: b541                                   |02d3: and-int/2addr v1, v4
+005fd0: 3801 2d00                              |02d4: if-eqz v1, 0301 // +002d
+005fd4: 6201 3300                              |02d6: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005fd8: 4401 010f                              |02d8: aget v1, v1, v15
+005fdc: 9501 0114                              |02da: and-int v1, v1, v20
+005fe0: 3801 2500                              |02dc: if-eqz v1, 0301 // +0025
+005fe4: 9607 1410                              |02de: or-int v7, v20, v16
+005fe8: 6201 3200                              |02e0: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+005fec: 4401 010f                              |02e2: aget v1, v1, v15
+005ff0: 9708 0401                              |02e4: xor-int v8, v4, v1
+005ff4: d809 0ff9                              |02e6: add-int/lit8 v9, v15, #int -7 // #f9
+005ff8: 6201 3300                              |02e8: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+005ffc: 440a 010f                              |02ea: aget v10, v1, v15
+006000: 6201 3200                              |02ec: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+006004: 4401 010f                              |02ee: aget v1, v1, v15
+006008: 960b 1001                              |02f0: or-int v11, v16, v1
+00600c: 130c 0108                              |02f2: const/16 v12, #int 2049 // #801
+006010: 6201 3300                              |02f4: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+006014: 4401 010f                              |02f6: aget v1, v1, v15
+006018: 960d 1001                              |02f8: or-int v13, v16, v1
+00601c: 0805 1100                              |02fa: move-object/from16 v5, v17
+006020: 0206 1200                              |02fc: move/from16 v6, v18
+006024: 7609 8b00 0500                         |02fe: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+00602a: 6201 3400                              |0301: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+00602e: 4401 010f                              |0303: aget v1, v1, v15
+006032: b541                                   |0305: and-int/2addr v1, v4
+006034: 3801 2d00                              |0306: if-eqz v1, 0333 // +002d
+006038: 6201 3500                              |0308: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+00603c: 4401 010f                              |030a: aget v1, v1, v15
+006040: 9501 0114                              |030c: and-int v1, v1, v20
+006044: 3801 2500                              |030e: if-eqz v1, 0333 // +0025
+006048: 9607 1410                              |0310: or-int v7, v20, v16
+00604c: 6201 3400                              |0312: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+006050: 4401 010f                              |0314: aget v1, v1, v15
+006054: 9708 0401                              |0316: xor-int v8, v4, v1
+006058: d809 0f07                              |0318: add-int/lit8 v9, v15, #int 7 // #07
+00605c: 6201 3500                              |031a: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+006060: 440a 010f                              |031c: aget v10, v1, v15
+006064: 6201 3400                              |031e: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+006068: 4401 010f                              |0320: aget v1, v1, v15
+00606c: 960b 1001                              |0322: or-int v11, v16, v1
+006070: 130c 0108                              |0324: const/16 v12, #int 2049 // #801
+006074: 6201 3500                              |0326: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+006078: 4401 010f                              |0328: aget v1, v1, v15
+00607c: 960d 1001                              |032a: or-int v13, v16, v1
+006080: 0805 1100                              |032c: move-object/from16 v5, v17
+006084: 0206 1200                              |032e: move/from16 v6, v18
+006088: 7609 8b00 0500                         |0330: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+00608e: 6201 3600                              |0333: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+006092: 4401 010f                              |0335: aget v1, v1, v15
+006096: b541                                   |0337: and-int/2addr v1, v4
+006098: 3801 2d00                              |0338: if-eqz v1, 0365 // +002d
+00609c: 6201 3700                              |033a: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+0060a0: 4401 010f                              |033c: aget v1, v1, v15
+0060a4: 9501 0114                              |033e: and-int v1, v1, v20
+0060a8: 3801 2500                              |0340: if-eqz v1, 0365 // +0025
+0060ac: 9607 1410                              |0342: or-int v7, v20, v16
+0060b0: 6201 3600                              |0344: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+0060b4: 4401 010f                              |0346: aget v1, v1, v15
+0060b8: 9708 0401                              |0348: xor-int v8, v4, v1
+0060bc: d809 0f09                              |034a: add-int/lit8 v9, v15, #int 9 // #09
+0060c0: 6201 3700                              |034c: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+0060c4: 440a 010f                              |034e: aget v10, v1, v15
+0060c8: 6201 3600                              |0350: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+0060cc: 4401 010f                              |0352: aget v1, v1, v15
+0060d0: 960b 1001                              |0354: or-int v11, v16, v1
+0060d4: 130c 0108                              |0356: const/16 v12, #int 2049 // #801
+0060d8: 6201 3700                              |0358: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+0060dc: 4401 010f                              |035a: aget v1, v1, v15
+0060e0: 960d 1001                              |035c: or-int v13, v16, v1
+0060e4: 0805 1100                              |035e: move-object/from16 v5, v17
+0060e8: 0206 1200                              |0360: move/from16 v6, v18
+0060ec: 7609 8b00 0500                         |0362: invoke-direct/range {v5, v6, v7, v8, v9, v10, v11, v12, v13}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+0060f2: 01e1                                   |0365: move v1, v14
+0060f4: 2900 cafe                              |0366: goto/16 0230 // -0136
+0060f8: 1201                                   |0368: const/4 v1, #int 0 // #0
+0060fa: 2900 19fd                              |0369: goto/16 0082 // -02e7
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #13              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '(ZIIIZ)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 9
+      ins           : 5
+      outs          : 1
+      insns size    : 46 16-bit code units
+006100:                                        |[006100] com.google.android.checkers.a.b:(ZIIIZ)I
+006110: 7110 9f00 0500                         |0000: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006116: 0a02                                   |0003: move-result v2
+006118: 7110 9f00 0600                         |0004: invoke-static {v6}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+00611e: 0a01                                   |0007: move-result v1
+006120: 7110 9f00 0700                         |0008: invoke-static {v7}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006126: 0a00                                   |000b: move-result v0
+006128: 3808 0800                              |000c: if-eqz v8, 0014 // +0008
+00612c: d902 021f                              |000e: rsub-int/lit8 v2, v2, #int 31 // #1f
+006130: d901 011f                              |0010: rsub-int/lit8 v1, v1, #int 31 // #1f
+006134: d900 001f                              |0012: rsub-int/lit8 v0, v0, #int 31 // #1f
+006138: d800 00fc                              |0014: add-int/lit8 v0, v0, #int -4 // #fc
+00613c: 3804 0d00                              |0016: if-eqz v4, 0023 // +000d
+006140: 6203 6300                              |0018: sget-object v3, Lcom/google/android/checkers/g;.k:[B // field@0063
+006144: d200 8003                              |001a: mul-int/lit16 v0, v0, #int 896 // #0380
+006148: da02 0220                              |001c: mul-int/lit8 v2, v2, #int 32 // #20
+00614c: b020                                   |001e: add-int/2addr v0, v2
+00614e: b010                                   |001f: add-int/2addr v0, v1
+006150: 4800 0300                              |0020: aget-byte v0, v3, v0
+006154: 0f00                                   |0022: return v0
+006156: 6203 6400                              |0023: sget-object v3, Lcom/google/android/checkers/g;.l:[B // field@0064
+00615a: d200 8003                              |0025: mul-int/lit16 v0, v0, #int 896 // #0380
+00615e: da02 0220                              |0027: mul-int/lit8 v2, v2, #int 32 // #20
+006162: b020                                   |0029: add-int/2addr v0, v2
+006164: b010                                   |002a: add-int/2addr v0, v1
+006166: 4800 0300                              |002b: aget-byte v0, v3, v0
+00616a: 28f5                                   |002d: goto 0022 // -000b
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #14              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '(ZIIZ)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 8
+      ins           : 4
+      outs          : 1
+      insns size    : 56 16-bit code units
+00616c:                                        |[00616c] com.google.android.checkers.a.b:(ZIIZ)I
+00617c: 7110 9f00 0500                         |0000: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006182: 0a00                                   |0003: move-result v0
+006184: d801 05ff                              |0004: add-int/lit8 v1, v5, #int -1 // #ff
+006188: b551                                   |0006: and-int/2addr v1, v5
+00618a: 7110 9f00 0100                         |0007: invoke-static {v1}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006190: 0a02                                   |000a: move-result v2
+006192: 7110 9f00 0600                         |000b: invoke-static {v6}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006198: 0a01                                   |000e: move-result v1
+00619a: 3807 0800                              |000f: if-eqz v7, 0017 // +0008
+00619e: d900 001f                              |0011: rsub-int/lit8 v0, v0, #int 31 // #1f
+0061a2: d902 021f                              |0013: rsub-int/lit8 v2, v2, #int 31 // #1f
+0061a6: d901 011f                              |0015: rsub-int/lit8 v1, v1, #int 31 // #1f
+0061aa: d801 01fc                              |0017: add-int/lit8 v1, v1, #int -4 // #fc
+0061ae: 3520 1100                              |0019: if-ge v0, v2, 002a // +0011
+0061b2: 6203 3800                              |001b: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+0061b6: 4402 0302                              |001d: aget v2, v3, v2
+0061ba: b020                                   |001f: add-int/2addr v0, v2
+0061bc: 3804 1000                              |0020: if-eqz v4, 0030 // +0010
+0061c0: 6202 5f00                              |0022: sget-object v2, Lcom/google/android/checkers/g;.g:[B // field@005f
+0061c4: d211 f001                              |0024: mul-int/lit16 v1, v1, #int 496 // #01f0
+0061c8: b010                                   |0026: add-int/2addr v0, v1
+0061ca: 4800 0200                              |0027: aget-byte v0, v2, v0
+0061ce: 0f00                                   |0029: return v0
+0061d0: 6203 3800                              |002a: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+0061d4: 4400 0300                              |002c: aget v0, v3, v0
+0061d8: b020                                   |002e: add-int/2addr v0, v2
+0061da: 28f1                                   |002f: goto 0020 // -000f
+0061dc: 6202 6000                              |0030: sget-object v2, Lcom/google/android/checkers/g;.h:[B // field@0060
+0061e0: d211 f001                              |0032: mul-int/lit16 v1, v1, #int 496 // #01f0
+0061e4: b010                                   |0034: add-int/2addr v0, v1
+0061e6: 4800 0200                              |0035: aget-byte v0, v2, v0
+0061ea: 28f2                                   |0037: goto 0029 // -000e
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #15              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '()V'
+      access        : 0x20012 (PRIVATE FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 2
+      ins           : 1
+      outs          : 1
+      insns size    : 19 16-bit code units
+0061ec:                                        |[0061ec] com.google.android.checkers.a.b:()V
+0061fc: 1d01                                   |0000: monitor-enter v1
+0061fe: 5510 4400                              |0001: iget-boolean v0, v1, Lcom/google/android/checkers/a;.k:Z // field@0044
+006202: 3800 0700                              |0003: if-eqz v0, 000a // +0007
+006206: 1200                                   |0005: const/4 v0, #int 0 // #0
+006208: 5c10 4400                              |0006: iput-boolean v0, v1, Lcom/google/android/checkers/a;.k:Z // field@0044
+00620c: 1e01                                   |0008: monitor-exit v1
+00620e: 0e00                                   |0009: return-void
+006210: 6e10 a200 0100                         |000a: invoke-virtual {v1}, Ljava/lang/Object;.wait:()V // method@00a2
+006216: 28f4                                   |000d: goto 0001 // -000c
+006218: 0d00                                   |000e: move-exception v0
+00621a: 28f2                                   |000f: goto 0001 // -000e
+00621c: 0d00                                   |0010: move-exception v0
+00621e: 1e01                                   |0011: monitor-exit v1
+006220: 2700                                   |0012: throw v0
+      catches       : 2
+        0x0001 - 0x0008
+          <any> -> 0x0010
+        0x000a - 0x000d
+          Ljava/lang/InterruptedException; -> 0x000e
+          <any> -> 0x0010
+      positions     : 
+      locals        : 
+
+    #16              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '(I)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 10
+      ins           : 2
+      outs          : 1
+      insns size    : 368 16-bit code units
+00623c:                                        |[00623c] com.google.android.checkers.a.b:(I)V
+00624c: 5280 3d00                              |0000: iget v0, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+006250: 5282 3e00                              |0002: iget v2, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+006254: 5283 3f00                              |0004: iget v3, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+006258: 5284 4000                              |0006: iget v4, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+00625c: 5481 4900                              |0008: iget-object v1, v8, Lcom/google/android/checkers/a;.p:[I // field@0049
+006260: 4401 0109                              |000a: aget v1, v1, v9
+006264: d511 ff00                              |000c: and-int/lit16 v1, v1, #int 255 // #00ff
+006268: 5485 4900                              |000e: iget-object v5, v8, Lcom/google/android/checkers/a;.p:[I // field@0049
+00626c: 4405 0509                              |0010: aget v5, v5, v9
+006270: d555 000f                              |0012: and-int/lit16 v5, v5, #int 3840 // #0f00
+006274: 5486 4800                              |0014: iget-object v6, v8, Lcom/google/android/checkers/a;.o:[I // field@0048
+006278: 4406 0609                              |0016: aget v6, v6, v9
+00627c: 2c05 4601 0000                         |0018: sparse-switch v5, 0000015e // +00000146
+006282: 5281 5100                              |001b: iget v1, v8, Lcom/google/android/checkers/a;.x:I // field@0051
+006286: 6205 3900                              |001d: sget-object v5, Lcom/google/android/checkers/a;.M:[I // field@0039
+00628a: 1306 8000                              |001f: const/16 v6, #int 128 // #80
+00628e: 4405 0506                              |0021: aget v5, v5, v6
+006292: b751                                   |0023: xor-int/2addr v1, v5
+006294: 5285 3d00                              |0024: iget v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+006298: b750                                   |0026: xor-int/2addr v0, v5
+00629a: 3900 ee00                              |0027: if-nez v0, 0115 // +00ee
+00629e: 5280 3e00                              |0029: iget v0, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+0062a2: b720                                   |002b: xor-int/2addr v0, v2
+0062a4: 3900 fb00                              |002c: if-nez v0, 0127 // +00fb
+0062a8: 5280 3f00                              |002e: iget v0, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+0062ac: b730                                   |0030: xor-int/2addr v0, v3
+0062ae: 3900 0801                              |0031: if-nez v0, 0139 // +0108
+0062b2: 5280 4000                              |0033: iget v0, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+0062b6: b740                                   |0035: xor-int/2addr v0, v4
+0062b8: 3900 1501                              |0036: if-nez v0, 014b // +0115
+0062bc: 5981 5100                              |0038: iput v1, v8, Lcom/google/android/checkers/a;.x:I // field@0051
+0062c0: 0e00                                   |003a: return-void
+0062c2: 1505 00f0                              |003b: const/high16 v5, #int -268435456 // #f000
+0062c6: b565                                   |003d: and-int/2addr v5, v6
+0062c8: 3805 3100                              |003e: if-eqz v5, 006f // +0031
+0062cc: 5285 3d00                              |0040: iget v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+0062d0: 5487 3a00                              |0042: iget-object v7, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+0062d4: 4407 0709                              |0044: aget v7, v7, v9
+0062d8: df07 07ff                              |0046: xor-int/lit8 v7, v7, #int -1 // #ff
+0062dc: b575                                   |0048: and-int/2addr v5, v7
+0062de: 5985 3d00                              |0049: iput v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+0062e2: 5285 3e00                              |004b: iget v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+0062e6: b665                                   |004d: or-int/2addr v5, v6
+0062e8: 5985 3e00                              |004e: iput v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+0062ec: 3801 cbff                              |0050: if-eqz v1, 001b // -0035
+0062f0: 5285 3f00                              |0052: iget v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+0062f4: 5486 3a00                              |0054: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+0062f8: 4406 0609                              |0056: aget v6, v6, v9
+0062fc: df06 06ff                              |0058: xor-int/lit8 v6, v6, #int -1 // #ff
+006300: b565                                   |005a: and-int/2addr v5, v6
+006302: 5985 3f00                              |005b: iput v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+006306: 5285 4000                              |005d: iget v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+00630a: 5486 3a00                              |005f: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+00630e: 4406 0609                              |0061: aget v6, v6, v9
+006312: df06 06ff                              |0063: xor-int/lit8 v6, v6, #int -1 // #ff
+006316: b565                                   |0065: and-int/2addr v5, v6
+006318: 5985 4000                              |0066: iput v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+00631c: 5285 5000                              |0068: iget v5, v8, Lcom/google/android/checkers/a;.w:I // field@0050
+006320: 9101 0501                              |006a: sub-int v1, v5, v1
+006324: 5981 5000                              |006c: iput v1, v8, Lcom/google/android/checkers/a;.w:I // field@0050
+006328: 28ad                                   |006e: goto 001b // -0053
+00632a: 5285 3d00                              |006f: iget v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+00632e: 5487 3a00                              |0071: iget-object v7, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+006332: 4407 0709                              |0073: aget v7, v7, v9
+006336: df07 07ff                              |0075: xor-int/lit8 v7, v7, #int -1 // #ff
+00633a: b575                                   |0077: and-int/2addr v5, v7
+00633c: b665                                   |0078: or-int/2addr v5, v6
+00633e: 5985 3d00                              |0079: iput v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+006342: 28d5                                   |007b: goto 0050 // -002b
+006344: 5285 3e00                              |007c: iget v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+006348: 5487 3a00                              |007e: iget-object v7, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+00634c: 4407 0709                              |0080: aget v7, v7, v9
+006350: df07 07ff                              |0082: xor-int/lit8 v7, v7, #int -1 // #ff
+006354: b575                                   |0084: and-int/2addr v5, v7
+006356: b665                                   |0085: or-int/2addr v5, v6
+006358: 5985 3e00                              |0086: iput v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+00635c: 3801 93ff                              |0088: if-eqz v1, 001b // -006d
+006360: 5285 3f00                              |008a: iget v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+006364: 5486 3a00                              |008c: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+006368: 4406 0609                              |008e: aget v6, v6, v9
+00636c: df06 06ff                              |0090: xor-int/lit8 v6, v6, #int -1 // #ff
+006370: b565                                   |0092: and-int/2addr v5, v6
+006372: 5985 3f00                              |0093: iput v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+006376: 5285 4000                              |0095: iget v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+00637a: 5486 3a00                              |0097: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+00637e: 4406 0609                              |0099: aget v6, v6, v9
+006382: df06 06ff                              |009b: xor-int/lit8 v6, v6, #int -1 // #ff
+006386: b565                                   |009d: and-int/2addr v5, v6
+006388: 5985 4000                              |009e: iput v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+00638c: 5285 5000                              |00a0: iget v5, v8, Lcom/google/android/checkers/a;.w:I // field@0050
+006390: 9101 0501                              |00a2: sub-int v1, v5, v1
+006394: 5981 5000                              |00a4: iput v1, v8, Lcom/google/android/checkers/a;.w:I // field@0050
+006398: 2900 75ff                              |00a6: goto/16 001b // -008b
+00639c: dd05 060f                              |00a8: and-int/lit8 v5, v6, #int 15 // #0f
+0063a0: 3805 3200                              |00aa: if-eqz v5, 00dc // +0032
+0063a4: 5285 3f00                              |00ac: iget v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+0063a8: 5487 3a00                              |00ae: iget-object v7, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+0063ac: 4407 0709                              |00b0: aget v7, v7, v9
+0063b0: df07 07ff                              |00b2: xor-int/lit8 v7, v7, #int -1 // #ff
+0063b4: b575                                   |00b4: and-int/2addr v5, v7
+0063b6: 5985 3f00                              |00b5: iput v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+0063ba: 5285 4000                              |00b7: iget v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+0063be: b665                                   |00b9: or-int/2addr v5, v6
+0063c0: 5985 4000                              |00ba: iput v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+0063c4: 3801 5fff                              |00bc: if-eqz v1, 001b // -00a1
+0063c8: 5285 3d00                              |00be: iget v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+0063cc: 5486 3a00                              |00c0: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+0063d0: 4406 0609                              |00c2: aget v6, v6, v9
+0063d4: df06 06ff                              |00c4: xor-int/lit8 v6, v6, #int -1 // #ff
+0063d8: b565                                   |00c6: and-int/2addr v5, v6
+0063da: 5985 3d00                              |00c7: iput v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+0063de: 5285 3e00                              |00c9: iget v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+0063e2: 5486 3a00                              |00cb: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+0063e6: 4406 0609                              |00cd: aget v6, v6, v9
+0063ea: df06 06ff                              |00cf: xor-int/lit8 v6, v6, #int -1 // #ff
+0063ee: b565                                   |00d1: and-int/2addr v5, v6
+0063f0: 5985 3e00                              |00d2: iput v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+0063f4: 5285 4f00                              |00d4: iget v5, v8, Lcom/google/android/checkers/a;.v:I // field@004f
+0063f8: 9101 0501                              |00d6: sub-int v1, v5, v1
+0063fc: 5981 4f00                              |00d8: iput v1, v8, Lcom/google/android/checkers/a;.v:I // field@004f
+006400: 2900 41ff                              |00da: goto/16 001b // -00bf
+006404: 5285 3f00                              |00dc: iget v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+006408: 5487 3a00                              |00de: iget-object v7, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+00640c: 4407 0709                              |00e0: aget v7, v7, v9
+006410: df07 07ff                              |00e2: xor-int/lit8 v7, v7, #int -1 // #ff
+006414: b575                                   |00e4: and-int/2addr v5, v7
+006416: b665                                   |00e5: or-int/2addr v5, v6
+006418: 5985 3f00                              |00e6: iput v5, v8, Lcom/google/android/checkers/a;.f:I // field@003f
+00641c: 28d4                                   |00e8: goto 00bc // -002c
+00641e: 5285 4000                              |00e9: iget v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+006422: 5487 3a00                              |00eb: iget-object v7, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+006426: 4407 0709                              |00ed: aget v7, v7, v9
+00642a: df07 07ff                              |00ef: xor-int/lit8 v7, v7, #int -1 // #ff
+00642e: b575                                   |00f1: and-int/2addr v5, v7
+006430: b665                                   |00f2: or-int/2addr v5, v6
+006432: 5985 4000                              |00f3: iput v5, v8, Lcom/google/android/checkers/a;.g:I // field@0040
+006436: 3801 26ff                              |00f5: if-eqz v1, 001b // -00da
+00643a: 5285 3d00                              |00f7: iget v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+00643e: 5486 3a00                              |00f9: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+006442: 4406 0609                              |00fb: aget v6, v6, v9
+006446: df06 06ff                              |00fd: xor-int/lit8 v6, v6, #int -1 // #ff
+00644a: b565                                   |00ff: and-int/2addr v5, v6
+00644c: 5985 3d00                              |0100: iput v5, v8, Lcom/google/android/checkers/a;.d:I // field@003d
+006450: 5285 3e00                              |0102: iget v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+006454: 5486 3a00                              |0104: iget-object v6, v8, Lcom/google/android/checkers/a;.a:[I // field@003a
+006458: 4406 0609                              |0106: aget v6, v6, v9
+00645c: df06 06ff                              |0108: xor-int/lit8 v6, v6, #int -1 // #ff
+006460: b565                                   |010a: and-int/2addr v5, v6
+006462: 5985 3e00                              |010b: iput v5, v8, Lcom/google/android/checkers/a;.e:I // field@003e
+006466: 5285 4f00                              |010d: iget v5, v8, Lcom/google/android/checkers/a;.v:I // field@004f
+00646a: 9101 0501                              |010f: sub-int v1, v5, v1
+00646e: 5981 4f00                              |0111: iput v1, v8, Lcom/google/android/checkers/a;.v:I // field@004f
+006472: 2900 08ff                              |0113: goto/16 001b // -00f8
+006476: 6205 3900                              |0115: sget-object v5, Lcom/google/android/checkers/a;.M:[I // field@0039
+00647a: 7110 9f00 0000                         |0117: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006480: 0a06                                   |011a: move-result v6
+006482: da06 0604                              |011b: mul-int/lit8 v6, v6, #int 4 // #04
+006486: d806 0600                              |011d: add-int/lit8 v6, v6, #int 0 // #00
+00648a: 4405 0506                              |011f: aget v5, v5, v6
+00648e: b751                                   |0121: xor-int/2addr v1, v5
+006490: d805 00ff                              |0122: add-int/lit8 v5, v0, #int -1 // #ff
+006494: b550                                   |0124: and-int/2addr v0, v5
+006496: 2900 02ff                              |0125: goto/16 0027 // -00fe
+00649a: 6202 3900                              |0127: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+00649e: 7110 9f00 0000                         |0129: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0064a4: 0a05                                   |012c: move-result v5
+0064a6: da05 0504                              |012d: mul-int/lit8 v5, v5, #int 4 // #04
+0064aa: d805 0501                              |012f: add-int/lit8 v5, v5, #int 1 // #01
+0064ae: 4402 0205                              |0131: aget v2, v2, v5
+0064b2: b721                                   |0133: xor-int/2addr v1, v2
+0064b4: d802 00ff                              |0134: add-int/lit8 v2, v0, #int -1 // #ff
+0064b8: b520                                   |0136: and-int/2addr v0, v2
+0064ba: 2900 f5fe                              |0137: goto/16 002c // -010b
+0064be: 6202 3900                              |0139: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+0064c2: 7110 9f00 0000                         |013b: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0064c8: 0a03                                   |013e: move-result v3
+0064ca: da03 0304                              |013f: mul-int/lit8 v3, v3, #int 4 // #04
+0064ce: d803 0302                              |0141: add-int/lit8 v3, v3, #int 2 // #02
+0064d2: 4402 0203                              |0143: aget v2, v2, v3
+0064d6: b721                                   |0145: xor-int/2addr v1, v2
+0064d8: d802 00ff                              |0146: add-int/lit8 v2, v0, #int -1 // #ff
+0064dc: b520                                   |0148: and-int/2addr v0, v2
+0064de: 2900 e8fe                              |0149: goto/16 0031 // -0118
+0064e2: 6202 3900                              |014b: sget-object v2, Lcom/google/android/checkers/a;.M:[I // field@0039
+0064e6: 7110 9f00 0000                         |014d: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0064ec: 0a03                                   |0150: move-result v3
+0064ee: da03 0304                              |0151: mul-int/lit8 v3, v3, #int 4 // #04
+0064f2: d803 0303                              |0153: add-int/lit8 v3, v3, #int 3 // #03
+0064f6: 4402 0203                              |0155: aget v2, v2, v3
+0064fa: b721                                   |0157: xor-int/2addr v1, v2
+0064fc: d802 00ff                              |0158: add-int/lit8 v2, v0, #int -1 // #ff
+006500: b520                                   |015a: and-int/2addr v0, v2
+006502: 2900 dbfe                              |015b: goto/16 0036 // -0125
+006506: 0000                                   |015d: nop // spacer
+006508: 0002 0400 0001 0000 0002 0000 0004 ... |015e: sparse-switch-data (18 units)
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #17              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '(IIIIIIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 18
+      ins           : 9
+      outs          : 9
+      insns size    : 99 16-bit code units
+00652c:                                        |[00652c] com.google.android.checkers.a.b:(IIIIIIII)V
+00653c: 1210                                   |0000: const/4 v0, #int 1 // #1
+00653e: 6201 3400                              |0001: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+006542: 4401 010d                              |0003: aget v1, v1, v13
+006546: b5c1                                   |0005: and-int/2addr v1, v12
+006548: 3801 2500                              |0006: if-eqz v1, 002b // +0025
+00654c: 6201 3500                              |0008: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+006550: 4401 010d                              |000a: aget v1, v1, v13
+006554: b5b1                                   |000c: and-int/2addr v1, v11
+006556: 3801 1e00                              |000d: if-eqz v1, 002b // +001e
+00655a: d804 0d07                              |000f: add-int/lit8 v4, v13, #int 7 // #07
+00655e: 6200 3500                              |0011: sget-object v0, Lcom/google/android/checkers/a;.I:[I // field@0035
+006562: 4405 000d                              |0013: aget v5, v0, v13
+006566: 6200 3400                              |0015: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+00656a: 4400 000d                              |0017: aget v0, v0, v13
+00656e: 9606 0f00                              |0019: or-int v6, v15, v0
+006572: d807 1001                              |001b: add-int/lit8 v7, v16, #int 1 // #01
+006576: 6200 3500                              |001d: sget-object v0, Lcom/google/android/checkers/a;.I:[I // field@0035
+00657a: 4400 000d                              |001f: aget v0, v0, v13
+00657e: 9608 1100                              |0021: or-int v8, v17, v0
+006582: 0790                                   |0023: move-object v0, v9
+006584: 01a1                                   |0024: move v1, v10
+006586: 01b2                                   |0025: move v2, v11
+006588: 01c3                                   |0026: move v3, v12
+00658a: 7609 8600 0000                         |0027: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.b:(IIIIIIII)V // method@0086
+006590: 1200                                   |002a: const/4 v0, #int 0 // #0
+006592: 6201 3600                              |002b: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+006596: 4401 010d                              |002d: aget v1, v1, v13
+00659a: b5c1                                   |002f: and-int/2addr v1, v12
+00659c: 3801 2500                              |0030: if-eqz v1, 0055 // +0025
+0065a0: 6201 3700                              |0032: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+0065a4: 4401 010d                              |0034: aget v1, v1, v13
+0065a8: b5b1                                   |0036: and-int/2addr v1, v11
+0065aa: 3801 1e00                              |0037: if-eqz v1, 0055 // +001e
+0065ae: d804 0d09                              |0039: add-int/lit8 v4, v13, #int 9 // #09
+0065b2: 6200 3700                              |003b: sget-object v0, Lcom/google/android/checkers/a;.K:[I // field@0037
+0065b6: 4405 000d                              |003d: aget v5, v0, v13
+0065ba: 6200 3600                              |003f: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+0065be: 4400 000d                              |0041: aget v0, v0, v13
+0065c2: 9606 0f00                              |0043: or-int v6, v15, v0
+0065c6: d807 1001                              |0045: add-int/lit8 v7, v16, #int 1 // #01
+0065ca: 6200 3700                              |0047: sget-object v0, Lcom/google/android/checkers/a;.K:[I // field@0037
+0065ce: 4400 000d                              |0049: aget v0, v0, v13
+0065d2: 9608 1100                              |004b: or-int v8, v17, v0
+0065d6: 0790                                   |004d: move-object v0, v9
+0065d8: 01a1                                   |004e: move v1, v10
+0065da: 01b2                                   |004f: move v2, v11
+0065dc: 01c3                                   |0050: move v3, v12
+0065de: 7609 8600 0000                         |0051: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.b:(IIIIIIII)V // method@0086
+0065e4: 1200                                   |0054: const/4 v0, #int 0 // #0
+0065e6: 3800 0d00                              |0055: if-eqz v0, 0062 // +000d
+0065ea: 0790                                   |0057: move-object v0, v9
+0065ec: 01a1                                   |0058: move v1, v10
+0065ee: 01e2                                   |0059: move v2, v14
+0065f0: 01f3                                   |005a: move v3, v15
+0065f2: 0204 1000                              |005b: move/from16 v4, v16
+0065f6: 0205 1100                              |005d: move/from16 v5, v17
+0065fa: 7606 7e00 0000                         |005f: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006600: 0e00                                   |0062: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #18              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '(IZI)Z'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 15
+      ins           : 4
+      outs          : 6
+      insns size    : 461 16-bit code units
+006604:                                        |[006604] com.google.android.checkers.a.b:(IZI)Z
+006614: 1404 e0e0 e000                         |0000: const v4, #float 0.000000 // #00e0e0e0
+00661a: 1216                                   |0003: const/4 v6, #int 1 // #1
+00661c: 1403 e0e0 e0e0                         |0004: const v3, #float -129633581999069331456.000000 // #e0e0e0e0
+006622: 130a 0008                              |0007: const/16 v10, #int 2048 // #800
+006626: 1309 0002                              |0009: const/16 v9, #int 512 // #200
+00662a: 380d e400                              |000b: if-eqz v13, 00ef // +00e4
+00662e: 52b0 3e00                              |000d: iget v0, v11, Lcom/google/android/checkers/a;.e:I // field@003e
+006632: 3900 1b00                              |000f: if-nez v0, 002a // +001b
+006636: 52b0 3d00                              |0011: iget v0, v11, Lcom/google/android/checkers/a;.d:I // field@003d
+00663a: e201 0e04                              |0013: ushr-int/lit8 v1, v14, #int 4 // #04
+00663e: 9502 0e03                              |0015: and-int v2, v14, v3
+006642: e202 0205                              |0017: ushr-int/lit8 v2, v2, #int 5 // #05
+006646: b621                                   |0019: or-int/2addr v1, v2
+006648: 1402 0007 0707                         |001a: const v2, #float 0.000000 // #07070700
+00664e: b5e2                                   |001d: and-int/2addr v2, v14
+006650: e202 0203                              |001e: ushr-int/lit8 v2, v2, #int 3 // #03
+006654: b621                                   |0020: or-int/2addr v1, v2
+006656: b510                                   |0021: and-int/2addr v0, v1
+006658: 3900 2f00                              |0022: if-nez v0, 0051 // +002f
+00665c: 52b0 3c00                              |0024: iget v0, v11, Lcom/google/android/checkers/a;.c:I // field@003c
+006660: 3800 a401                              |0026: if-eqz v0, 01ca // +01a4
+006664: 0160                                   |0028: move v0, v6
+006666: 0f00                                   |0029: return v0
+006668: 52b0 3e00                              |002a: iget v0, v11, Lcom/google/android/checkers/a;.e:I // field@003e
+00666c: 52b1 3d00                              |002c: iget v1, v11, Lcom/google/android/checkers/a;.d:I // field@003d
+006670: b610                                   |002e: or-int/2addr v0, v1
+006672: e201 0e04                              |002f: ushr-int/lit8 v1, v14, #int 4 // #04
+006676: 9502 0e03                              |0031: and-int v2, v14, v3
+00667a: e202 0205                              |0033: ushr-int/lit8 v2, v2, #int 5 // #05
+00667e: b621                                   |0035: or-int/2addr v1, v2
+006680: 1402 0007 0707                         |0036: const v2, #float 0.000000 // #07070700
+006686: b5e2                                   |0039: and-int/2addr v2, v14
+006688: e202 0203                              |003a: ushr-int/lit8 v2, v2, #int 3 // #03
+00668c: b621                                   |003c: or-int/2addr v1, v2
+00668e: b510                                   |003d: and-int/2addr v0, v1
+006690: 52b1 3e00                              |003e: iget v1, v11, Lcom/google/android/checkers/a;.e:I // field@003e
+006694: e002 0e04                              |0040: shl-int/lit8 v2, v14, #int 4 // #04
+006698: 1403 0707 0707                         |0042: const v3, #float 0.000000 // #07070707
+00669e: b5e3                                   |0045: and-int/2addr v3, v14
+0066a0: e003 0305                              |0046: shl-int/lit8 v3, v3, #int 5 // #05
+0066a4: b632                                   |0048: or-int/2addr v2, v3
+0066a6: 9503 0e04                              |0049: and-int v3, v14, v4
+0066aa: e003 0303                              |004b: shl-int/lit8 v3, v3, #int 3 // #03
+0066ae: b632                                   |004d: or-int/2addr v2, v3
+0066b0: b521                                   |004e: and-int/2addr v1, v2
+0066b2: b610                                   |004f: or-int/2addr v0, v1
+0066b4: 28d2                                   |0050: goto 0022 // -002e
+0066b6: 7110 9f00 0000                         |0051: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0066bc: 0a08                                   |0054: move-result v8
+0066be: 9803 0608                              |0055: shl-int v3, v6, v8
+0066c2: 9707 0003                              |0057: xor-int v7, v0, v3
+0066c6: 52b0 3e00                              |0059: iget v0, v11, Lcom/google/android/checkers/a;.e:I // field@003e
+0066ca: b530                                   |005b: and-int/2addr v0, v3
+0066cc: 3900 3400                              |005c: if-nez v0, 0090 // +0034
+0066d0: 6200 3400                              |005e: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+0066d4: 4400 0008                              |0060: aget v0, v0, v8
+0066d8: b5e0                                   |0062: and-int/2addr v0, v14
+0066da: 3800 1300                              |0063: if-eqz v0, 0076 // +0013
+0066de: 6200 3400                              |0065: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+0066e2: 4402 0008                              |0067: aget v2, v0, v8
+0066e6: 1304 0001                              |0069: const/16 v4, #int 256 // #100
+0066ea: 6200 3400                              |006b: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+0066ee: 4400 0008                              |006d: aget v0, v0, v8
+0066f2: 9605 0300                              |006f: or-int v5, v3, v0
+0066f6: 07b0                                   |0071: move-object v0, v11
+0066f8: 01c1                                   |0072: move v1, v12
+0066fa: 7606 7e00 0000                         |0073: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006700: 6200 3600                              |0076: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+006704: 4400 0008                              |0078: aget v0, v0, v8
+006708: b5e0                                   |007a: and-int/2addr v0, v14
+00670a: 3800 7100                              |007b: if-eqz v0, 00ec // +0071
+00670e: 6200 3600                              |007d: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+006712: 4402 0008                              |007f: aget v2, v0, v8
+006716: 1304 0001                              |0081: const/16 v4, #int 256 // #100
+00671a: 6200 3600                              |0083: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+00671e: 4400 0008                              |0085: aget v0, v0, v8
+006722: 9605 0300                              |0087: or-int v5, v3, v0
+006726: 07b0                                   |0089: move-object v0, v11
+006728: 01c1                                   |008a: move v1, v12
+00672a: 7606 7e00 0000                         |008b: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006730: 0170                                   |008e: move v0, v7
+006732: 2893                                   |008f: goto 0022 // -006d
+006734: 6200 3000                              |0090: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+006738: 4400 0008                              |0092: aget v0, v0, v8
+00673c: b5e0                                   |0094: and-int/2addr v0, v14
+00673e: 3800 1200                              |0095: if-eqz v0, 00a7 // +0012
+006742: 6200 3000                              |0097: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+006746: 4402 0008                              |0099: aget v2, v0, v8
+00674a: 6200 3000                              |009b: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+00674e: 4400 0008                              |009d: aget v0, v0, v8
+006752: 9605 0300                              |009f: or-int v5, v3, v0
+006756: 07b0                                   |00a1: move-object v0, v11
+006758: 01c1                                   |00a2: move v1, v12
+00675a: 0194                                   |00a3: move v4, v9
+00675c: 7606 7e00 0000                         |00a4: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006762: 6200 3200                              |00a7: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+006766: 4400 0008                              |00a9: aget v0, v0, v8
+00676a: b5e0                                   |00ab: and-int/2addr v0, v14
+00676c: 3800 1200                              |00ac: if-eqz v0, 00be // +0012
+006770: 6200 3200                              |00ae: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+006774: 4402 0008                              |00b0: aget v2, v0, v8
+006778: 6200 3200                              |00b2: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+00677c: 4400 0008                              |00b4: aget v0, v0, v8
+006780: 9605 0300                              |00b6: or-int v5, v3, v0
+006784: 07b0                                   |00b8: move-object v0, v11
+006786: 01c1                                   |00b9: move v1, v12
+006788: 0194                                   |00ba: move v4, v9
+00678a: 7606 7e00 0000                         |00bb: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006790: 6200 3400                              |00be: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+006794: 4400 0008                              |00c0: aget v0, v0, v8
+006798: b5e0                                   |00c2: and-int/2addr v0, v14
+00679a: 3800 1200                              |00c3: if-eqz v0, 00d5 // +0012
+00679e: 6200 3400                              |00c5: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+0067a2: 4402 0008                              |00c7: aget v2, v0, v8
+0067a6: 6200 3400                              |00c9: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+0067aa: 4400 0008                              |00cb: aget v0, v0, v8
+0067ae: 9605 0300                              |00cd: or-int v5, v3, v0
+0067b2: 07b0                                   |00cf: move-object v0, v11
+0067b4: 01c1                                   |00d0: move v1, v12
+0067b6: 0194                                   |00d1: move v4, v9
+0067b8: 7606 7e00 0000                         |00d2: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+0067be: 6200 3600                              |00d5: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+0067c2: 4400 0008                              |00d7: aget v0, v0, v8
+0067c6: b5e0                                   |00d9: and-int/2addr v0, v14
+0067c8: 3800 1200                              |00da: if-eqz v0, 00ec // +0012
+0067cc: 6200 3600                              |00dc: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+0067d0: 4402 0008                              |00de: aget v2, v0, v8
+0067d4: 6200 3600                              |00e0: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+0067d8: 4400 0008                              |00e2: aget v0, v0, v8
+0067dc: 9605 0300                              |00e4: or-int v5, v3, v0
+0067e0: 07b0                                   |00e6: move-object v0, v11
+0067e2: 01c1                                   |00e7: move v1, v12
+0067e4: 0194                                   |00e8: move v4, v9
+0067e6: 7606 7e00 0000                         |00e9: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+0067ec: 0170                                   |00ec: move v0, v7
+0067ee: 2900 35ff                              |00ed: goto/16 0022 // -00cb
+0067f2: 52b0 4000                              |00ef: iget v0, v11, Lcom/google/android/checkers/a;.g:I // field@0040
+0067f6: 3900 5400                              |00f1: if-nez v0, 0145 // +0054
+0067fa: 52b0 3f00                              |00f3: iget v0, v11, Lcom/google/android/checkers/a;.f:I // field@003f
+0067fe: e001 0e04                              |00f5: shl-int/lit8 v1, v14, #int 4 // #04
+006802: 1402 0707 0707                         |00f7: const v2, #float 0.000000 // #07070707
+006808: b5e2                                   |00fa: and-int/2addr v2, v14
+00680a: e002 0205                              |00fb: shl-int/lit8 v2, v2, #int 5 // #05
+00680e: b621                                   |00fd: or-int/2addr v1, v2
+006810: 9502 0e04                              |00fe: and-int v2, v14, v4
+006814: e002 0203                              |0100: shl-int/lit8 v2, v2, #int 3 // #03
+006818: b621                                   |0102: or-int/2addr v1, v2
+00681a: b510                                   |0103: and-int/2addr v0, v1
+00681c: 3800 20ff                              |0104: if-eqz v0, 0024 // -00e0
+006820: 7110 9f00 0000                         |0106: invoke-static {v0}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006826: 0a08                                   |0109: move-result v8
+006828: 9803 0608                              |010a: shl-int v3, v6, v8
+00682c: 9707 0003                              |010c: xor-int v7, v0, v3
+006830: 52b0 4000                              |010e: iget v0, v11, Lcom/google/android/checkers/a;.g:I // field@0040
+006834: b530                                   |0110: and-int/2addr v0, v3
+006836: 3900 5a00                              |0111: if-nez v0, 016b // +005a
+00683a: 6200 3000                              |0113: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+00683e: 4400 0008                              |0115: aget v0, v0, v8
+006842: b5e0                                   |0117: and-int/2addr v0, v14
+006844: 3800 1300                              |0118: if-eqz v0, 012b // +0013
+006848: 6200 3000                              |011a: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+00684c: 4402 0008                              |011c: aget v2, v0, v8
+006850: 1304 0004                              |011e: const/16 v4, #int 1024 // #400
+006854: 6200 3000                              |0120: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+006858: 4400 0008                              |0122: aget v0, v0, v8
+00685c: 9605 0300                              |0124: or-int v5, v3, v0
+006860: 07b0                                   |0126: move-object v0, v11
+006862: 01c1                                   |0127: move v1, v12
+006864: 7606 7e00 0000                         |0128: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+00686a: 6200 3200                              |012b: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+00686e: 4400 0008                              |012d: aget v0, v0, v8
+006872: b5e0                                   |012f: and-int/2addr v0, v14
+006874: 3800 9700                              |0130: if-eqz v0, 01c7 // +0097
+006878: 6200 3200                              |0132: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+00687c: 4402 0008                              |0134: aget v2, v0, v8
+006880: 1304 0004                              |0136: const/16 v4, #int 1024 // #400
+006884: 6200 3200                              |0138: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+006888: 4400 0008                              |013a: aget v0, v0, v8
+00688c: 9605 0300                              |013c: or-int v5, v3, v0
+006890: 07b0                                   |013e: move-object v0, v11
+006892: 01c1                                   |013f: move v1, v12
+006894: 7606 7e00 0000                         |0140: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+00689a: 0170                                   |0143: move v0, v7
+00689c: 28c0                                   |0144: goto 0104 // -0040
+00689e: 52b0 4000                              |0145: iget v0, v11, Lcom/google/android/checkers/a;.g:I // field@0040
+0068a2: 52b1 3f00                              |0147: iget v1, v11, Lcom/google/android/checkers/a;.f:I // field@003f
+0068a6: b610                                   |0149: or-int/2addr v0, v1
+0068a8: e001 0e04                              |014a: shl-int/lit8 v1, v14, #int 4 // #04
+0068ac: 1402 0707 0707                         |014c: const v2, #float 0.000000 // #07070707
+0068b2: b5e2                                   |014f: and-int/2addr v2, v14
+0068b4: e002 0205                              |0150: shl-int/lit8 v2, v2, #int 5 // #05
+0068b8: b621                                   |0152: or-int/2addr v1, v2
+0068ba: 9502 0e04                              |0153: and-int v2, v14, v4
+0068be: e002 0203                              |0155: shl-int/lit8 v2, v2, #int 3 // #03
+0068c2: b621                                   |0157: or-int/2addr v1, v2
+0068c4: b510                                   |0158: and-int/2addr v0, v1
+0068c6: 52b1 4000                              |0159: iget v1, v11, Lcom/google/android/checkers/a;.g:I // field@0040
+0068ca: e202 0e04                              |015b: ushr-int/lit8 v2, v14, #int 4 // #04
+0068ce: b5e3                                   |015d: and-int/2addr v3, v14
+0068d0: e203 0305                              |015e: ushr-int/lit8 v3, v3, #int 5 // #05
+0068d4: b632                                   |0160: or-int/2addr v2, v3
+0068d6: 1403 0007 0707                         |0161: const v3, #float 0.000000 // #07070700
+0068dc: b5e3                                   |0164: and-int/2addr v3, v14
+0068de: e203 0303                              |0165: ushr-int/lit8 v3, v3, #int 3 // #03
+0068e2: b632                                   |0167: or-int/2addr v2, v3
+0068e4: b521                                   |0168: and-int/2addr v1, v2
+0068e6: b610                                   |0169: or-int/2addr v0, v1
+0068e8: 289a                                   |016a: goto 0104 // -0066
+0068ea: 6200 3000                              |016b: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+0068ee: 4400 0008                              |016d: aget v0, v0, v8
+0068f2: b5e0                                   |016f: and-int/2addr v0, v14
+0068f4: 3800 1200                              |0170: if-eqz v0, 0182 // +0012
+0068f8: 6200 3000                              |0172: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+0068fc: 4402 0008                              |0174: aget v2, v0, v8
+006900: 6200 3000                              |0176: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+006904: 4400 0008                              |0178: aget v0, v0, v8
+006908: 9605 0300                              |017a: or-int v5, v3, v0
+00690c: 07b0                                   |017c: move-object v0, v11
+00690e: 01c1                                   |017d: move v1, v12
+006910: 01a4                                   |017e: move v4, v10
+006912: 7606 7e00 0000                         |017f: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006918: 6200 3200                              |0182: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+00691c: 4400 0008                              |0184: aget v0, v0, v8
+006920: b5e0                                   |0186: and-int/2addr v0, v14
+006922: 3800 1200                              |0187: if-eqz v0, 0199 // +0012
+006926: 6200 3200                              |0189: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+00692a: 4402 0008                              |018b: aget v2, v0, v8
+00692e: 6200 3200                              |018d: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+006932: 4400 0008                              |018f: aget v0, v0, v8
+006936: 9605 0300                              |0191: or-int v5, v3, v0
+00693a: 07b0                                   |0193: move-object v0, v11
+00693c: 01c1                                   |0194: move v1, v12
+00693e: 01a4                                   |0195: move v4, v10
+006940: 7606 7e00 0000                         |0196: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006946: 6200 3400                              |0199: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+00694a: 4400 0008                              |019b: aget v0, v0, v8
+00694e: b5e0                                   |019d: and-int/2addr v0, v14
+006950: 3800 1200                              |019e: if-eqz v0, 01b0 // +0012
+006954: 6200 3400                              |01a0: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+006958: 4402 0008                              |01a2: aget v2, v0, v8
+00695c: 6200 3400                              |01a4: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+006960: 4400 0008                              |01a6: aget v0, v0, v8
+006964: 9605 0300                              |01a8: or-int v5, v3, v0
+006968: 07b0                                   |01aa: move-object v0, v11
+00696a: 01c1                                   |01ab: move v1, v12
+00696c: 01a4                                   |01ac: move v4, v10
+00696e: 7606 7e00 0000                         |01ad: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006974: 6200 3600                              |01b0: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+006978: 4400 0008                              |01b2: aget v0, v0, v8
+00697c: b5e0                                   |01b4: and-int/2addr v0, v14
+00697e: 3800 1200                              |01b5: if-eqz v0, 01c7 // +0012
+006982: 6200 3600                              |01b7: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+006986: 4402 0008                              |01b9: aget v2, v0, v8
+00698a: 6200 3600                              |01bb: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+00698e: 4400 0008                              |01bd: aget v0, v0, v8
+006992: 9605 0300                              |01bf: or-int v5, v3, v0
+006996: 07b0                                   |01c1: move-object v0, v11
+006998: 01c1                                   |01c2: move v1, v12
+00699a: 01a4                                   |01c3: move v4, v10
+00699c: 7606 7e00 0000                         |01c4: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+0069a2: 0170                                   |01c7: move v0, v7
+0069a4: 2900 3cff                              |01c8: goto/16 0104 // -00c4
+0069a8: 1200                                   |01ca: const/4 v0, #int 0 // #0
+0069aa: 2900 5efe                              |01cb: goto/16 0029 // -01a2
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #19              : (in Lcom/google/android/checkers/a;)
+      name          : 'c'
+      type          : '(ZIIZ)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 8
+      ins           : 4
+      outs          : 1
+      insns size    : 54 16-bit code units
+0069b0:                                        |[0069b0] com.google.android.checkers.a.c:(ZIIZ)I
+0069c0: 7110 9f00 0500                         |0000: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0069c6: 0a00                                   |0003: move-result v0
+0069c8: d801 05ff                              |0004: add-int/lit8 v1, v5, #int -1 // #ff
+0069cc: b551                                   |0006: and-int/2addr v1, v5
+0069ce: 7110 9f00 0100                         |0007: invoke-static {v1}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0069d4: 0a02                                   |000a: move-result v2
+0069d6: 7110 9f00 0600                         |000b: invoke-static {v6}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+0069dc: 0a01                                   |000e: move-result v1
+0069de: 3807 0800                              |000f: if-eqz v7, 0017 // +0008
+0069e2: d900 001f                              |0011: rsub-int/lit8 v0, v0, #int 31 // #1f
+0069e6: d902 021f                              |0013: rsub-int/lit8 v2, v2, #int 31 // #1f
+0069ea: d901 011f                              |0015: rsub-int/lit8 v1, v1, #int 31 // #1f
+0069ee: 3520 1100                              |0017: if-ge v0, v2, 0028 // +0011
+0069f2: 6203 3800                              |0019: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+0069f6: 4402 0302                              |001b: aget v2, v3, v2
+0069fa: b020                                   |001d: add-int/2addr v0, v2
+0069fc: 3804 1000                              |001e: if-eqz v4, 002e // +0010
+006a00: 6202 6500                              |0020: sget-object v2, Lcom/google/android/checkers/g;.m:[B // field@0065
+006a04: da00 0020                              |0022: mul-int/lit8 v0, v0, #int 32 // #20
+006a08: b010                                   |0024: add-int/2addr v0, v1
+006a0a: 4800 0200                              |0025: aget-byte v0, v2, v0
+006a0e: 0f00                                   |0027: return v0
+006a10: 6203 3800                              |0028: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+006a14: 4400 0300                              |002a: aget v0, v3, v0
+006a18: b020                                   |002c: add-int/2addr v0, v2
+006a1a: 28f1                                   |002d: goto 001e // -000f
+006a1c: 6202 6600                              |002e: sget-object v2, Lcom/google/android/checkers/g;.n:[B // field@0066
+006a20: da00 0020                              |0030: mul-int/lit8 v0, v0, #int 32 // #20
+006a24: b010                                   |0032: add-int/2addr v0, v1
+006a26: 4800 0200                              |0033: aget-byte v0, v2, v0
+006a2a: 28f2                                   |0035: goto 0027 // -000e
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #20              : (in Lcom/google/android/checkers/a;)
+      name          : 'c'
+      type          : '()V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 2
+      ins           : 0
+      outs          : 2
+      insns size    : 8 16-bit code units
+006a2c:                                        |[006a2c] com.google.android.checkers.a.c:()V
+006a3c: 1600 f401                              |0000: const-wide/16 v0, #int 500 // #1f4
+006a40: 7120 ae00 1000                         |0002: invoke-static {v0, v1}, Ljava/lang/Thread;.sleep:(J)V // method@00ae
+006a46: 0e00                                   |0005: return-void
+006a48: 0d00                                   |0006: move-exception v0
+006a4a: 28fe                                   |0007: goto 0005 // -0002
+      catches       : 1
+        0x0002 - 0x0005
+          Ljava/lang/InterruptedException; -> 0x0006
+      positions     : 
+      locals        : 
+
+    #21              : (in Lcom/google/android/checkers/a;)
+      name          : 'c'
+      type          : '(IIIIIIII)V'
+      access        : 0x0012 (PRIVATE FINAL)
+      code          -
+      registers     : 18
+      ins           : 9
+      outs          : 9
+      insns size    : 203 16-bit code units
+006a58:                                        |[006a58] com.google.android.checkers.a.c:(IIIIIIII)V
+006a68: 1210                                   |0000: const/4 v0, #int 1 // #1
+006a6a: 6201 3000                              |0001: sget-object v1, Lcom/google/android/checkers/a;.D:[I // field@0030
+006a6e: 4401 010d                              |0003: aget v1, v1, v13
+006a72: b5c1                                   |0005: and-int/2addr v1, v12
+006a74: 3801 2a00                              |0006: if-eqz v1, 0030 // +002a
+006a78: 6201 3100                              |0008: sget-object v1, Lcom/google/android/checkers/a;.E:[I // field@0031
+006a7c: 4401 010d                              |000a: aget v1, v1, v13
+006a80: b5b1                                   |000c: and-int/2addr v1, v11
+006a82: 3801 2300                              |000d: if-eqz v1, 0030 // +0023
+006a86: 6200 3000                              |000f: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+006a8a: 4400 000d                              |0011: aget v0, v0, v13
+006a8e: 9703 0c00                              |0013: xor-int v3, v12, v0
+006a92: d804 0df7                              |0015: add-int/lit8 v4, v13, #int -9 // #f7
+006a96: 6200 3100                              |0017: sget-object v0, Lcom/google/android/checkers/a;.E:[I // field@0031
+006a9a: 4405 000d                              |0019: aget v5, v0, v13
+006a9e: 6200 3000                              |001b: sget-object v0, Lcom/google/android/checkers/a;.D:[I // field@0030
+006aa2: 4400 000d                              |001d: aget v0, v0, v13
+006aa6: 9606 0f00                              |001f: or-int v6, v15, v0
+006aaa: d807 1001                              |0021: add-int/lit8 v7, v16, #int 1 // #01
+006aae: 6200 3100                              |0023: sget-object v0, Lcom/google/android/checkers/a;.E:[I // field@0031
+006ab2: 4400 000d                              |0025: aget v0, v0, v13
+006ab6: 9608 1100                              |0027: or-int v8, v17, v0
+006aba: 0790                                   |0029: move-object v0, v9
+006abc: 01a1                                   |002a: move v1, v10
+006abe: 01b2                                   |002b: move v2, v11
+006ac0: 7609 8b00 0000                         |002c: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+006ac6: 1200                                   |002f: const/4 v0, #int 0 // #0
+006ac8: 6201 3200                              |0030: sget-object v1, Lcom/google/android/checkers/a;.F:[I // field@0032
+006acc: 4401 010d                              |0032: aget v1, v1, v13
+006ad0: b5c1                                   |0034: and-int/2addr v1, v12
+006ad2: 3801 2a00                              |0035: if-eqz v1, 005f // +002a
+006ad6: 6201 3300                              |0037: sget-object v1, Lcom/google/android/checkers/a;.G:[I // field@0033
+006ada: 4401 010d                              |0039: aget v1, v1, v13
+006ade: b5b1                                   |003b: and-int/2addr v1, v11
+006ae0: 3801 2300                              |003c: if-eqz v1, 005f // +0023
+006ae4: 6200 3200                              |003e: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+006ae8: 4400 000d                              |0040: aget v0, v0, v13
+006aec: 9703 0c00                              |0042: xor-int v3, v12, v0
+006af0: d804 0df9                              |0044: add-int/lit8 v4, v13, #int -7 // #f9
+006af4: 6200 3300                              |0046: sget-object v0, Lcom/google/android/checkers/a;.G:[I // field@0033
+006af8: 4405 000d                              |0048: aget v5, v0, v13
+006afc: 6200 3200                              |004a: sget-object v0, Lcom/google/android/checkers/a;.F:[I // field@0032
+006b00: 4400 000d                              |004c: aget v0, v0, v13
+006b04: 9606 0f00                              |004e: or-int v6, v15, v0
+006b08: d807 1001                              |0050: add-int/lit8 v7, v16, #int 1 // #01
+006b0c: 6200 3300                              |0052: sget-object v0, Lcom/google/android/checkers/a;.G:[I // field@0033
+006b10: 4400 000d                              |0054: aget v0, v0, v13
+006b14: 9608 1100                              |0056: or-int v8, v17, v0
+006b18: 0790                                   |0058: move-object v0, v9
+006b1a: 01a1                                   |0059: move v1, v10
+006b1c: 01b2                                   |005a: move v2, v11
+006b1e: 7609 8b00 0000                         |005b: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+006b24: 1200                                   |005e: const/4 v0, #int 0 // #0
+006b26: 6201 3400                              |005f: sget-object v1, Lcom/google/android/checkers/a;.H:[I // field@0034
+006b2a: 4401 010d                              |0061: aget v1, v1, v13
+006b2e: b5c1                                   |0063: and-int/2addr v1, v12
+006b30: 3801 2a00                              |0064: if-eqz v1, 008e // +002a
+006b34: 6201 3500                              |0066: sget-object v1, Lcom/google/android/checkers/a;.I:[I // field@0035
+006b38: 4401 010d                              |0068: aget v1, v1, v13
+006b3c: b5b1                                   |006a: and-int/2addr v1, v11
+006b3e: 3801 2300                              |006b: if-eqz v1, 008e // +0023
+006b42: 6200 3400                              |006d: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+006b46: 4400 000d                              |006f: aget v0, v0, v13
+006b4a: 9703 0c00                              |0071: xor-int v3, v12, v0
+006b4e: d804 0d07                              |0073: add-int/lit8 v4, v13, #int 7 // #07
+006b52: 6200 3500                              |0075: sget-object v0, Lcom/google/android/checkers/a;.I:[I // field@0035
+006b56: 4405 000d                              |0077: aget v5, v0, v13
+006b5a: 6200 3400                              |0079: sget-object v0, Lcom/google/android/checkers/a;.H:[I // field@0034
+006b5e: 4400 000d                              |007b: aget v0, v0, v13
+006b62: 9606 0f00                              |007d: or-int v6, v15, v0
+006b66: d807 1001                              |007f: add-int/lit8 v7, v16, #int 1 // #01
+006b6a: 6200 3500                              |0081: sget-object v0, Lcom/google/android/checkers/a;.I:[I // field@0035
+006b6e: 4400 000d                              |0083: aget v0, v0, v13
+006b72: 9608 1100                              |0085: or-int v8, v17, v0
+006b76: 0790                                   |0087: move-object v0, v9
+006b78: 01a1                                   |0088: move v1, v10
+006b7a: 01b2                                   |0089: move v2, v11
+006b7c: 7609 8b00 0000                         |008a: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+006b82: 1200                                   |008d: const/4 v0, #int 0 // #0
+006b84: 6201 3600                              |008e: sget-object v1, Lcom/google/android/checkers/a;.J:[I // field@0036
+006b88: 4401 010d                              |0090: aget v1, v1, v13
+006b8c: b5c1                                   |0092: and-int/2addr v1, v12
+006b8e: 3801 2a00                              |0093: if-eqz v1, 00bd // +002a
+006b92: 6201 3700                              |0095: sget-object v1, Lcom/google/android/checkers/a;.K:[I // field@0037
+006b96: 4401 010d                              |0097: aget v1, v1, v13
+006b9a: b5b1                                   |0099: and-int/2addr v1, v11
+006b9c: 3801 2300                              |009a: if-eqz v1, 00bd // +0023
+006ba0: 6200 3600                              |009c: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+006ba4: 4400 000d                              |009e: aget v0, v0, v13
+006ba8: 9703 0c00                              |00a0: xor-int v3, v12, v0
+006bac: d804 0d09                              |00a2: add-int/lit8 v4, v13, #int 9 // #09
+006bb0: 6200 3700                              |00a4: sget-object v0, Lcom/google/android/checkers/a;.K:[I // field@0037
+006bb4: 4405 000d                              |00a6: aget v5, v0, v13
+006bb8: 6200 3600                              |00a8: sget-object v0, Lcom/google/android/checkers/a;.J:[I // field@0036
+006bbc: 4400 000d                              |00aa: aget v0, v0, v13
+006bc0: 9606 0f00                              |00ac: or-int v6, v15, v0
+006bc4: d807 1001                              |00ae: add-int/lit8 v7, v16, #int 1 // #01
+006bc8: 6200 3700                              |00b0: sget-object v0, Lcom/google/android/checkers/a;.K:[I // field@0037
+006bcc: 4400 000d                              |00b2: aget v0, v0, v13
+006bd0: 9608 1100                              |00b4: or-int v8, v17, v0
+006bd4: 0790                                   |00b6: move-object v0, v9
+006bd6: 01a1                                   |00b7: move v1, v10
+006bd8: 01b2                                   |00b8: move v2, v11
+006bda: 7609 8b00 0000                         |00b9: invoke-direct/range {v0, v1, v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.c:(IIIIIIII)V // method@008b
+006be0: 1200                                   |00bc: const/4 v0, #int 0 // #0
+006be2: 3800 0d00                              |00bd: if-eqz v0, 00ca // +000d
+006be6: 0790                                   |00bf: move-object v0, v9
+006be8: 01a1                                   |00c0: move v1, v10
+006bea: 01e2                                   |00c1: move v2, v14
+006bec: 01f3                                   |00c2: move v3, v15
+006bee: 0204 1000                              |00c3: move/from16 v4, v16
+006bf2: 0205 1100                              |00c5: move/from16 v5, v17
+006bf6: 7606 7e00 0000                         |00c7: invoke-direct/range {v0, v1, v2, v3, v4, v5}, Lcom/google/android/checkers/a;.a:(IIIII)V // method@007e
+006bfc: 0e00                                   |00ca: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #22              : (in Lcom/google/android/checkers/a;)
+      name          : 'd'
+      type          : '(ZIIZ)I'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 8
+      ins           : 4
+      outs          : 1
+      insns size    : 56 16-bit code units
+006c00:                                        |[006c00] com.google.android.checkers.a.d:(ZIIZ)I
+006c10: 7110 9f00 0500                         |0000: invoke-static {v5}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006c16: 0a00                                   |0003: move-result v0
+006c18: d801 05ff                              |0004: add-int/lit8 v1, v5, #int -1 // #ff
+006c1c: b551                                   |0006: and-int/2addr v1, v5
+006c1e: 7110 9f00 0100                         |0007: invoke-static {v1}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006c24: 0a02                                   |000a: move-result v2
+006c26: 7110 9f00 0600                         |000b: invoke-static {v6}, Ljava/lang/Integer;.numberOfTrailingZeros:(I)I // method@009f
+006c2c: 0a01                                   |000e: move-result v1
+006c2e: 3807 0800                              |000f: if-eqz v7, 0017 // +0008
+006c32: d900 001f                              |0011: rsub-int/lit8 v0, v0, #int 31 // #1f
+006c36: d902 021f                              |0013: rsub-int/lit8 v2, v2, #int 31 // #1f
+006c3a: d901 011f                              |0015: rsub-int/lit8 v1, v1, #int 31 // #1f
+006c3e: d801 01fc                              |0017: add-int/lit8 v1, v1, #int -4 // #fc
+006c42: 3520 1100                              |0019: if-ge v0, v2, 002a // +0011
+006c46: 6203 3800                              |001b: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+006c4a: 4402 0302                              |001d: aget v2, v3, v2
+006c4e: b020                                   |001f: add-int/2addr v0, v2
+006c50: 3804 1000                              |0020: if-eqz v4, 0030 // +0010
+006c54: 6202 6700                              |0022: sget-object v2, Lcom/google/android/checkers/g;.o:[B // field@0067
+006c58: da00 001c                              |0024: mul-int/lit8 v0, v0, #int 28 // #1c
+006c5c: b010                                   |0026: add-int/2addr v0, v1
+006c5e: 4800 0200                              |0027: aget-byte v0, v2, v0
+006c62: 0f00                                   |0029: return v0
+006c64: 6203 3800                              |002a: sget-object v3, Lcom/google/android/checkers/a;.L:[I // field@0038
+006c68: 4400 0300                              |002c: aget v0, v3, v0
+006c6c: b020                                   |002e: add-int/2addr v0, v2
+006c6e: 28f1                                   |002f: goto 0020 // -000f
+006c70: 6202 6800                              |0030: sget-object v2, Lcom/google/android/checkers/g;.p:[B // field@0068
+006c74: da00 001c                              |0032: mul-int/lit8 v0, v0, #int 28 // #1c
+006c78: b010                                   |0034: add-int/2addr v0, v1
+006c7a: 4800 0200                              |0035: aget-byte v0, v2, v0
+006c7e: 28f2                                   |0037: goto 0029 // -000e
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(ZZ)I'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 4
+      ins           : 3
+      outs          : 3
+      insns size    : 8 16-bit code units
+006c80:                                        |[006c80] com.google.android.checkers.a.a:(ZZ)I
+006c90: 5c13 4c00                              |0000: iput-boolean v3, v1, Lcom/google/android/checkers/a;.s:Z // field@004c
+006c94: 1200                                   |0002: const/4 v0, #int 0 // #0
+006c96: 7030 7500 0102                         |0003: invoke-direct {v1, v0, v2}, Lcom/google/android/checkers/a;.a:(IZ)I // method@0075
+006c9c: 0a00                                   |0006: move-result v0
+006c9e: 0f00                                   |0007: return v0
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #1              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '()V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 4
+      ins           : 1
+      outs          : 3
+      insns size    : 45 16-bit code units
+006ca0:                                        |[006ca0] com.google.android.checkers.a.a:()V
+006cb0: 1302 0c00                              |0000: const/16 v2, #int 12 // #c
+006cb4: 1201                                   |0002: const/4 v1, #int 0 // #0
+006cb6: 1300 ff0f                              |0003: const/16 v0, #int 4095 // #fff
+006cba: 5930 3d00                              |0005: iput v0, v3, Lcom/google/android/checkers/a;.d:I // field@003d
+006cbe: 5931 3e00                              |0007: iput v1, v3, Lcom/google/android/checkers/a;.e:I // field@003e
+006cc2: 1500 f0ff                              |0009: const/high16 v0, #int -1048576 // #fff0
+006cc6: 5930 3f00                              |000b: iput v0, v3, Lcom/google/android/checkers/a;.f:I // field@003f
+006cca: 5931 4000                              |000d: iput v1, v3, Lcom/google/android/checkers/a;.g:I // field@0040
+006cce: 5932 4f00                              |000f: iput v2, v3, Lcom/google/android/checkers/a;.v:I // field@004f
+006cd2: 5932 5000                              |0011: iput v2, v3, Lcom/google/android/checkers/a;.w:I // field@0050
+006cd6: 7020 7600 1300                         |0013: invoke-direct {v3, v1}, Lcom/google/android/checkers/a;.a:(Z)I // method@0076
+006cdc: 0a00                                   |0016: move-result v0
+006cde: 5930 5100                              |0017: iput v0, v3, Lcom/google/android/checkers/a;.x:I // field@0051
+006ce2: 7030 7500 1301                         |0019: invoke-direct {v3, v1, v1}, Lcom/google/android/checkers/a;.a:(IZ)I // method@0075
+006ce8: 5530 2e00                              |001c: iget-boolean v0, v3, Lcom/google/android/checkers/a;.B:Z // field@002e
+006cec: 3800 0700                              |001e: if-eqz v0, 0025 // +0007
+006cf0: 0110                                   |0020: move v0, v1
+006cf2: 1502 1000                              |0021: const/high16 v2, #int 1048576 // #10
+006cf6: 3420 0300                              |0023: if-lt v0, v2, 0026 // +0003
+006cfa: 0e00                                   |0025: return-void
+006cfc: 5432 5200                              |0026: iget-object v2, v3, Lcom/google/android/checkers/a;.y:[I // field@0052
+006d00: 4b01 0200                              |0028: aput v1, v2, v0
+006d04: d800 0001                              |002a: add-int/lit8 v0, v0, #int 1 // #01
+006d08: 28f5                                   |002c: goto 0021 // -000b
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #2              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(I)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 2
+      insns size    : 4 16-bit code units
+006d0c:                                        |[006d0c] com.google.android.checkers.a.a:(I)V
+006d1c: 7020 8500 1000                         |0000: invoke-direct {v0, v1}, Lcom/google/android/checkers/a;.b:(I)V // method@0085
+006d22: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #3              : (in Lcom/google/android/checkers/a;)
+      name          : 'a'
+      type          : '(IIIIZ)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 8
+      ins           : 6
+      outs          : 2
+      insns size    : 37 16-bit code units
+006d24:                                        |[006d24] com.google.android.checkers.a.a:(IIIIZ)V
+006d34: 5923 3d00                              |0000: iput v3, v2, Lcom/google/android/checkers/a;.d:I // field@003d
+006d38: 5924 3e00                              |0002: iput v4, v2, Lcom/google/android/checkers/a;.e:I // field@003e
+006d3c: 5925 3f00                              |0004: iput v5, v2, Lcom/google/android/checkers/a;.f:I // field@003f
+006d40: 5926 4000                              |0006: iput v6, v2, Lcom/google/android/checkers/a;.g:I // field@0040
+006d44: 5220 3d00                              |0008: iget v0, v2, Lcom/google/android/checkers/a;.d:I // field@003d
+006d48: 5221 3e00                              |000a: iget v1, v2, Lcom/google/android/checkers/a;.e:I // field@003e
+006d4c: b610                                   |000c: or-int/2addr v0, v1
+006d4e: 7110 9e00 0000                         |000d: invoke-static {v0}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+006d54: 0a00                                   |0010: move-result v0
+006d56: 5920 4f00                              |0011: iput v0, v2, Lcom/google/android/checkers/a;.v:I // field@004f
+006d5a: 5220 3f00                              |0013: iget v0, v2, Lcom/google/android/checkers/a;.f:I // field@003f
+006d5e: 5221 4000                              |0015: iget v1, v2, Lcom/google/android/checkers/a;.g:I // field@0040
+006d62: b610                                   |0017: or-int/2addr v0, v1
+006d64: 7110 9e00 0000                         |0018: invoke-static {v0}, Ljava/lang/Integer;.bitCount:(I)I // method@009e
+006d6a: 0a00                                   |001b: move-result v0
+006d6c: 5920 5000                              |001c: iput v0, v2, Lcom/google/android/checkers/a;.w:I // field@0050
+006d70: 7020 7600 7200                         |001e: invoke-direct {v2, v7}, Lcom/google/android/checkers/a;.a:(Z)I // method@0076
+006d76: 0a00                                   |0021: move-result v0
+006d78: 5920 5100                              |0022: iput v0, v2, Lcom/google/android/checkers/a;.x:I // field@0051
+006d7c: 0e00                                   |0024: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #4              : (in Lcom/google/android/checkers/a;)
+      name          : 'b'
+      type          : '(ZZ)V'
+      access        : 0x20011 (PUBLIC FINAL DECLARED_SYNCHRONIZED)
+      code          -
+      registers     : 4
+      ins           : 3
+      outs          : 1
+      insns size    : 16 16-bit code units
+006d80:                                        |[006d80] com.google.android.checkers.a.b:(ZZ)V
+006d90: 1d01                                   |0000: monitor-enter v1
+006d92: 5c12 4d00                              |0001: iput-boolean v2, v1, Lcom/google/android/checkers/a;.t:Z // field@004d
+006d96: 5c13 4c00                              |0003: iput-boolean v3, v1, Lcom/google/android/checkers/a;.s:Z // field@004c
+006d9a: 1210                                   |0005: const/4 v0, #int 1 // #1
+006d9c: 5c10 4400                              |0006: iput-boolean v0, v1, Lcom/google/android/checkers/a;.k:Z // field@0044
+006da0: 6e10 a100 0100                         |0008: invoke-virtual {v1}, Ljava/lang/Object;.notify:()V // method@00a1
+006da6: 1e01                                   |000b: monitor-exit v1
+006da8: 0e00                                   |000c: return-void
+006daa: 0d00                                   |000d: move-exception v0
+006dac: 1e01                                   |000e: monitor-exit v1
+006dae: 2700                                   |000f: throw v0
+      catches       : 1
+        0x0001 - 0x000b
+          <any> -> 0x000d
+      positions     : 
+      locals        : 
+
+    #5              : (in Lcom/google/android/checkers/a;)
+      name          : 'run'
+      type          : '()V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 24
+      ins           : 1
+      outs          : 7
+      insns size    : 526 16-bit code units
+006dbc:                                        |[006dbc] com.google.android.checkers.a.run:()V
+006dcc: 7601 8400 1700                         |0000: invoke-direct/range {v23}, Lcom/google/android/checkers/a;.b:()V // method@0084
+006dd2: 0800 1700                              |0003: move-object/from16 v0, v23
+006dd6: 5202 3c00                              |0005: iget v2, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+006dda: 1213                                   |0007: const/4 v3, #int 1 // #1
+006ddc: 3332 1100                              |0008: if-ne v2, v3, 0019 // +0011
+006de0: 7100 8a00 0000                         |000a: invoke-static {}, Lcom/google/android/checkers/a;.c:()V // method@008a
+006de6: 0800 1700                              |000d: move-object/from16 v0, v23
+006dea: 5402 4300                              |000f: iget-object v2, v0, Lcom/google/android/checkers/a;.j:Lcom/google/android/checkers/CheckersView; // field@0043
+006dee: 1203                                   |0011: const/4 v3, #int 0 // #0
+006df0: 1204                                   |0012: const/4 v4, #int 0 // #0
+006df2: 12f5                                   |0013: const/4 v5, #int -1 // #ff
+006df4: 1216                                   |0014: const/4 v6, #int 1 // #1
+006df6: 6e56 5000 3254                         |0015: invoke-virtual {v2, v3, v4, v5, v6}, Lcom/google/android/checkers/CheckersView;.a:(IIII)V // method@0050
+006dfc: 28e8                                   |0018: goto 0000 // -0018
+006dfe: 0800 1700                              |0019: move-object/from16 v0, v23
+006e02: 5202 4100                              |001b: iget v2, v0, Lcom/google/android/checkers/a;.h:I // field@0041
+006e06: 3902 1c00                              |001d: if-nez v2, 0039 // +001c
+006e0a: 7100 8a00 0000                         |001f: invoke-static {}, Lcom/google/android/checkers/a;.c:()V // method@008a
+006e10: 0800 1700                              |0022: move-object/from16 v0, v23
+006e14: 5402 4200                              |0024: iget-object v2, v0, Lcom/google/android/checkers/a;.i:Ljava/util/Random; // field@0042
+006e18: 0800 1700                              |0026: move-object/from16 v0, v23
+006e1c: 5203 3c00                              |0028: iget v3, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+006e20: 6e20 b000 3200                         |002a: invoke-virtual {v2, v3}, Ljava/util/Random;.nextInt:(I)I // method@00b0
+006e26: 0a02                                   |002d: move-result v2
+006e28: 0800 1700                              |002e: move-object/from16 v0, v23
+006e2c: 5403 4300                              |0030: iget-object v3, v0, Lcom/google/android/checkers/a;.j:Lcom/google/android/checkers/CheckersView; // field@0043
+006e30: 1204                                   |0032: const/4 v4, #int 0 // #0
+006e32: 1205                                   |0033: const/4 v5, #int 0 // #0
+006e34: 1216                                   |0034: const/4 v6, #int 1 // #1
+006e36: 6e56 5000 2354                         |0035: invoke-virtual {v3, v2, v4, v5, v6}, Lcom/google/android/checkers/CheckersView;.a:(IIII)V // method@0050
+006e3c: 28c8                                   |0038: goto 0000 // -0038
+006e3e: 0800 1700                              |0039: move-object/from16 v0, v23
+006e42: 5202 3d00                              |003b: iget v2, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+006e46: 1303 ff0f                              |003d: const/16 v3, #int 4095 // #fff
+006e4a: 3332 2700                              |003f: if-ne v2, v3, 0066 // +0027
+006e4e: 7100 8a00 0000                         |0041: invoke-static {}, Lcom/google/android/checkers/a;.c:()V // method@008a
+006e54: 0800 1700                              |0044: move-object/from16 v0, v23
+006e58: 5403 4200                              |0046: iget-object v3, v0, Lcom/google/android/checkers/a;.i:Ljava/util/Random; // field@0042
+006e5c: 0800 1700                              |0048: move-object/from16 v0, v23
+006e60: 5204 3c00                              |004a: iget v4, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+006e64: 0800 1700                              |004c: move-object/from16 v0, v23
+006e68: 5502 4d00                              |004e: iget-boolean v2, v0, Lcom/google/android/checkers/a;.t:Z // field@004d
+006e6c: 3802 1400                              |0050: if-eqz v2, 0064 // +0014
+006e70: 1212                                   |0052: const/4 v2, #int 1 // #1
+006e72: 9102 0402                              |0053: sub-int v2, v4, v2
+006e76: 6e20 b000 2300                         |0055: invoke-virtual {v3, v2}, Ljava/util/Random;.nextInt:(I)I // method@00b0
+006e7c: 0a02                                   |0058: move-result v2
+006e7e: 0800 1700                              |0059: move-object/from16 v0, v23
+006e82: 5403 4300                              |005b: iget-object v3, v0, Lcom/google/android/checkers/a;.j:Lcom/google/android/checkers/CheckersView; // field@0043
+006e86: 1204                                   |005d: const/4 v4, #int 0 // #0
+006e88: 12e5                                   |005e: const/4 v5, #int -2 // #fe
+006e8a: 1216                                   |005f: const/4 v6, #int 1 // #1
+006e8c: 6e56 5000 2354                         |0060: invoke-virtual {v3, v2, v4, v5, v6}, Lcom/google/android/checkers/CheckersView;.a:(IIII)V // method@0050
+006e92: 289d                                   |0063: goto 0000 // -0063
+006e94: 1202                                   |0064: const/4 v2, #int 0 // #0
+006e96: 28ee                                   |0065: goto 0053 // -0012
+006e98: 7100 ab00 0000                         |0066: invoke-static {}, Ljava/lang/System;.currentTimeMillis:()J // method@00ab
+006e9e: 0b02                                   |0069: move-result-wide v2
+006ea0: 0800 1700                              |006a: move-object/from16 v0, v23
+006ea4: 5a02 4500                              |006c: iput-wide v2, v0, Lcom/google/android/checkers/a;.l:J // field@0045
+006ea8: 1202                                   |006e: const/4 v2, #int 0 // #0
+006eaa: 0800 1700                              |006f: move-object/from16 v0, v23
+006eae: 5902 4700                              |0071: iput v2, v0, Lcom/google/android/checkers/a;.n:I // field@0047
+006eb2: 1202                                   |0073: const/4 v2, #int 0 // #0
+006eb4: 0800 1700                              |0074: move-object/from16 v0, v23
+006eb8: 5c02 4600                              |0076: iput-boolean v2, v0, Lcom/google/android/checkers/a;.m:Z // field@0046
+006ebc: 0800 1700                              |0078: move-object/from16 v0, v23
+006ec0: 5502 4c00                              |007a: iget-boolean v2, v0, Lcom/google/android/checkers/a;.s:Z // field@004c
+006ec4: 3902 5100                              |007c: if-nez v2, 00cd // +0051
+006ec8: 6302 6a00                              |007e: sget-boolean v2, Lcom/google/android/checkers/g;.r:Z // field@006a
+006ecc: 3802 4d00                              |0080: if-eqz v2, 00cd // +004d
+006ed0: 1212                                   |0082: const/4 v2, #int 1 // #1
+006ed2: 0800 1700                              |0083: move-object/from16 v0, v23
+006ed6: 5c02 4e00                              |0085: iput-boolean v2, v0, Lcom/google/android/checkers/a;.u:Z // field@004e
+006eda: 0800 1700                              |0087: move-object/from16 v0, v23
+006ede: 520e 3c00                              |0089: iget v14, v0, Lcom/google/android/checkers/a;.c:I // field@003c
+006ee2: 120d                                   |008b: const/4 v13, #int 0 // #0
+006ee4: 120b                                   |008c: const/4 v11, #int 0 // #0
+006ee6: 120a                                   |008d: const/4 v10, #int 0 // #0
+006ee8: 1212                                   |008e: const/4 v2, #int 1 // #1
+006eea: 0800 1700                              |008f: move-object/from16 v0, v23
+006eee: 5902 2f00                              |0091: iput v2, v0, Lcom/google/android/checkers/a;.C:I // field@002f
+006ef2: 0800 1700                              |0093: move-object/from16 v0, v23
+006ef6: 520f 3d00                              |0095: iget v15, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+006efa: 0800 1700                              |0097: move-object/from16 v0, v23
+006efe: 5200 3e00                              |0099: iget v0, v0, Lcom/google/android/checkers/a;.e:I // field@003e
+006f02: 0210 0000                              |009b: move/from16 v16, v0
+006f06: 0800 1700                              |009d: move-object/from16 v0, v23
+006f0a: 5200 3f00                              |009f: iget v0, v0, Lcom/google/android/checkers/a;.f:I // field@003f
+006f0e: 0211 0000                              |00a1: move/from16 v17, v0
+006f12: 0800 1700                              |00a3: move-object/from16 v0, v23
+006f16: 5200 4000                              |00a5: iget v0, v0, Lcom/google/android/checkers/a;.g:I // field@0040
+006f1a: 0212 0000                              |00a7: move/from16 v18, v0
+006f1e: 0800 1700                              |00a9: move-object/from16 v0, v23
+006f22: 5200 4f00                              |00ab: iget v0, v0, Lcom/google/android/checkers/a;.v:I // field@004f
+006f26: 0213 0000                              |00ad: move/from16 v19, v0
+006f2a: 0800 1700                              |00af: move-object/from16 v0, v23
+006f2e: 5200 5000                              |00b1: iget v0, v0, Lcom/google/android/checkers/a;.w:I // field@0050
+006f32: 0214 0000                              |00b3: move/from16 v20, v0
+006f36: 0800 1700                              |00b5: move-object/from16 v0, v23
+006f3a: 5200 5100                              |00b7: iget v0, v0, Lcom/google/android/checkers/a;.x:I // field@0051
+006f3e: 0215 0000                              |00b9: move/from16 v21, v0
+006f42: 1216                                   |00bb: const/4 v6, #int 1 // #1
+006f44: 1302 4000                              |00bc: const/16 v2, #int 64 // #40
+006f48: 3726 1100                              |00be: if-le v6, v2, 00cf // +0011
+006f4c: 0800 1700                              |00c0: move-object/from16 v0, v23
+006f50: 5402 4300                              |00c2: iget-object v2, v0, Lcom/google/android/checkers/a;.j:Lcom/google/android/checkers/CheckersView; // field@0043
+006f54: 0800 1700                              |00c4: move-object/from16 v0, v23
+006f58: 5203 2f00                              |00c6: iget v3, v0, Lcom/google/android/checkers/a;.C:I // field@002f
+006f5c: 6e53 5000 d2ab                         |00c8: invoke-virtual {v2, v13, v11, v10, v3}, Lcom/google/android/checkers/CheckersView;.a:(IIII)V // method@0050
+006f62: 2900 35ff                              |00cb: goto/16 0000 // -00cb
+006f66: 1202                                   |00cd: const/4 v2, #int 0 // #0
+006f68: 28b5                                   |00ce: goto 0083 // -004b
+006f6a: 1309 0180                              |00cf: const/16 v9, #int -32767 // #8001
+006f6e: 120c                                   |00d1: const/4 v12, #int 0 // #0
+006f70: 34ec 1500                              |00d2: if-lt v12, v14, 00e7 // +0015
+006f74: 1302 0083                              |00d4: const/16 v2, #int -32000 // #8300
+006f78: 3729 eaff                              |00d6: if-le v9, v2, 00c0 // -0016
+006f7c: 1302 007d                              |00d8: const/16 v2, #int 32000 // #7d00
+006f80: 3529 e6ff                              |00da: if-ge v9, v2, 00c0 // -001a
+006f84: 1202                                   |00dc: const/4 v2, #int 0 // #0
+006f86: 0125                                   |00dd: move v5, v2
+006f88: 01d2                                   |00de: move v2, v13
+006f8a: d803 0eff                              |00df: add-int/lit8 v3, v14, #int -1 // #ff
+006f8e: 3435 6000                              |00e1: if-lt v5, v3, 0141 // +0060
+006f92: d806 0601                              |00e3: add-int/lit8 v6, v6, #int 1 // #01
+006f96: 012d                                   |00e5: move v13, v2
+006f98: 28d6                                   |00e6: goto 00bc // -002a
+006f9a: 0800 1700                              |00e7: move-object/from16 v0, v23
+006f9e: 7020 8500 c000                         |00e9: invoke-direct {v0, v12}, Lcom/google/android/checkers/a;.b:(I)V // method@0085
+006fa4: 1303 0180                              |00ec: const/16 v3, #int -32767 // #8001
+006fa8: 7b94                                   |00ee: neg-int v4, v9
+006faa: 1215                                   |00ef: const/4 v5, #int 1 // #1
+006fac: 1207                                   |00f0: const/4 v7, #int 0 // #0
+006fae: 0800 1700                              |00f1: move-object/from16 v0, v23
+006fb2: 5502 4d00                              |00f3: iget-boolean v2, v0, Lcom/google/android/checkers/a;.t:Z // field@004d
+006fb6: 3802 4a00                              |00f5: if-eqz v2, 013f // +004a
+006fba: 1208                                   |00f7: const/4 v8, #int 0 // #0
+006fbc: 0802 1700                              |00f8: move-object/from16 v2, v23
+006fc0: 7607 7400 0200                         |00fa: invoke-direct/range {v2, v3, v4, v5, v6, v7, v8}, Lcom/google/android/checkers/a;.a:(IIIIIZ)I // method@0074
+006fc6: 0a02                                   |00fd: move-result v2
+006fc8: 7b22                                   |00fe: neg-int v2, v2
+006fca: 0800 1700                              |00ff: move-object/from16 v0, v23
+006fce: 5403 4a00                              |0101: iget-object v3, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+006fd2: 4b02 030c                              |0103: aput v2, v3, v12
+006fd6: 0800 1700                              |0105: move-object/from16 v0, v23
+006fda: 590f 3d00                              |0107: iput v15, v0, Lcom/google/android/checkers/a;.d:I // field@003d
+006fde: 0200 1000                              |0109: move/from16 v0, v16
+006fe2: 0801 1700                              |010b: move-object/from16 v1, v23
+006fe6: 5910 3e00                              |010d: iput v0, v1, Lcom/google/android/checkers/a;.e:I // field@003e
+006fea: 0200 1100                              |010f: move/from16 v0, v17
+006fee: 0801 1700                              |0111: move-object/from16 v1, v23
+006ff2: 5910 3f00                              |0113: iput v0, v1, Lcom/google/android/checkers/a;.f:I // field@003f
+006ff6: 0200 1200                              |0115: move/from16 v0, v18
+006ffa: 0801 1700                              |0117: move-object/from16 v1, v23
+006ffe: 5910 4000                              |0119: iput v0, v1, Lcom/google/android/checkers/a;.g:I // field@0040
+007002: 0200 1300                              |011b: move/from16 v0, v19
+007006: 0801 1700                              |011d: move-object/from16 v1, v23
+00700a: 5910 4f00                              |011f: iput v0, v1, Lcom/google/android/checkers/a;.v:I // field@004f
+00700e: 0200 1400                              |0121: move/from16 v0, v20
+007012: 0801 1700                              |0123: move-object/from16 v1, v23
+007016: 5910 5000                              |0125: iput v0, v1, Lcom/google/android/checkers/a;.w:I // field@0050
+00701a: 0200 1500                              |0127: move/from16 v0, v21
+00701e: 0801 1700                              |0129: move-object/from16 v1, v23
+007022: 5910 5100                              |012b: iput v0, v1, Lcom/google/android/checkers/a;.x:I // field@0051
+007026: 0800 1700                              |012d: move-object/from16 v0, v23
+00702a: 5503 4600                              |012f: iget-boolean v3, v0, Lcom/google/android/checkers/a;.m:Z // field@0046
+00702e: 3903 8fff                              |0131: if-nez v3, 00c0 // -0071
+007032: 3792 d500                              |0133: if-le v2, v9, 0208 // +00d5
+007036: 0163                                   |0135: move v3, v6
+007038: 0124                                   |0136: move v4, v2
+00703a: 01c5                                   |0137: move v5, v12
+00703c: d80c 0c01                              |0138: add-int/lit8 v12, v12, #int 1 // #01
+007040: 0129                                   |013a: move v9, v2
+007042: 013a                                   |013b: move v10, v3
+007044: 014b                                   |013c: move v11, v4
+007046: 015d                                   |013d: move v13, v5
+007048: 2894                                   |013e: goto 00d2 // -006c
+00704a: 1218                                   |013f: const/4 v8, #int 1 // #1
+00704c: 28b8                                   |0140: goto 00f8 // -0048
+00704e: 1213                                   |0141: const/4 v3, #int 1 // #1
+007050: d804 0eff                              |0142: add-int/lit8 v4, v14, #int -1 // #ff
+007054: 3445 0800                              |0144: if-lt v5, v4, 014c // +0008
+007058: 3903 9dff                              |0146: if-nez v3, 00e3 // -0063
+00705c: d803 0501                              |0148: add-int/lit8 v3, v5, #int 1 // #01
+007060: 0135                                   |014a: move v5, v3
+007062: 2894                                   |014b: goto 00df // -006c
+007064: 0800 1700                              |014c: move-object/from16 v0, v23
+007068: 5407 4a00                              |014e: iget-object v7, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+00706c: 4407 0704                              |0150: aget v7, v7, v4
+007070: 0800 1700                              |0152: move-object/from16 v0, v23
+007074: 5408 4a00                              |0154: iget-object v8, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+007078: d809 04ff                              |0156: add-int/lit8 v9, v4, #int -1 // #ff
+00707c: 4408 0809                              |0158: aget v8, v8, v9
+007080: 3787 a800                              |015a: if-le v7, v8, 0202 // +00a8
+007084: 0800 1700                              |015c: move-object/from16 v0, v23
+007088: 5403 4a00                              |015e: iget-object v3, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+00708c: 4403 0304                              |0160: aget v3, v3, v4
+007090: 0800 1700                              |0162: move-object/from16 v0, v23
+007094: 5407 4a00                              |0164: iget-object v7, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+007098: 0800 1700                              |0166: move-object/from16 v0, v23
+00709c: 5408 4a00                              |0168: iget-object v8, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+0070a0: d809 04ff                              |016a: add-int/lit8 v9, v4, #int -1 // #ff
+0070a4: 4408 0809                              |016c: aget v8, v8, v9
+0070a8: 4b08 0704                              |016e: aput v8, v7, v4
+0070ac: 0800 1700                              |0170: move-object/from16 v0, v23
+0070b0: 5407 4a00                              |0172: iget-object v7, v0, Lcom/google/android/checkers/a;.q:[I // field@004a
+0070b4: d808 04ff                              |0174: add-int/lit8 v8, v4, #int -1 // #ff
+0070b8: 4b03 0708                              |0176: aput v3, v7, v8
+0070bc: 0800 1700                              |0178: move-object/from16 v0, v23
+0070c0: 5403 4800                              |017a: iget-object v3, v0, Lcom/google/android/checkers/a;.o:[I // field@0048
+0070c4: 4403 0304                              |017c: aget v3, v3, v4
+0070c8: 0800 1700                              |017e: move-object/from16 v0, v23
+0070cc: 5407 4800                              |0180: iget-object v7, v0, Lcom/google/android/checkers/a;.o:[I // field@0048
+0070d0: 0800 1700                              |0182: move-object/from16 v0, v23
+0070d4: 5408 4800                              |0184: iget-object v8, v0, Lcom/google/android/checkers/a;.o:[I // field@0048
+0070d8: d809 04ff                              |0186: add-int/lit8 v9, v4, #int -1 // #ff
+0070dc: 4408 0809                              |0188: aget v8, v8, v9
+0070e0: 4b08 0704                              |018a: aput v8, v7, v4
+0070e4: 0800 1700                              |018c: move-object/from16 v0, v23
+0070e8: 5407 4800                              |018e: iget-object v7, v0, Lcom/google/android/checkers/a;.o:[I // field@0048
+0070ec: d808 04ff                              |0190: add-int/lit8 v8, v4, #int -1 // #ff
+0070f0: 4b03 0708                              |0192: aput v3, v7, v8
+0070f4: 0800 1700                              |0194: move-object/from16 v0, v23
+0070f8: 5403 3a00                              |0196: iget-object v3, v0, Lcom/google/android/checkers/a;.a:[I // field@003a
+0070fc: 4403 0304                              |0198: aget v3, v3, v4
+007100: 0800 1700                              |019a: move-object/from16 v0, v23
+007104: 5407 3a00                              |019c: iget-object v7, v0, Lcom/google/android/checkers/a;.a:[I // field@003a
+007108: 0800 1700                              |019e: move-object/from16 v0, v23
+00710c: 5408 3a00                              |01a0: iget-object v8, v0, Lcom/google/android/checkers/a;.a:[I // field@003a
+007110: d809 04ff                              |01a2: add-int/lit8 v9, v4, #int -1 // #ff
+007114: 4408 0809                              |01a4: aget v8, v8, v9
+007118: 4b08 0704                              |01a6: aput v8, v7, v4
+00711c: 0800 1700                              |01a8: move-object/from16 v0, v23
+007120: 5407 3a00                              |01aa: iget-object v7, v0, Lcom/google/android/checkers/a;.a:[I // field@003a
+007124: d808 04ff                              |01ac: add-int/lit8 v8, v4, #int -1 // #ff
+007128: 4b03 0708                              |01ae: aput v3, v7, v8
+00712c: 0800 1700                              |01b0: move-object/from16 v0, v23
+007130: 5403 4900                              |01b2: iget-object v3, v0, Lcom/google/android/checkers/a;.p:[I // field@0049
+007134: 4403 0304                              |01b4: aget v3, v3, v4
+007138: 0800 1700                              |01b6: move-object/from16 v0, v23
+00713c: 5407 4900                              |01b8: iget-object v7, v0, Lcom/google/android/checkers/a;.p:[I // field@0049
+007140: 0800 1700                              |01ba: move-object/from16 v0, v23
+007144: 5408 4900                              |01bc: iget-object v8, v0, Lcom/google/android/checkers/a;.p:[I // field@0049
+007148: d809 04ff                              |01be: add-int/lit8 v9, v4, #int -1 // #ff
+00714c: 4408 0809                              |01c0: aget v8, v8, v9
+007150: 4b08 0704                              |01c2: aput v8, v7, v4
+007154: 0800 1700                              |01c4: move-object/from16 v0, v23
+007158: 5407 4900                              |01c6: iget-object v7, v0, Lcom/google/android/checkers/a;.p:[I // field@0049
+00715c: d808 04ff                              |01c8: add-int/lit8 v8, v4, #int -1 // #ff
+007160: 4b03 0708                              |01ca: aput v3, v7, v8
+007164: 0800 1700                              |01cc: move-object/from16 v0, v23
+007168: 5403 3b00                              |01ce: iget-object v3, v0, Lcom/google/android/checkers/a;.b:[I // field@003b
+00716c: 4403 0304                              |01d0: aget v3, v3, v4
+007170: 0800 1700                              |01d2: move-object/from16 v0, v23
+007174: 5407 3b00                              |01d4: iget-object v7, v0, Lcom/google/android/checkers/a;.b:[I // field@003b
+007178: 0800 1700                              |01d6: move-object/from16 v0, v23
+00717c: 5408 3b00                              |01d8: iget-object v8, v0, Lcom/google/android/checkers/a;.b:[I // field@003b
+007180: d809 04ff                              |01da: add-int/lit8 v9, v4, #int -1 // #ff
+007184: 4408 0809                              |01dc: aget v8, v8, v9
+007188: 4b08 0704                              |01de: aput v8, v7, v4
+00718c: 0800 1700                              |01e0: move-object/from16 v0, v23
+007190: 5407 3b00                              |01e2: iget-object v7, v0, Lcom/google/android/checkers/a;.b:[I // field@003b
+007194: d808 04ff                              |01e4: add-int/lit8 v8, v4, #int -1 // #ff
+007198: 4b03 0708                              |01e6: aput v3, v7, v8
+00719c: 3342 1300                              |01e8: if-ne v2, v4, 01fb // +0013
+0071a0: d802 02ff                              |01ea: add-int/lit8 v2, v2, #int -1 // #ff
+0071a4: 1203                                   |01ec: const/4 v3, #int 0 // #0
+0071a6: 0216 0300                              |01ed: move/from16 v22, v3
+0071aa: 0123                                   |01ef: move v3, v2
+0071ac: 0202 1600                              |01f0: move/from16 v2, v22
+0071b0: d804 04ff                              |01f2: add-int/lit8 v4, v4, #int -1 // #ff
+0071b4: 0216 0200                              |01f4: move/from16 v22, v2
+0071b8: 0132                                   |01f6: move v2, v3
+0071ba: 0203 1600                              |01f7: move/from16 v3, v22
+0071be: 2900 4bff                              |01f9: goto/16 0144 // -00b5
+0071c2: d803 04ff                              |01fb: add-int/lit8 v3, v4, #int -1 // #ff
+0071c6: 3332 efff                              |01fd: if-ne v2, v3, 01ec // -0011
+0071ca: d802 0201                              |01ff: add-int/lit8 v2, v2, #int 1 // #01
+0071ce: 28eb                                   |0201: goto 01ec // -0015
+0071d0: 0216 0300                              |0202: move/from16 v22, v3
+0071d4: 0123                                   |0204: move v3, v2
+0071d6: 0202 1600                              |0205: move/from16 v2, v22
+0071da: 28eb                                   |0207: goto 01f2 // -0015
+0071dc: 0192                                   |0208: move v2, v9
+0071de: 01a3                                   |0209: move v3, v10
+0071e0: 01b4                                   |020a: move v4, v11
+0071e2: 01d5                                   |020b: move v5, v13
+0071e4: 2900 2cff                              |020c: goto/16 0138 // -00d4
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #3 header:
+class_idx           : 33
+access_flags        : 16 (0x0010)
+superclass_idx      : 46
+interfaces_off      : 29520 (0x007350)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 35082 (0x00890a)
+static_fields_size  : 0
+instance_fields_size: 1
+direct_methods_size : 1
+virtual_methods_size: 1
+
+Class #3            -
+  Class descriptor  : 'Lcom/google/android/checkers/b;'
+  Access flags      : 0x0010 (FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Landroid/content/DialogInterface$OnClickListener;'
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/b;)
+      name          : 'a'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x1010 (FINAL SYNTHETIC)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/b;)
+      name          : '<init>'
+      type          : '(Lcom/google/android/checkers/CheckersView;)V'
+      access        : 0x10000 (CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 1
+      insns size    : 6 16-bit code units
+0071e8:                                        |[0071e8] com.google.android.checkers.b.<init>:(Lcom/google/android/checkers/CheckersView;)V
+0071f8: 5b01 5400                              |0000: iput-object v1, v0, Lcom/google/android/checkers/b;.a:Lcom/google/android/checkers/CheckersView; // field@0054
+0071fc: 7010 a000 0000                         |0002: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00a0
+007202: 0e00                                   |0005: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/b;)
+      name          : 'onClick'
+      type          : '(Landroid/content/DialogInterface;I)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 4
+      ins           : 3
+      outs          : 1
+      insns size    : 14 16-bit code units
+007204:                                        |[007204] com.google.android.checkers.b.onClick:(Landroid/content/DialogInterface;I)V
+007214: 5410 5400                              |0000: iget-object v0, v1, Lcom/google/android/checkers/b;.a:Lcom/google/android/checkers/CheckersView; // field@0054
+007218: 7110 5900 0000                         |0002: invoke-static {v0}, Lcom/google/android/checkers/CheckersView;.a:(Lcom/google/android/checkers/CheckersView;)Z // method@0059
+00721e: 0a00                                   |0005: move-result v0
+007220: 3800 0700                              |0006: if-eqz v0, 000d // +0007
+007224: 5410 5400                              |0008: iget-object v0, v1, Lcom/google/android/checkers/b;.a:Lcom/google/android/checkers/CheckersView; // field@0054
+007228: 6e10 6d00 0000                         |000a: invoke-virtual {v0}, Lcom/google/android/checkers/CheckersView;.postInvalidate:()V // method@006d
+00722e: 0e00                                   |000d: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #4 header:
+class_idx           : 34
+access_flags        : 16 (0x0010)
+superclass_idx      : 46
+interfaces_off      : 29520 (0x007350)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 35103 (0x00891f)
+static_fields_size  : 0
+instance_fields_size: 1
+direct_methods_size : 1
+virtual_methods_size: 1
+
+Class #4            -
+  Class descriptor  : 'Lcom/google/android/checkers/c;'
+  Access flags      : 0x0010 (FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Landroid/content/DialogInterface$OnClickListener;'
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/c;)
+      name          : 'a'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x1010 (FINAL SYNTHETIC)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/c;)
+      name          : '<init>'
+      type          : '(Lcom/google/android/checkers/CheckersView;)V'
+      access        : 0x10000 (CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 1
+      insns size    : 6 16-bit code units
+007230:                                        |[007230] com.google.android.checkers.c.<init>:(Lcom/google/android/checkers/CheckersView;)V
+007240: 5b01 5500                              |0000: iput-object v1, v0, Lcom/google/android/checkers/c;.a:Lcom/google/android/checkers/CheckersView; // field@0055
+007244: 7010 a000 0000                         |0002: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00a0
+00724a: 0e00                                   |0005: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/c;)
+      name          : 'onClick'
+      type          : '(Landroid/content/DialogInterface;I)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 3
+      ins           : 3
+      outs          : 0
+      insns size    : 1 16-bit code units
+00724c:                                        |[00724c] com.google.android.checkers.c.onClick:(Landroid/content/DialogInterface;I)V
+00725c: 0e00                                   |0000: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #5 header:
+class_idx           : 35
+access_flags        : 16 (0x0010)
+superclass_idx      : 46
+interfaces_off      : 29520 (0x007350)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 35124 (0x008934)
+static_fields_size  : 0
+instance_fields_size: 1
+direct_methods_size : 1
+virtual_methods_size: 1
+
+Class #5            -
+  Class descriptor  : 'Lcom/google/android/checkers/d;'
+  Access flags      : 0x0010 (FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Landroid/content/DialogInterface$OnClickListener;'
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/d;)
+      name          : 'a'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x1010 (FINAL SYNTHETIC)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/d;)
+      name          : '<init>'
+      type          : '(Lcom/google/android/checkers/CheckersView;)V'
+      access        : 0x10000 (CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 1
+      insns size    : 6 16-bit code units
+007260:                                        |[007260] com.google.android.checkers.d.<init>:(Lcom/google/android/checkers/CheckersView;)V
+007270: 5b01 5600                              |0000: iput-object v1, v0, Lcom/google/android/checkers/d;.a:Lcom/google/android/checkers/CheckersView; // field@0056
+007274: 7010 a000 0000                         |0002: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00a0
+00727a: 0e00                                   |0005: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/d;)
+      name          : 'onClick'
+      type          : '(Landroid/content/DialogInterface;I)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 3
+      ins           : 3
+      outs          : 0
+      insns size    : 1 16-bit code units
+00727c:                                        |[00727c] com.google.android.checkers.d.onClick:(Landroid/content/DialogInterface;I)V
+00728c: 0e00                                   |0000: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #6 header:
+class_idx           : 36
+access_flags        : 16 (0x0010)
+superclass_idx      : 46
+interfaces_off      : 29520 (0x007350)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 35145 (0x008949)
+static_fields_size  : 0
+instance_fields_size: 1
+direct_methods_size : 1
+virtual_methods_size: 1
+
+Class #6            -
+  Class descriptor  : 'Lcom/google/android/checkers/e;'
+  Access flags      : 0x0010 (FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Landroid/content/DialogInterface$OnClickListener;'
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/e;)
+      name          : 'a'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x1010 (FINAL SYNTHETIC)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/e;)
+      name          : '<init>'
+      type          : '(Lcom/google/android/checkers/CheckersView;)V'
+      access        : 0x10000 (CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 1
+      insns size    : 6 16-bit code units
+007290:                                        |[007290] com.google.android.checkers.e.<init>:(Lcom/google/android/checkers/CheckersView;)V
+0072a0: 5b01 5700                              |0000: iput-object v1, v0, Lcom/google/android/checkers/e;.a:Lcom/google/android/checkers/CheckersView; // field@0057
+0072a4: 7010 a000 0000                         |0002: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00a0
+0072aa: 0e00                                   |0005: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/e;)
+      name          : 'onClick'
+      type          : '(Landroid/content/DialogInterface;I)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 5
+      ins           : 3
+      outs          : 2
+      insns size    : 7 16-bit code units
+0072ac:                                        |[0072ac] com.google.android.checkers.e.onClick:(Landroid/content/DialogInterface;I)V
+0072bc: 5420 5700                              |0000: iget-object v0, v2, Lcom/google/android/checkers/e;.a:Lcom/google/android/checkers/CheckersView; // field@0057
+0072c0: 1211                                   |0002: const/4 v1, #int 1 // #1
+0072c2: 6e20 6800 1000                         |0003: invoke-virtual {v0, v1}, Lcom/google/android/checkers/CheckersView;.e:(Z)Z // method@0068
+0072c8: 0e00                                   |0006: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #7 header:
+class_idx           : 37
+access_flags        : 16 (0x0010)
+superclass_idx      : 46
+interfaces_off      : 29520 (0x007350)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 35166 (0x00895e)
+static_fields_size  : 0
+instance_fields_size: 1
+direct_methods_size : 1
+virtual_methods_size: 1
+
+Class #7            -
+  Class descriptor  : 'Lcom/google/android/checkers/f;'
+  Access flags      : 0x0010 (FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+    #0              : 'Landroid/content/DialogInterface$OnClickListener;'
+  Static fields     -
+  Instance fields   -
+    #0              : (in Lcom/google/android/checkers/f;)
+      name          : 'a'
+      type          : 'Lcom/google/android/checkers/CheckersView;'
+      access        : 0x1010 (FINAL SYNTHETIC)
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/f;)
+      name          : '<init>'
+      type          : '(Lcom/google/android/checkers/CheckersView;)V'
+      access        : 0x10000 (CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 2
+      outs          : 1
+      insns size    : 6 16-bit code units
+0072cc:                                        |[0072cc] com.google.android.checkers.f.<init>:(Lcom/google/android/checkers/CheckersView;)V
+0072dc: 5b01 5800                              |0000: iput-object v1, v0, Lcom/google/android/checkers/f;.a:Lcom/google/android/checkers/CheckersView; // field@0058
+0072e0: 7010 a000 0000                         |0002: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@00a0
+0072e6: 0e00                                   |0005: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Lcom/google/android/checkers/f;)
+      name          : 'onClick'
+      type          : '(Landroid/content/DialogInterface;I)V'
+      access        : 0x0011 (PUBLIC FINAL)
+      code          -
+      registers     : 4
+      ins           : 3
+      outs          : 2
+      insns size    : 6 16-bit code units
+0072e8:                                        |[0072e8] com.google.android.checkers.f.onClick:(Landroid/content/DialogInterface;I)V
+0072f8: 5410 5800                              |0000: iget-object v0, v1, Lcom/google/android/checkers/f;.a:Lcom/google/android/checkers/CheckersView; // field@0058
+0072fc: 7120 5600 3000                         |0002: invoke-static {v0, v3}, Lcom/google/android/checkers/CheckersView;.a:(Lcom/google/android/checkers/CheckersView;I)V // method@0056
+007302: 0e00                                   |0005: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  source_file_idx   : -1 (unknown)
+
+Class #8 header:
+class_idx           : 38
+access_flags        : 17 (0x0011)
+superclass_idx      : 46
+interfaces_off      : 0 (0x000000)
+source_file_idx     : -1
+annotations_off     : 0 (0x000000)
+class_data_off      : 35187 (0x008973)
+static_fields_size  : 19
+instance_fields_size: 0
+direct_methods_size : 1
+virtual_methods_size: 0
+
+Class #8            -
+  Class descriptor  : 'Lcom/google/android/checkers/g;'
+  Access flags      : 0x0011 (PUBLIC FINAL)
+  Superclass        : 'Ljava/lang/Object;'
+  Interfaces        -
+  Static fields     -
+    #0              : (in Lcom/google/android/checkers/g;)
+      name          : 'a'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #1              : (in Lcom/google/android/checkers/g;)
+      name          : 'b'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #2              : (in Lcom/google/android/checkers/g;)
+      name          : 'c'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #3              : (in Lcom/google/android/checkers/g;)
+      name          : 'd'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #4              : (in Lcom/google/android/checkers/g;)
+      name          : 'e'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #5              : (in Lcom/google/android/checkers/g;)
+      name          : 'f'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #6              : (in Lcom/google/android/checkers/g;)
+      name          : 'g'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #7              : (in Lcom/google/android/checkers/g;)
+      name          : 'h'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #8              : (in Lcom/google/android/checkers/g;)
+      name          : 'i'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #9              : (in Lcom/google/android/checkers/g;)
+      name          : 'j'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #10              : (in Lcom/google/android/checkers/g;)
+      name          : 'k'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #11              : (in Lcom/google/android/checkers/g;)
+      name          : 'l'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #12              : (in Lcom/google/android/checkers/g;)
+      name          : 'm'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #13              : (in Lcom/google/android/checkers/g;)
+      name          : 'n'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #14              : (in Lcom/google/android/checkers/g;)
+      name          : 'o'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #15              : (in Lcom/google/android/checkers/g;)
+      name          : 'p'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #16              : (in Lcom/google/android/checkers/g;)
+      name          : 'q'
+      type          : '[B'
+      access        : 0x0009 (PUBLIC STATIC)
+    #17              : (in Lcom/google/android/checkers/g;)
+      name          : 'r'
+      type          : 'Z'
+      access        : 0x0009 (PUBLIC STATIC)
+    #18              : (in Lcom/google/android/checkers/g;)
+      name          : 's'
+      type          : 'Ljava/io/BufferedInputStream;'
+      access        : 0x0008 (STATIC)
+  Instance fields   -
+  Direct methods    -
+    #0              : (in Lcom/google/android/checkers/g;)
+      name          : 'a'
+      type          : '([B)Z'
+      access        : 0x0008 (STATIC)
+      code          -
+      registers     : 5
+      ins           : 1
+      outs          : 2
+      insns size    : 29 16-bit code units
+007304:                                        |[007304] com.google.android.checkers.g.a:([B)Z
+007314: 2141                                   |0000: array-length v1, v4
+007316: 1200                                   |0001: const/4 v0, #int 0 // #0
+007318: 3410 0400                              |0002: if-lt v0, v1, 0006 // +0004
+00731c: 1210                                   |0004: const/4 v0, #int 1 // #1
+00731e: 0f00                                   |0005: return v0
+007320: 6202 6b00                              |0006: sget-object v2, Lcom/google/android/checkers/g;.s:Ljava/io/BufferedInputStream; // field@006b
+007324: 6e10 9c00 0200                         |0008: invoke-virtual {v2}, Ljava/io/BufferedInputStream;.read:()I // method@009c
+00732a: 0a02                                   |000b: move-result v2
+00732c: 12f3                                   |000c: const/4 v3, #int -1 // #ff
+00732e: 3332 0a00                              |000d: if-ne v2, v3, 0017 // +000a
+007332: 2200 2b00                              |000f: new-instance v0, Ljava/lang/Exception; // type@002b
+007336: 1a01 3401                              |0011: const-string v1, "tb eof" // string@0134
+00733a: 7020 9d00 1000                         |0013: invoke-direct {v0, v1}, Ljava/lang/Exception;.<init>:(Ljava/lang/String;)V // method@009d
+007340: 2700                                   |0016: throw v0
+007342: 8d22                                   |0017: int-to-byte v2, v2
+007344: 4f02 0400                              |0018: aput-byte v2, v4, v0
+007348: d800 0001                              |001a: add-int/lit8 v0, v0, #int 1 // #01
+00734c: 28e6                                   |001c: goto 0002 // -001a
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+  source_file_idx   : -1 (unknown)
+
diff --git a/test/dexdump/checkers.xml b/test/dexdump/checkers.xml
new file mode 100755
index 0000000..232254f
--- /dev/null
+++ b/test/dexdump/checkers.xml
@@ -0,0 +1,672 @@
+<api>
+<package name="com.google.android.checkers"
+>
+<class name="Checkers"
+ extends="android.app.Activity"
+ abstract="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<constructor name="Checkers"
+ type="com.google.android.checkers.Checkers"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</constructor>
+<method name="onConfigurationChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.content.res.Configuration">
+</parameter>
+</method>
+<method name="onCreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="onCreateOptionsMenu"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.view.Menu">
+</parameter>
+</method>
+<method name="onKeyDown"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+<parameter name="arg1" type="android.view.KeyEvent">
+</parameter>
+</method>
+<method name="onOptionsItemSelected"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.view.MenuItem">
+</parameter>
+</method>
+<method name="onPause"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="onStop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="onTrackballEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.view.MotionEvent">
+</parameter>
+</method>
+</class>
+<class name="CheckersView"
+ extends="android.view.View"
+ abstract="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<constructor name="CheckersView"
+ type="com.google.android.checkers.CheckersView"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.content.Context">
+</parameter>
+<parameter name="arg1" type="android.content.SharedPreferences">
+</parameter>
+</constructor>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+</method>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="float">
+</parameter>
+<parameter name="arg1" type="float">
+</parameter>
+</method>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+<parameter name="arg1" type="int">
+</parameter>
+<parameter name="arg2" type="int">
+</parameter>
+<parameter name="arg3" type="int">
+</parameter>
+</method>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="android.content.SharedPreferences.Editor">
+</parameter>
+</method>
+<method name="a"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+</method>
+<method name="a"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+</method>
+<method name="b"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+</method>
+<method name="b"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+</method>
+<method name="c"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+</method>
+<method name="c"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+</method>
+<method name="d"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+</method>
+<method name="draw"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.graphics.Canvas">
+</parameter>
+</method>
+<method name="e"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+</method>
+<method name="onSizeChanged"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="false"
+ visibility="protected"
+>
+<parameter name="arg0" type="int">
+</parameter>
+<parameter name="arg1" type="int">
+</parameter>
+<parameter name="arg2" type="int">
+</parameter>
+<parameter name="arg3" type="int">
+</parameter>
+</method>
+<method name="onTouchEvent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="android.view.MotionEvent">
+</parameter>
+</method>
+<method name="setLevel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+</method>
+</class>
+<class name="a"
+ extends="java.lang.Thread"
+ abstract="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<field name="a"
+ type="int[]"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="b"
+ type="int[]"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="c"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="d"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="e"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="f"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="g"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="h"
+ type="int"
+ transient="false"
+ volatile="true"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</field>
+<constructor name="a"
+ type="com.google.android.checkers.a"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="com.google.android.checkers.CheckersView">
+</parameter>
+</constructor>
+<method name="a"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+<parameter name="arg1" type="boolean">
+</parameter>
+</method>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+</method>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+</method>
+<method name="a"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+<parameter name="arg1" type="int">
+</parameter>
+<parameter name="arg2" type="int">
+</parameter>
+<parameter name="arg3" type="int">
+</parameter>
+<parameter name="arg4" type="boolean">
+</parameter>
+</method>
+<method name="b"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="true"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<parameter name="arg0" type="boolean">
+</parameter>
+<parameter name="arg1" type="boolean">
+</parameter>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+</method>
+</class>
+<class name="g"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ visibility="public"
+>
+<field name="a"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="b"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="c"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="d"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="e"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="f"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="g"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="h"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="i"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="j"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="k"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="l"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="m"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="n"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="o"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="p"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="q"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+<field name="r"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</field>
+</class>
+</package>
+</api>
diff --git a/test/dexdump/run-all-tests b/test/dexdump/run-all-tests
new file mode 100755
index 0000000..d9f1e96
--- /dev/null
+++ b/test/dexdump/run-all-tests
@@ -0,0 +1,103 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+    newProg=`/bin/ls -ld "${prog}"`
+    newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+    if expr "x${newProg}" : 'x/' >/dev/null; then
+        prog="${newProg}"
+    else
+        progdir=`dirname "${prog}"`
+        prog="${progdir}/${newProg}"
+    fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+
+# Set up a temp directory for output.
+tmpdir=/tmp/test-$$
+mkdir ${tmpdir}
+
+# Set up dexdump binary and flags to test.
+DEXD="${ANDROID_HOST_OUT}/bin/dexdump2"
+DEXDFLAGS1="-dfh"
+DEXDFLAGS2="-l xml"
+
+# Set up dexlist binary and flags to test.
+DEXL="${ANDROID_HOST_OUT}/bin/dexlist2"
+DEXLFLAGS=""
+
+# Run the tests.
+passed=0
+failed=0
+for i in *.dex; do
+    echo $i
+    basenm=`basename "${i}" .dex`
+    txtfile=${basenm}.txt
+    xmlfile=${basenm}.xml
+    lstfile=${basenm}.lst
+    gentxtfile=${tmpdir}/${txtfile}
+    genxmlfile=${tmpdir}/${xmlfile}
+    genlstfile=${tmpdir}/${lstfile}
+    ${DEXD} ${DEXDFLAGS1} ${i} > ${gentxtfile}
+    cmp ${txtfile} ${gentxtfile}
+    if [ "$?" = "0" ]; then
+        ((passed += 1))
+    else
+        ((failed += 1))
+        echo failed: ${i}
+    fi
+    ${DEXD} ${DEXDFLAGS2} ${i} > ${genxmlfile}
+    cmp ${xmlfile} ${genxmlfile}
+    if [ "$?" = "0" ]; then
+        ((passed += 1))
+    else
+        ((failed += 1))
+        echo failed: ${i}
+    fi
+    ${DEXL} ${DEXLFLAGS} ${i} > ${genlstfile}
+    cmp ${lstfile} ${genlstfile}
+    if [ "$?" = "0" ]; then
+        ((passed += 1))
+    else
+        ((failed += 1))
+        echo failed: ${i}
+    fi
+done
+
+# Report results.
+echo
+echo "passed: ${passed} test(s)"
+echo "failed: ${failed} test(s)"
+echo
+
+# Clean up, cd back to original dir.
+rm -rf ${tmpdir}
+cd ${oldwd}
+
+# Return status.
+if [ "${failed}" != "0" ]; then
+  echo failed
+  exit 1
+fi
+exit 0
+
diff --git a/test/etc/default-build b/test/etc/default-build
index 92954a9..c281bca 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -39,24 +39,57 @@
   exit 0
 fi
 
-if [ -d src ]; then
-  mkdir classes
-  ${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
-fi
-
-if [ -d src2 ]; then
-  mkdir -p classes
-  ${JAVAC} -d classes `find src2 -name '*.java'`
-fi
-
 if ! [ -d src ] && ! [ -d src2 ]; then
   # No src directory? Then forget about trying to run dx.
   SKIP_DX_MERGER="true"
 fi
 
-if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-    --dump-width=1000 ${DX_FLAGS} classes
+if [ -d src-multidex ]; then
+  # Jack does not support this configuration unless we specify how to partition the DEX file
+  # with a .jpp file.
+  USE_JACK="false"
+fi
+
+if [ ${USE_JACK} = "true" ]; then
+  # Jack toolchain
+  if [ -d src ]; then
+    ${JACK} --output-jack src.jack src
+    imported_jack_files="--import src.jack"
+  fi
+
+  if [ -d src2 ]; then
+    ${JACK} --output-jack src2.jack src2
+    imported_jack_files="--import src2.jack ${imported_jack_files}"
+  fi
+
+  # Compile jack files into a DEX file. We set jack.import.type.policy=keep-first to consider
+  # class definitions from src2 first.
+  ${JACK} ${imported_jack_files} -D jack.import.type.policy=keep-first --output-dex .
+else
+  # Legacy toolchain with javac+dx
+  if [ -d src ]; then
+    mkdir classes
+    ${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
+  fi
+
+  if [ -d src-multidex ]; then
+    mkdir classes2
+    ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
+        --dump-width=1000 ${DX_FLAGS} classes2
+    fi
+  fi
+
+  if [ -d src2 ]; then
+    mkdir -p classes
+    ${JAVAC} -d classes `find src2 -name '*.java'`
+  fi
+
+  if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+      --dump-width=1000 ${DX_FLAGS} classes
+  fi
 fi
 
 if [ -d smali ]; then
@@ -72,30 +105,34 @@
 fi
 
 if [ -d src-ex ]; then
-  mkdir classes-ex
-  ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
-      --dump-width=1000 ${DX_FLAGS} classes-ex
+  if [ ${USE_JACK} = "true" ]; then
+      # Rename previous "classes.dex" so it is not overwritten.
+      mv classes.dex classes-1.dex
+      #TODO find another way to append src.jack to the jack classpath
+      ${JACK}:src.jack --output-dex . src-ex
+      zip $TEST_NAME-ex.jar classes.dex
+      # Restore previous "classes.dex" so it can be zipped.
+      mv classes-1.dex classes.dex
+  else
+    mkdir classes-ex
+    ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
+        --dump-width=1000 ${DX_FLAGS} classes-ex
 
-    # quick shuffle so that the stored name is "classes.dex"
-    mv classes.dex classes-1.dex
-    mv classes-ex.dex classes.dex
-    zip $TEST_NAME-ex.jar classes.dex
-    mv classes.dex classes-ex.dex
-    mv classes-1.dex classes.dex
+      # quick shuffle so that the stored name is "classes.dex"
+      mv classes.dex classes-1.dex
+      mv classes-ex.dex classes.dex
+      zip $TEST_NAME-ex.jar classes.dex
+      mv classes.dex classes-ex.dex
+      mv classes-1.dex classes.dex
+    fi
   fi
 fi
 
 # Create a single jar with two dex files for multidex.
 if [ -d src-multidex ]; then
-  mkdir classes2
-  ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
-      --dump-width=1000 ${DX_FLAGS} classes2
-    zip $TEST_NAME.jar classes.dex classes2.dex
-  fi
+  zip $TEST_NAME.jar classes.dex classes2.dex
 elif [ ${NEED_DEX} = "true" ]; then
   zip $TEST_NAME.jar classes.dex
 fi
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index cf6be83..842d87e 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -458,7 +458,9 @@
       # When running under gdb, we cannot do piping and grepping...
       $cmdline "$@"
     else
-      $cmdline "$@" 2>&1
+      trap 'kill -INT -$pid' INT
+      $cmdline "$@" 2>&1 & pid=$!
+      wait $pid
       # Add extra detail if time out is enabled.
       if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "y" ]; then
         echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
diff --git a/test/run-test b/test/run-test
index ffa25eb..bdf680b 100755
--- a/test/run-test
+++ b/test/run-test
@@ -46,6 +46,7 @@
 export RUN="${progdir}/etc/run-test-jar"
 export DEX_LOCATION=/data/run-test/${test_dir}
 export NEED_DEX="true"
+export USE_JACK="false"
 
 # If dx was not set by the environment variable, assume it is in the path.
 if [ -z "$DX" ]; then
@@ -67,6 +68,46 @@
   export DXMERGER="dexmerger"
 fi
 
+# If jack was not set by the environment variable, assume it is in the path.
+if [ -z "$JACK" ]; then
+  export JACK="jack"
+fi
+
+# If the tree is compiled with Jack, build test with Jack by default.
+if [ "$ANDROID_COMPILE_WITH_JACK" = "true" ]; then
+  USE_JACK="true"
+fi
+
+# ANDROID_BUILD_TOP is not set in a build environment.
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    export ANDROID_BUILD_TOP=$oldwd
+fi
+
+# If JACK_VM_COMMAND is not set, assume it launches the prebuilt jack-launcher.
+if [ -z "$JACK_VM_COMMAND" ]; then
+  if [ ! -z "$TMPDIR" ]; then
+    jack_temp_dir="-Djava.io.tmpdir=$TMPDIR"
+  fi
+  export JACK_VM_COMMAND="java -Dfile.encoding=UTF-8 -Xms2560m -XX:+TieredCompilation $jack_temp_dir -jar $ANDROID_BUILD_TOP/prebuilts/sdk/tools/jack-launcher.jar"
+fi
+
+# If JACK_CLASSPATH is not set, assume it only contains core-libart.
+if [ -z "$JACK_CLASSPATH" ]; then
+  export JACK_CLASSPATH="$ANDROID_BUILD_TOP/out/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack"
+fi
+
+# If JACK_JAR is not set, assume it is located in the prebuilts directory.
+if [ -z "$JACK_JAR" ]; then
+  export JACK_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jack.jar"
+fi
+
+# If JILL_JAR is not set, assume it is located in the prebuilts directory.
+if [ -z "$JILL_JAR" ]; then
+  export JILL_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jill.jar"
+fi
+
+export JACK="$JACK -g -cp $JACK_CLASSPATH"
+export JILL="java -jar $JILL_JAR"
 
 info="info.txt"
 build="build"
@@ -76,6 +117,7 @@
 output="output.txt"
 build_output="build-output.txt"
 cfg_output="graph.cfg"
+strace_output="strace-output.txt"
 lib="libartd.so"
 run_args="--quiet"
 build_args=""
@@ -96,6 +138,7 @@
 basic_verify="false"
 gc_verify="false"
 gc_stress="false"
+strace="false"
 always_clean="no"
 never_clean="no"
 have_dex2oat="yes"
@@ -116,6 +159,7 @@
         runtime="jvm"
         prebuild_mode="no"
         NEED_DEX="false"
+        USE_JACK="false"
         run_args="${run_args} --jvm"
         shift
     elif [ "x$1" = "x-O" ]; then
@@ -193,6 +237,10 @@
         run_args="${run_args} --gdb"
         dev_mode="yes"
         shift
+    elif [ "x$1" = "x--strace" ]; then
+        strace="yes"
+        run_args="${run_args} --invoke-with strace --invoke-with -o --invoke-with $tmp_dir/$strace_output"
+        shift
     elif [ "x$1" = "x--zygote" ]; then
         run_args="${run_args} --zygote"
         shift
@@ -237,6 +285,12 @@
     elif [ "x$1" = "x--build-only" ]; then
         build_only="yes"
         shift
+    elif [ "x$1" = "x--build-with-javac-dx" ]; then
+        USE_JACK="false"
+        shift
+    elif [ "x$1" = "x--build-with-jack" ]; then
+        USE_JACK="true"
+        shift
     elif [ "x$1" = "x--output-path" ]; then
         shift
         tmp_dir=$1
@@ -369,10 +423,7 @@
     fi
 elif [ "$runtime" = "art" ]; then
     if [ "$target_mode" = "no" ]; then
-        # ANDROID_BUILD_TOP and ANDROID_HOST_OUT are not set in a build environment.
-        if [ -z "$ANDROID_BUILD_TOP" ]; then
-            export ANDROID_BUILD_TOP=$oldwd
-        fi
+        # ANDROID_HOST_OUT is not set in a build environment.
         if [ -z "$ANDROID_HOST_OUT" ]; then
             export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
         fi
@@ -462,6 +513,8 @@
         echo "    --debuggable          Whether to compile Java code for a debugger."
         echo "    --gdb                 Run under gdb; incompatible with some tests."
         echo "    --build-only          Build test files only (off by default)."
+        echo "    --build-with-javac-dx Build test files with javac and dx (on by default)."
+        echo "    --build-with-jack     Build test files with jack and jill (off by default)."
         echo "    --interpreter         Enable interpreter only mode (off by default)."
         echo "    --jit                 Enable jit (off by default)."
         echo "    --optimizing          Enable optimizing compiler (default)."
@@ -556,6 +609,10 @@
   # if Checker is not invoked and the test only runs the program.
   build_args="${build_args} --dx-option --no-optimize"
 
+  # Jack does not necessarily generate the same DEX output than dx. Because these tests depend
+  # on a particular DEX output, keep building them with dx for now (b/19467889).
+  USE_JACK="false"
+
   if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$target_mode" = "no" -a "$debuggable" = "no" ]; then
     run_checker="yes"
     run_args="${run_args} -Xcompiler-option --dump-cfg=$tmp_dir/$cfg_output \
@@ -564,14 +621,20 @@
 fi
 
 # To cause tests to fail fast, limit the file sizes created by dx, dex2oat and ART output to 2MB.
-file_size_limit=2048
+build_file_size_limit=2048
+run_file_size_limit=2048
 if echo "$test_dir" | grep 089; then
-  file_size_limit=5120
+  build_file_size_limit=5120
+  run_file_size_limit=5120
 elif echo "$test_dir" | grep 083; then
-  file_size_limit=5120
+  build_file_size_limit=5120
+  run_file_size_limit=5120
 fi
-if ! ulimit -S "$file_size_limit"; then
-   echo "ulimit file size setting failed"
+if [ ${USE_JACK} = "false" ]; then
+  # Set ulimit if we build with dx only, Jack can generate big temp files.
+  if ! ulimit -S "$build_file_size_limit"; then
+    echo "ulimit file size setting failed"
+  fi
 fi
 
 good="no"
@@ -582,6 +645,9 @@
     build_exit="$?"
     echo "build exit status: $build_exit" 1>&2
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" 2>&1
         run_exit="$?"
@@ -604,6 +670,9 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         if [ "$run_checker" = "yes" ]; then
@@ -635,6 +704,9 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         run_exit="$?"
@@ -684,6 +756,11 @@
         echo '#################### diffs'
         diff --strip-trailing-cr -u "$expected" "$output" | tail -n 2000
         echo '####################'
+        if [ "$strace" = "yes" ]; then
+            echo '#################### strace output'
+            tail -n 2000 "$tmp_dir/$strace_output"
+            echo '####################'
+        fi
         echo ' '
     fi
 
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 682a27b..992a8a6 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -137,5 +137,18 @@
   result: EXEC_FAILED,
   bug:22106064,
   name: "libcore.java.lang.OldThreadGroupTest#test_enumerateLThreadArrayLZtest_enumerateLThreadArrayLZ"
+},
+{
+  description: "test_xattr fails on arm64 on the buildbots only: needs investigation",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.io.OsTest#test_xattr"],
+  bug: 22258911
+},
+{
+  description: "fails on L builds: needs investigation",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["org.apache.harmony.tests.java.lang.ClassTest#test_forNameLjava_lang_String"]
 }
 ]
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 7135dba..116a611 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -33,7 +33,7 @@
 # We use Quick's image on target because optimizing's image is not compiled debuggable.
 image="-Ximage:/data/art-test/core.art"
 args=$@
-debuggee_args="-Xcompiler-option --compiler-backend=Optimizing -Xcompiler-option --debuggable"
+debuggee_args="-Xcompiler-option --debuggable"
 device_dir="--device-dir=/data/local/tmp"
 # We use the art script on target to ensure the runner and the debuggee share the same
 # image.
@@ -92,6 +92,5 @@
       --vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \
       --vm-arg -Djpda.settings.debuggeeJavaPath="\"$art_debugee $image $debuggee_args\"" \
       --classpath $test_jar \
-      --vm-arg -Xcompiler-option --vm-arg --compiler-backend=Optimizing \
       --vm-arg -Xcompiler-option --vm-arg --debuggable \
       org.apache.harmony.jpda.tests.share.AllTests
diff --git a/tools/symbolize.sh b/tools/symbolize.sh
index 7365a9b..f5686e6 100755
--- a/tools/symbolize.sh
+++ b/tools/symbolize.sh
@@ -22,6 +22,7 @@
 INTERACTIVE="no"
 if [ "x$1" = "x--interactive" ] ; then
   INTERACTIVE="yes"
+  shift
 fi
 
 # Pull the file from the device and symbolize it.
@@ -57,4 +58,15 @@
   done
 }
 
-all
+if [ "x$1" = "x" ] ; then
+  # No further arguments, iterate over all oat files on device.
+  all
+else
+  # Take the parameters as a list of paths on device.
+  while (($#)); do
+    DIR=$(dirname $1)
+    NAME=$(basename $1)
+    one $DIR $NAME
+    shift
+  done
+fi