am c08e0c73: ART: Fix test

* commit 'c08e0c73bb397bc535c299dc0b9062f9ee2d86a0':
  ART: Fix test
diff --git a/Android.mk b/Android.mk
index 3467f1d..c01464a 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
@@ -119,6 +121,10 @@
 
 # Sync test files to the target, depends upon all things that must be pushed to the target.
 .PHONY: test-art-target-sync
+# Check if we need to sync. In case ART_TEST_ANDROID_ROOT is not empty,
+# the code below uses 'adb push' instead of 'adb sync', which does not
+# check if the files on the device have changed.
+ifneq ($(ART_TEST_NO_SYNC),true)
 ifeq ($(ART_TEST_ANDROID_ROOT),)
 test-art-target-sync: $(TEST_ART_TARGET_SYNC_DEPS)
 	adb root
@@ -130,9 +136,7 @@
 	adb wait-for-device push $(ANDROID_PRODUCT_OUT)/system $(ART_TEST_ANDROID_ROOT)
 	adb push $(ANDROID_PRODUCT_OUT)/data /data
 endif
-
-# Undefine variable now its served its purpose.
-TEST_ART_TARGET_SYNC_DEPS :=
+endif
 
 # "mm test-art" to build and run all tests on host and device
 .PHONY: test-art
@@ -164,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.
@@ -233,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
@@ -377,6 +387,15 @@
 build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUTS)
 
 ########################################################################
+# Rules for building all dependencies for tests.
+
+.PHONY: build-art-host-tests
+build-art-host-tests:   build-art-host $(TEST_ART_RUN_TEST_DEPENDENCIES) $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES) $(ART_TEST_HOST_GTEST_DEPENDENCIES)
+
+.PHONY: build-art-target-tests
+build-art-target-tests:   build-art-target $(TEST_ART_RUN_TEST_DEPENDENCIES) $(TEST_ART_TARGET_SYNC_DEPS)
+
+########################################################################
 # targets to switch back and forth from libdvm to libart
 
 .PHONY: use-art
@@ -467,3 +486,4 @@
 # Clear locally used variables.
 art_dont_bother :=
 art_test_bother :=
+TEST_ART_TARGET_SYNC_DEPS :=
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index b84154b..ee0cb09 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,9 @@
 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
 
 #
 # Used to enable JIT
@@ -68,6 +81,9 @@
 ART_HOST_CFLAGS :=
 ART_TARGET_CFLAGS :=
 
+ART_HOST_ASFLAGS :=
+ART_TARGET_ASFLAGS :=
+
 # Clang build support.
 
 # Host.
@@ -199,6 +215,9 @@
   -fvisibility=protected \
   $(art_default_gc_type_cflags)
 
+# Base set of asflags used by all things ART.
+art_asflags :=
+
 # Missing declarations: too many at the moment, as we use "extern" quite a bit.
 #  -Wmissing-declarations \
 
@@ -217,10 +236,12 @@
 
 ifeq ($(ART_HEAP_POISONING),true)
   art_cflags += -DART_HEAP_POISONING=1
+  art_asflags += -DART_HEAP_POISONING=1
 endif
 
 ifeq ($(ART_USE_READ_BARRIER),true)
   art_cflags += -DART_USE_READ_BARRIER=1
+  art_asflags += -DART_USE_READ_BARRIER=1
 endif
 
 ifeq ($(ART_USE_TLAB),true)
@@ -248,7 +269,9 @@
       ifndef SANITIZE_HOST
         art_host_non_debug_cflags += -Wframe-larger-than=2700
       endif
-      art_target_non_debug_cflags += -Wframe-larger-than=1728
+      ifndef SANITIZE_TARGET
+        art_target_non_debug_cflags += -Wframe-larger-than=1728
+      endif
     endif
   endif
 endif
@@ -258,11 +281,13 @@
 endif
 ART_HOST_CFLAGS += $(art_cflags) -DART_BASE_ADDRESS=$(LIBART_IMG_HOST_BASE_ADDRESS)
 ART_HOST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=default
+ART_HOST_ASFLAGS += $(art_asflags)
 
 ifndef LIBART_IMG_TARGET_BASE_ADDRESS
   $(error LIBART_IMG_TARGET_BASE_ADDRESS unset)
 endif
 ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS)
+ART_TARGET_ASFLAGS += $(art_asflags)
 
 ART_HOST_NON_DEBUG_CFLAGS := $(art_host_non_debug_cflags)
 ART_TARGET_NON_DEBUG_CFLAGS := $(art_target_non_debug_cflags)
@@ -292,6 +317,7 @@
 
 # Clear locals now they've served their purpose.
 art_cflags :=
+art_asflags :=
 art_debug_cflags :=
 art_non_debug_cflags :=
 art_host_non_debug_cflags :=
@@ -311,6 +337,7 @@
 define set-target-local-cflags-vars
   LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
   LOCAL_CFLAGS_x86 += $(ART_TARGET_CFLAGS_x86)
+  LOCAL_ASFLAGS += $(ART_TARGET_ASFLAGS)
   LOCAL_LDFLAGS += $(ART_TARGET_LDFLAGS)
   art_target_cflags_ndebug_or_debug := $(1)
   ifeq ($$(art_target_cflags_ndebug_or_debug),debug)
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index b9a449c..a561c5f 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -41,7 +41,7 @@
 ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$PPID)
 endif
 
-# Core.oat location on the device.
+# core.oat location on the device.
 TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$(DEX2OAT_TARGET_ARCH)/core.oat
 ifdef TARGET_2ND_ARCH
 2ND_TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$($(TARGET_2ND_ARCH_VAR_PREFIX)DEX2OAT_TARGET_ARCH)/core.oat
@@ -49,7 +49,7 @@
 
 CORE_OAT_SUFFIX := .oat
 
-# Core.oat locations under the out directory.
+# core.oat locations under the out directory.
 HOST_CORE_OAT_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core
 ifneq ($(HOST_PREFER_32_BIT),true)
 2ND_HOST_CORE_OAT_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core
@@ -63,7 +63,7 @@
 
 CORE_IMG_SUFFIX := .art
 
-# Core.art locations under the out directory.
+# core.art locations under the out directory.
 HOST_CORE_IMG_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/core
 ifneq ($(HOST_PREFER_32_BIT),true)
 2ND_HOST_CORE_IMG_OUT_BASE := $(HOST_OUT_JAVA_LIBRARIES)/$(2ND_ART_HOST_ARCH)/core
@@ -80,7 +80,7 @@
 TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
 
 # Jar files for core.art.
-TARGET_CORE_JARS := core-libart conscrypt okhttp core-junit bouncycastle
+TARGET_CORE_JARS := core-libart conscrypt okhttp bouncycastle
 HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS))
 
 HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index dfea6e1..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)
@@ -70,25 +80,43 @@
   endif
 
   ifeq ($$(art_target_or_host),target)
-  	$(call set-target-local-clang-vars)
-  	$(call set-target-local-cflags-vars,$(6))
+    $(call set-target-local-clang-vars)
+    $(call set-target-local-cflags-vars,$(6))
     LOCAL_SHARED_LIBRARIES += libdl
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+    LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
     else
       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
@@ -143,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 69472b7..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 \
@@ -150,6 +174,7 @@
   runtime/class_linker_test.cc \
   runtime/dex_file_test.cc \
   runtime/dex_file_verifier_test.cc \
+  runtime/dex_instruction_test.cc \
   runtime/dex_instruction_visitor_test.cc \
   runtime/dex_method_iterator_test.cc \
   runtime/entrypoints/math_entrypoints_test.cc \
@@ -291,6 +316,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_CPP_EXTENSION := cc
 LOCAL_CFLAGS := $(ART_HOST_CFLAGS)
+LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
 LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
 LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/compiler
 LOCAL_SHARED_LIBRARIES := libartd libartd-compiler
@@ -313,6 +339,7 @@
 ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
+ART_TEST_HOST_GTEST_DEPENDENCIES :=
 
 ART_GTEST_TARGET_ANDROID_ROOT := '/system'
 ifneq ($(ART_TEST_ANDROID_ROOT),)
@@ -374,11 +401,15 @@
   gtest_exe := $$(HOST_OUT_EXECUTABLES)/$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
   # Dependencies for all host gtests.
   gtest_deps := $$(HOST_CORE_DEX_LOCATIONS) \
-    $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION)
+    $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION) \
+    $$(gtest_exe) \
+    $$(ART_GTEST_$(1)_HOST_DEPS) \
+    $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX))
 
+  ART_TEST_HOST_GTEST_DEPENDENCIES += $$(gtest_deps)
 
 .PHONY: $$(gtest_rule)
-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX)) $$(gtest_deps)
+$$(gtest_rule): $$(gtest_exe) $$(gtest_deps)
 	$(hide) ($$(call ART_TEST_SKIP,$$@) && $$< && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@)
 
@@ -388,7 +419,7 @@
 
 
 .PHONY: valgrind-$$(gtest_rule)
-valgrind-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX)) $$(gtest_deps) $(ART_VALGRIND_DEPENDENCIES)
+valgrind-$$(gtest_rule): $$(gtest_exe) $$(gtest_deps) $(ART_VALGRIND_DEPENDENCIES)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
 	  VALGRIND_LIB=$(HOST_OUT)/lib64/valgrind \
 	  $(HOST_OUT_EXECUTABLES)/valgrind --leak-check=full --error-exitcode=1 $$< && \
@@ -484,6 +515,7 @@
   else # host
     LOCAL_CLANG := $$(ART_HOST_CLANG)
     LOCAL_CFLAGS += $$(ART_HOST_CFLAGS) $$(ART_HOST_DEBUG_CFLAGS)
+    LOCAL_ASFLAGS += $$(ART_HOST_ASFLAGS)
     LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libziparchive-host libz-host libvixld
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -lpthread -ldl
     LOCAL_IS_HOST_MODULE := true
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/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 1386439..98fd327 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -101,6 +101,19 @@
     return ::testing::AssertionFailure() << "key was not in the map";
   }
 
+  template <typename TMap, typename TKey, typename T>
+  ::testing::AssertionResult IsExpectedDefaultKeyValue(const T& expected,
+                                                       const TMap& map,
+                                                       const TKey& key) {
+    const T& actual = map.GetOrDefault(key);
+    if (!UsuallyEquals(expected, actual)) {
+      return ::testing::AssertionFailure()
+          << "expected " << detail::ToStringAny(expected) << " but got "
+          << detail::ToStringAny(actual);
+     }
+    return ::testing::AssertionSuccess();
+  }
+
 class CmdlineParserTest : public ::testing::Test {
  public:
   CmdlineParserTest() = default;
@@ -145,13 +158,23 @@
 
 #define EXPECT_KEY_EXISTS(map, key) EXPECT_TRUE((map).Exists(key))
 #define EXPECT_KEY_VALUE(map, key, expected) EXPECT_TRUE(IsExpectedKeyValue(expected, map, key))
+#define EXPECT_DEFAULT_KEY_VALUE(map, key, expected) EXPECT_TRUE(IsExpectedDefaultKeyValue(expected, map, key))
 
-#define EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv)               \
+#define _EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv)              \
   do {                                                        \
     EXPECT_TRUE(IsResultSuccessful(parser_->Parse(argv)));    \
     EXPECT_EQ(0u, parser_->GetArgumentsMap().Size());         \
+
+#define EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv)               \
+  _EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv);                   \
   } while (false)
 
+#define EXPECT_SINGLE_PARSE_DEFAULT_VALUE(expected, argv, key)\
+  _EXPECT_SINGLE_PARSE_EMPTY_SUCCESS(argv);                   \
+    RuntimeArgumentMap args = parser_->ReleaseArgumentsMap(); \
+    EXPECT_DEFAULT_KEY_VALUE(args, key, expected);            \
+  } while (false)                                             // NOLINT [readability/namespace] [5]
+
 #define _EXPECT_SINGLE_PARSE_EXISTS(argv, key)                \
   do {                                                        \
     EXPECT_TRUE(IsResultSuccessful(parser_->Parse(argv)));    \
@@ -262,6 +285,13 @@
   EXPECT_SINGLE_PARSE_FAIL("-verbose:blablabla", CmdlineResult::kUsage);  // invalid verbose opt
 
   {
+    const char* log_args = "-verbose:deopt";
+    LogVerbosity log_verbosity = LogVerbosity();
+    log_verbosity.deopt = true;
+    EXPECT_SINGLE_PARSE_VALUE(log_verbosity, log_args, M::Verbose);
+  }
+
+  {
     const char* log_args = "-verbose:oat";
     LogVerbosity log_verbosity = LogVerbosity();
     log_verbosity.oat = true;
@@ -502,6 +532,24 @@
   }
 }  // TEST_F
 
+/* -X[no]experimental-lambdas */
+TEST_F(CmdlineParserTest, TestExperimentalLambdas) {
+  // Off by default
+  EXPECT_SINGLE_PARSE_DEFAULT_VALUE(false,
+                                    "",
+                                    M::ExperimentalLambdas);
+
+  // Disabled explicitly
+  EXPECT_SINGLE_PARSE_VALUE(false,
+                            "-Xnoexperimental-lambdas",
+                            M::ExperimentalLambdas);
+
+  // Enabled explicitly
+  EXPECT_SINGLE_PARSE_VALUE(true,
+                            "-Xexperimental-lambdas",
+                            M::ExperimentalLambdas);
+}
+
 TEST_F(CmdlineParserTest, TestIgnoreUnrecognized) {
   RuntimeParser::Builder parserBuilder;
 
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 2cb86a6..a57b619 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -585,6 +585,8 @@
         log_verbosity.class_linker = true;
       } else if (verbose_options[j] == "compiler") {
         log_verbosity.compiler = true;
+      } else if (verbose_options[j] == "deopt") {
+        log_verbosity.deopt = true;
       } else if (verbose_options[j] == "gc") {
         log_verbosity.gc = true;
       } else if (verbose_options[j] == "heap") {
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 5770edf..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)
 
@@ -235,7 +249,11 @@
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     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
@@ -243,7 +261,7 @@
     endif
   endif
 
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
+  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime art/disassembler
 
   ifeq ($$(art_target_or_host),host)
     # For compiler driver TLS.
@@ -253,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)
@@ -266,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)
@@ -277,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/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 0a1e2e3..4b67884 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -182,13 +182,11 @@
       }
     }
 
-    // TODO: make selectable
-    Compiler::Kind compiler_kind = Compiler::kQuick;
     timer_.reset(new CumulativeLogger("Compilation times"));
     compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
                                               verification_results_.get(),
                                               method_inliner_map_.get(),
-                                              compiler_kind, instruction_set,
+                                              compiler_kind_, instruction_set,
                                               instruction_set_features_.get(),
                                               true,
                                               GetImageClasses(),
@@ -211,6 +209,14 @@
                                               CompilerCallbacks::CallbackMode::kCompileApp));
 }
 
+Compiler::Kind CommonCompilerTest::GetCompilerKind() const {
+  return compiler_kind_;
+}
+
+void CommonCompilerTest::SetCompilerKind(Compiler::Kind compiler_kind) {
+  compiler_kind_ = compiler_kind;
+}
+
 void CommonCompilerTest::TearDown() {
   timer_.reset();
   compiler_driver_.reset();
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 769319b..d215662 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "common_runtime_test.h"
+#include "compiler.h"
 #include "oat_file.h"
 
 namespace art {
@@ -55,7 +56,10 @@
  protected:
   virtual void SetUp();
 
-  virtual void SetUpRuntimeOptions(RuntimeOptions *options);
+  virtual void SetUpRuntimeOptions(RuntimeOptions* options);
+
+  Compiler::Kind GetCompilerKind() const;
+  void SetCompilerKind(Compiler::Kind compiler_kind);
 
   // Get the set of image classes given to the compiler-driver in SetUp. Note: the compiler
   // driver assumes ownership of the set, so the test should properly release the set.
@@ -88,6 +92,7 @@
 
   void UnreserveImageSpace();
 
+  Compiler::Kind compiler_kind_ = kUseOptimizingCompiler ? Compiler::kOptimizing : Compiler::kQuick;
   std::unique_ptr<CompilerOptions> compiler_options_;
   std::unique_ptr<VerificationResults> verification_results_;
   std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
@@ -103,6 +108,20 @@
   std::list<std::vector<uint8_t>> header_code_and_maps_chunks_;
 };
 
+// TODO: When heap reference poisoning works with all compilers in use, get rid of this.
+#define TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK() \
+  if (kPoisonHeapReferences && GetCompilerKind() == Compiler::kQuick) { \
+    printf("WARNING: TEST DISABLED FOR HEAP REFERENCE POISONING WITH QUICK\n"); \
+    return; \
+  }
+
+// TODO: When non-PIC works with all compilers in use, get rid of this.
+#define TEST_DISABLED_FOR_NON_PIC_COMPILING_WITH_OPTIMIZING() \
+  if (GetCompilerKind() == Compiler::kOptimizing) { \
+    printf("WARNING: TEST DISABLED FOR NON-PIC COMPILING WITH OPTIMIZING\n"); \
+    return; \
+  }
+
 }  // namespace art
 
 #endif  // ART_COMPILER_COMMON_COMPILER_TEST_H_
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 920be0b4..3834242 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -173,7 +173,7 @@
   decoded_instruction->vB = inst->HasVRegB() ? inst->VRegB() : 0;
   decoded_instruction->vB_wide = inst->HasWideVRegB() ? inst->WideVRegB() : 0;
   decoded_instruction->vC = inst->HasVRegC() ?  inst->VRegC() : 0;
-  if (inst->HasVarArgs()) {
+  if (inst->HasVarArgs35c()) {
     inst->GetVarArgs(decoded_instruction->arg);
   }
   return inst->SizeInCodeUnits();
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index 94fc474..1a5c108 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -191,30 +191,8 @@
       GenConversionCall(kQuickF2l, rl_dest, rl_src, kCoreReg);
       return;
     case Instruction::LONG_TO_FLOAT: {
-      rl_src = LoadValueWide(rl_src, kFPReg);
-      RegisterInfo* info = GetRegInfo(rl_src.reg);
-      RegStorage src_low = info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg();
-      DCHECK(src_low.Valid());
-      RegStorage src_high = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg();
-      DCHECK(src_high.Valid());
-      rl_result = EvalLoc(rl_dest, kFPReg, true);
-      // Allocate temp registers.
-      RegStorage high_val = AllocTempDouble();
-      RegStorage low_val = AllocTempDouble();
-      RegStorage const_val = AllocTempDouble();
-      // Long to double.
-      NewLIR2(kThumb2VcvtF64S32, high_val.GetReg(), src_high.GetReg());
-      NewLIR2(kThumb2VcvtF64U32, low_val.GetReg(), src_low.GetReg());
-      LoadConstantWide(const_val, INT64_C(0x41f0000000000000));
-      NewLIR3(kThumb2VmlaF64, low_val.GetReg(), high_val.GetReg(), const_val.GetReg());
-      // Double to float.
-      NewLIR2(kThumb2VcvtDF, rl_result.reg.GetReg(), low_val.GetReg());
-      // Free temp registers.
-      FreeTemp(high_val);
-      FreeTemp(low_val);
-      FreeTemp(const_val);
-      // Store result.
-      StoreValue(rl_dest, rl_result);
+      CheckEntrypointTypes<kQuickL2f, float, int64_t>();  // float -> kFPReg
+      GenConversionCall(kQuickL2f, rl_dest, rl_src, kFPReg);
       return;
     }
     case Instruction::DOUBLE_TO_LONG:
diff --git a/compiler/dex/quick/arm64/arm64_lir.h b/compiler/dex/quick/arm64/arm64_lir.h
index c530a8b..2253d10 100644
--- a/compiler/dex/quick/arm64/arm64_lir.h
+++ b/compiler/dex/quick/arm64/arm64_lir.h
@@ -35,14 +35,15 @@
  * r16-r17: Also known as ip0-ip1, respectively. Used as scratch registers by
  *          the linker, by the trampolines and other stubs (the backend uses
  *          these as temporary registers).
- * r18    : (rxSELF) is reserved (pointer to thread-local storage).
- * r19-r29: Callee save registers (promotion targets).
+ * r18    : Caller save register (used as temporary register).
+ * r19    : (rxSELF) is reserved (pointer to thread-local storage).
+ * r20-r29: Callee save registers (promotion targets).
  * r30    : (lr) is reserved (the link register).
  * rsp    : (sp) is reserved (the stack pointer).
  * rzr    : (zr) is reserved (the zero register).
  *
- * 18 core temps that codegen can use (r0-r17).
- * 10 core registers that can be used for promotion.
+ * 19 core temps that codegen can use (r0-r18).
+ * 9 core registers that can be used for promotion.
  *
  * Floating-point registers
  * v0-v31
@@ -145,7 +146,7 @@
   // Aliases which are not defined in "ARM Architecture Reference, register names".
   rxIP0 = rx16,
   rxIP1 = rx17,
-  rxSELF = rx18,
+  rxSELF = rx19,
   rxLR = rx30,
   /*
    * FIXME: It's a bit awkward to define both 32 and 64-bit views of these - we'll only ever use
@@ -154,7 +155,7 @@
    */
   rwIP0 = rw16,
   rwIP1 = rw17,
-  rwSELF = rw18,
+  rwSELF = rw19,
   rwLR = rw30,
 };
 
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index d5de18d..6efa11e 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -51,19 +51,17 @@
      rs_d8, rs_d9, rs_d10, rs_d11, rs_d12, rs_d13, rs_d14, rs_d15,
      rs_d16, rs_d17, rs_d18, rs_d19, rs_d20, rs_d21, rs_d22, rs_d23,
      rs_d24, rs_d25, rs_d26, rs_d27, rs_d28, rs_d29, rs_d30, rs_d31};
-// Note: we are not able to call to C function since rs_xSELF is a special register need to be
-// preserved but would be scratched by native functions follow aapcs64.
 static constexpr RegStorage reserved_regs_arr[] = {rs_wSELF, rs_wsp, rs_wLR, rs_wzr};
 static constexpr RegStorage reserved64_regs_arr[] = {rs_xSELF, rs_sp, rs_xLR, rs_xzr};
 
 static constexpr RegStorage core_temps_arr[] =
     {rs_w0, rs_w1, rs_w2, rs_w3, rs_w4, rs_w5, rs_w6, rs_w7,
      rs_w8, rs_w9, rs_w10, rs_w11, rs_w12, rs_w13, rs_w14, rs_w15, rs_w16,
-     rs_w17};
+     rs_w17, rs_w18};
 static constexpr RegStorage core64_temps_arr[] =
     {rs_x0, rs_x1, rs_x2, rs_x3, rs_x4, rs_x5, rs_x6, rs_x7,
      rs_x8, rs_x9, rs_x10, rs_x11, rs_x12, rs_x13, rs_x14, rs_x15, rs_x16,
-     rs_x17};
+     rs_x17, rs_x18};
 static constexpr RegStorage sp_temps_arr[] =
     {rs_f0, rs_f1, rs_f2, rs_f3, rs_f4, rs_f5, rs_f6, rs_f7,
      rs_f16, rs_f17, rs_f18, rs_f19, rs_f20, rs_f21, rs_f22, rs_f23,
@@ -691,6 +689,7 @@
   Clobber(rs_x15);
   Clobber(rs_x16);
   Clobber(rs_x17);
+  Clobber(rs_x18);
   Clobber(rs_x30);
 
   Clobber(rs_f0);
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index c803e65..8629f39 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1370,7 +1370,9 @@
   DCHECK(first_bb->data_flow_info->vreg_to_ssa_map_exit != nullptr);
   const int32_t* first_vreg_to_ssa_map = first_bb->data_flow_info->vreg_to_ssa_map_exit;
   references->ClearAllBits();
-  for (uint32_t vreg = 0, num_vregs = mir_graph_->GetNumOfCodeVRs(); vreg != num_vregs; ++vreg) {
+  for (uint32_t vreg = 0,
+       num_vregs = mir_graph_->GetNumOfCodeVRs() + mir_graph_->GetNumUsedCompilerTemps();
+       vreg != num_vregs; ++vreg) {
     int32_t sreg = first_vreg_to_ssa_map[vreg];
     if (sreg != INVALID_SREG && mir_graph_->reg_location_[sreg].ref &&
         !mir_graph_->IsConstantNullRef(mir_graph_->reg_location_[sreg])) {
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index aa95e77..3f89001 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -107,7 +107,9 @@
 }
 
 RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind) {
-  DCHECK(!rl_src.ref || op_kind == kRefReg);
+  // If op_kind isn't a reference, rl_src should not be marked as a reference either
+  // unless we've seen type conflicts (i.e. register promotion is disabled).
+  DCHECK(op_kind == kRefReg || (!rl_src.ref || (cu_->disable_opt & (1u << kPromoteRegs)) != 0u));
   rl_src = UpdateLoc(rl_src);
   if (rl_src.location == kLocPhysReg) {
     if (!RegClassMatches(op_kind, rl_src.reg)) {
diff --git a/compiler/dex/quick/quick_cfi_test_expected.inc b/compiler/dex/quick/quick_cfi_test_expected.inc
index 52d66a4..3032697 100644
--- a/compiler/dex/quick/quick_cfi_test_expected.inc
+++ b/compiler/dex/quick/quick_cfi_test_expected.inc
@@ -33,15 +33,15 @@
 // 0x00000014: .cfi_def_cfa_offset: 64
 
 static constexpr uint8_t expected_asm_kArm64[] = {
-    0xFF, 0x03, 0x01, 0xD1, 0xE8, 0xA7, 0x01, 0x6D, 0xF3, 0xD3, 0x02, 0xA9,
+    0xFF, 0x03, 0x01, 0xD1, 0xE8, 0xA7, 0x01, 0x6D, 0xF4, 0xD7, 0x02, 0xA9,
     0xFE, 0x1F, 0x00, 0xF9, 0xE0, 0x03, 0x00, 0xF9, 0xE8, 0xA7, 0x41, 0x6D,
-    0xF3, 0xD3, 0x42, 0xA9, 0xFE, 0x1F, 0x40, 0xF9, 0xFF, 0x03, 0x01, 0x91,
+    0xF4, 0xD7, 0x42, 0xA9, 0xFE, 0x1F, 0x40, 0xF9, 0xFF, 0x03, 0x01, 0x91,
     0xC0, 0x03, 0x5F, 0xD6,
 };
 static constexpr uint8_t expected_cfi_kArm64[] = {
-    0x44, 0x0E, 0x40, 0x44, 0x05, 0x48, 0x0A, 0x05, 0x49, 0x08, 0x44, 0x93,
-    0x06, 0x94, 0x04, 0x44, 0x9E, 0x02, 0x44, 0x0A, 0x44, 0x06, 0x48, 0x06,
-    0x49, 0x44, 0xD3, 0xD4, 0x44, 0xDE, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E,
+    0x44, 0x0E, 0x40, 0x44, 0x05, 0x48, 0x0A, 0x05, 0x49, 0x08, 0x44, 0x94,
+    0x06, 0x95, 0x04, 0x44, 0x9E, 0x02, 0x44, 0x0A, 0x44, 0x06, 0x48, 0x06,
+    0x49, 0x44, 0xD4, 0xD5, 0x44, 0xDE, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E,
     0x40,
 };
 // 0x00000000: sub sp, sp, #0x40 (64)
@@ -49,9 +49,9 @@
 // 0x00000004: stp d8, d9, [sp, #24]
 // 0x00000008: .cfi_offset_extended: r72 at cfa-40
 // 0x00000008: .cfi_offset_extended: r73 at cfa-32
-// 0x00000008: stp x19, x20, [sp, #40]
-// 0x0000000c: .cfi_offset: r19 at cfa-24
-// 0x0000000c: .cfi_offset: r20 at cfa-16
+// 0x00000008: stp x20, x21, [sp, #40]
+// 0x0000000c: .cfi_offset: r20 at cfa-24
+// 0x0000000c: .cfi_offset: r21 at cfa-16
 // 0x0000000c: str lr, [sp, #56]
 // 0x00000010: .cfi_offset: r30 at cfa-8
 // 0x00000010: str x0, [sp]
@@ -59,9 +59,9 @@
 // 0x00000014: ldp d8, d9, [sp, #24]
 // 0x00000018: .cfi_restore_extended: r72
 // 0x00000018: .cfi_restore_extended: r73
-// 0x00000018: ldp x19, x20, [sp, #40]
-// 0x0000001c: .cfi_restore: r19
+// 0x00000018: ldp x20, x21, [sp, #40]
 // 0x0000001c: .cfi_restore: r20
+// 0x0000001c: .cfi_restore: r21
 // 0x0000001c: ldr lr, [sp, #56]
 // 0x00000020: .cfi_restore: r30
 // 0x00000020: add sp, sp, #0x40 (64)
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index ff4659a..39496a4 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -378,13 +378,13 @@
     Instruction::IGET_BYTE_QUICK,
     Instruction::IGET_CHAR_QUICK,
     Instruction::IGET_SHORT_QUICK,
-    Instruction::UNUSED_F3,
+    Instruction::INVOKE_LAMBDA,
     Instruction::UNUSED_F4,
     Instruction::UNUSED_F5,
-    Instruction::UNUSED_F6,
+    Instruction::CREATE_LAMBDA,
     Instruction::UNUSED_F7,
-    Instruction::UNUSED_F8,
-    Instruction::UNUSED_F9,
+    Instruction::BOX_LAMBDA,
+    Instruction::UNBOX_LAMBDA,
     Instruction::UNUSED_FA,
     Instruction::UNUSED_FB,
     Instruction::UNUSED_FC,
@@ -422,7 +422,15 @@
     Instruction::INVOKE_VIRTUAL_RANGE_QUICK,
 };
 
-// Unsupported opcodes. null can be used when everything is supported. Size of the lists is
+// TODO: Add support for lambda opcodes to the quick compiler.
+static const int kUnsupportedLambdaOpcodes[] = {
+    Instruction::INVOKE_LAMBDA,
+    Instruction::CREATE_LAMBDA,
+    Instruction::BOX_LAMBDA,
+    Instruction::UNBOX_LAMBDA,
+};
+
+// Unsupported opcodes. Null can be used when everything is supported. Size of the lists is
 // recorded below.
 static const int* kUnsupportedOpcodes[] = {
     // 0 = kNone.
@@ -430,17 +438,17 @@
     // 1 = kArm, unused (will use kThumb2).
     kAllOpcodes,
     // 2 = kArm64.
-    nullptr,
+    kUnsupportedLambdaOpcodes,
     // 3 = kThumb2.
-    nullptr,
+    kUnsupportedLambdaOpcodes,
     // 4 = kX86.
-    nullptr,
+    kUnsupportedLambdaOpcodes,
     // 5 = kX86_64.
-    nullptr,
+    kUnsupportedLambdaOpcodes,
     // 6 = kMips.
-    nullptr,
+    kUnsupportedLambdaOpcodes,
     // 7 = kMips64.
-    nullptr
+    kUnsupportedLambdaOpcodes,
 };
 static_assert(sizeof(kUnsupportedOpcodes) == 8 * sizeof(int*), "kUnsupportedOpcodes unexpected");
 
@@ -451,21 +459,26 @@
     // 1 = kArm, unused (will use kThumb2).
     arraysize(kAllOpcodes),
     // 2 = kArm64.
-    0,
+    arraysize(kUnsupportedLambdaOpcodes),
     // 3 = kThumb2.
-    0,
+    arraysize(kUnsupportedLambdaOpcodes),
     // 4 = kX86.
-    0,
+    arraysize(kUnsupportedLambdaOpcodes),
     // 5 = kX86_64.
-    0,
+    arraysize(kUnsupportedLambdaOpcodes),
     // 6 = kMips.
-    0,
+    arraysize(kUnsupportedLambdaOpcodes),
     // 7 = kMips64.
-    0
+    arraysize(kUnsupportedLambdaOpcodes),
 };
 static_assert(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t),
               "kUnsupportedOpcodesSize unexpected");
 
+static bool IsUnsupportedExperimentalLambdasOnly(size_t i) {
+  DCHECK_LE(i, arraysize(kUnsupportedOpcodes));
+  return kUnsupportedOpcodes[i] == kUnsupportedLambdaOpcodes;
+}
+
 // The maximum amount of Dalvik register in a method for which we will start compiling. Tries to
 // avoid an abort when we need to manage more SSA registers than we can.
 static constexpr size_t kMaxAllowedDalvikRegisters = INT16_MAX / 2;
@@ -488,6 +501,30 @@
   return true;
 }
 
+// If the ISA has unsupported opcodes, should we skip scanning over them?
+//
+// Most of the time we're compiling non-experimental files, so scanning just slows
+// performance down by as much as 6% with 4 threads.
+// In the rare cases we compile experimental opcodes, the runtime has an option to enable it,
+// which will force scanning for any unsupported opcodes.
+static bool SkipScanningUnsupportedOpcodes(InstructionSet instruction_set) {
+  if (UNLIKELY(kUnsupportedOpcodesSize[instruction_set] == 0U)) {
+    // All opcodes are supported no matter what. Usually not the case
+    // since experimental opcodes are not implemented in the quick compiler.
+    return true;
+  } else if (LIKELY(!Runtime::Current()->AreExperimentalLambdasEnabled())) {
+    // Experimental opcodes are disabled.
+    //
+    // If all unsupported opcodes are experimental we don't need to do scanning.
+    return IsUnsupportedExperimentalLambdasOnly(instruction_set);
+  } else {
+    // Experimental opcodes are enabled.
+    //
+    // Do the opcode scanning if the ISA has any unsupported opcodes.
+    return false;
+  }
+}
+
 // Skip the method that we do not support currently.
 bool QuickCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file,
                                      CompilationUnit* cu) const {
@@ -499,7 +536,7 @@
 
   // Check whether we do have limitations at all.
   if (kSupportedTypes[cu->instruction_set] == nullptr &&
-      kUnsupportedOpcodesSize[cu->instruction_set] == 0U) {
+      SkipScanningUnsupportedOpcodes(cu->instruction_set)) {
     return true;
   }
 
@@ -616,6 +653,12 @@
                                        uint32_t method_idx,
                                        jobject class_loader,
                                        const DexFile& dex_file) const {
+  if (kPoisonHeapReferences) {
+    VLOG(compiler) << "Skipping method : " << PrettyMethod(method_idx, dex_file)
+                   << "  Reason = Quick does not support heap poisoning.";
+    return nullptr;
+  }
+
   // TODO: check method fingerprint here to determine appropriate backend type.  Until then, use
   // build default.
   CompilerDriver* driver = GetCompilerDriver();
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 2bc8042..273b1628 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -100,7 +100,7 @@
     return false;
   }
   // There are 2 bytes to encode the number of entries.
-  if (num_entries >= 65536) {
+  if (num_entries > std::numeric_limits<uint16_t>::max()) {
     LOG(WARNING) << "Cannot encode GC map for method with " << num_entries << " entries: "
                  << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
                                  *method_verifier->GetMethodReference().dex_file);
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index bad4495..bf11839 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -124,7 +124,7 @@
   DequickenMap dequicken_map_;
   SafeCastSet safe_cast_set_;
 
-  bool has_verification_failures_;
+  bool has_verification_failures_ = false;
   bool has_runtime_throw_ = false;
 
   // Copy of mapping generated by verifier of dex PCs of string init invocations
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0613e6e..7890108 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1261,7 +1261,7 @@
   mirror::Class* referrer_class;
   mirror::DexCache* dex_cache;
   {
-    StackHandleScope<3> hs(soa.Self());
+    StackHandleScope<2> hs(soa.Self());
     Handle<mirror::DexCache> dex_cache_handle(
         hs.NewHandle(mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile())));
     Handle<mirror::ClassLoader> class_loader_handle(
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index f737007..2d7ceae 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -668,7 +668,7 @@
   bool dedupe_enabled_;
   bool dump_stats_;
   const bool dump_passes_;
-  const std::string& dump_cfg_file_name_;
+  const std::string dump_cfg_file_name_;
 
   CumulativeLogger* const timings_logger_;
 
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index ba03f5a..b358f4f 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -146,7 +146,7 @@
 }
 
 TEST_F(CompilerDriverTest, AbstractMethodErrorStub) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK();
   jobject class_loader;
   {
     ScopedObjectAccess soa(Thread::Current());
@@ -192,6 +192,7 @@
 };
 
 TEST_F(CompilerDriverMethodsTest, Selection) {
+  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK();
   Thread* self = Thread::Current();
   jobject class_loader;
   {
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index ddee3ba..dce1e86 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -44,7 +44,8 @@
 // it is used by C++ exception handling (which we do not use so we
 // can choose either).  C++ compilers generally tend to use .eh_frame
 // because if they need it sometimes, they might as well always use it.
-constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_EH_FRAME_FORMAT;
+// Let's use .debug_frame because it is easier to strip or compress.
+constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT;
 
 // The ARM specification defines three special mapping symbols
 // $a, $t and $d which mark ARM, Thumb and data ranges respectively.
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 772cc80..7e31a7a 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -45,6 +45,7 @@
 };
 
 TEST_F(ImageTest, WriteRead) {
+  TEST_DISABLED_FOR_NON_PIC_COMPILING_WITH_OPTIMIZING();
   // Create a generic location tmp file, to be the base of the .art and .oat temporary files.
   ScratchFile location;
   ScratchFile image_location(location, ".art");
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index e8461b0..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_);
@@ -1113,9 +1115,9 @@
   heap->VisitObjects(CopyAndFixupObjectsCallback, this);
   // Fix up the object previously had hash codes.
   for (const auto& hash_pair : saved_hashcode_map_) {
-    Object* const obj = hash_pair.first;
-    DCHECK_EQ(obj->GetLockWord(false).ReadBarrierState(), 0U);
-    obj->SetLockWord(LockWord::FromHashCode(hash_pair.second, 0U), false);
+    Object* obj = hash_pair.first;
+    DCHECK_EQ(obj->GetLockWord<kVerifyNone>(false).ReadBarrierState(), 0U);
+    obj->SetLockWord<kVerifyNone>(LockWord::FromHashCode(hash_pair.second, 0U), false);
   }
   saved_hashcode_map_.clear();
 }
@@ -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/jni/jni_cfi_test.cc b/compiler/jni/jni_cfi_test.cc
index 3a0d520..016f28e 100644
--- a/compiler/jni/jni_cfi_test.cc
+++ b/compiler/jni/jni_cfi_test.cc
@@ -56,7 +56,7 @@
     jni_asm->IncreaseFrameSize(32);
     jni_asm->DecreaseFrameSize(32);
     jni_asm->RemoveFrame(frame_size, callee_save_regs);
-    jni_asm->EmitSlowPaths();
+    jni_asm->FinalizeCode();
     std::vector<uint8_t> actual_asm(jni_asm->CodeSize());
     MemoryRegion code(&actual_asm[0], actual_asm.size());
     jni_asm->FinalizeInstructions(code);
diff --git a/compiler/jni/jni_cfi_test_expected.inc b/compiler/jni/jni_cfi_test_expected.inc
index 09b6034..dd4496f 100644
--- a/compiler/jni/jni_cfi_test_expected.inc
+++ b/compiler/jni/jni_cfi_test_expected.inc
@@ -84,14 +84,13 @@
     0xFF, 0x03, 0x03, 0xD1, 0xF3, 0x53, 0x06, 0xA9, 0xF5, 0x5B, 0x07, 0xA9,
     0xF7, 0x63, 0x08, 0xA9, 0xF9, 0x6B, 0x09, 0xA9, 0xFB, 0x73, 0x0A, 0xA9,
     0xFD, 0x7B, 0x0B, 0xA9, 0xE8, 0x27, 0x02, 0x6D, 0xEA, 0x2F, 0x03, 0x6D,
-    0xEC, 0x37, 0x04, 0x6D, 0xEE, 0x3F, 0x05, 0x6D, 0xF5, 0x03, 0x12, 0xAA,
-    0xE0, 0x03, 0x00, 0xF9, 0xE1, 0xCB, 0x00, 0xB9, 0xE0, 0xCF, 0x00, 0xBD,
-    0xE2, 0xD3, 0x00, 0xB9, 0xE3, 0xD7, 0x00, 0xB9, 0xFF, 0x83, 0x00, 0xD1,
-    0xFF, 0x83, 0x00, 0x91, 0xF2, 0x03, 0x15, 0xAA, 0xF3, 0x53, 0x46, 0xA9,
-    0xF5, 0x5B, 0x47, 0xA9, 0xF7, 0x63, 0x48, 0xA9, 0xF9, 0x6B, 0x49, 0xA9,
-    0xFB, 0x73, 0x4A, 0xA9, 0xFD, 0x7B, 0x4B, 0xA9, 0xE8, 0x27, 0x42, 0x6D,
-    0xEA, 0x2F, 0x43, 0x6D, 0xEC, 0x37, 0x44, 0x6D, 0xEE, 0x3F, 0x45, 0x6D,
-    0xFF, 0x03, 0x03, 0x91, 0xC0, 0x03, 0x5F, 0xD6,
+    0xEC, 0x37, 0x04, 0x6D, 0xEE, 0x3F, 0x05, 0x6D, 0xE0, 0x03, 0x00, 0xF9,
+    0xE1, 0xCB, 0x00, 0xB9, 0xE0, 0xCF, 0x00, 0xBD, 0xE2, 0xD3, 0x00, 0xB9,
+    0xE3, 0xD7, 0x00, 0xB9, 0xFF, 0x83, 0x00, 0xD1, 0xFF, 0x83, 0x00, 0x91,
+    0xF3, 0x53, 0x46, 0xA9, 0xF5, 0x5B, 0x47, 0xA9, 0xF7, 0x63, 0x48, 0xA9,
+    0xF9, 0x6B, 0x49, 0xA9, 0xFB, 0x73, 0x4A, 0xA9, 0xFD, 0x7B, 0x4B, 0xA9,
+    0xE8, 0x27, 0x42, 0x6D, 0xEA, 0x2F, 0x43, 0x6D, 0xEC, 0x37, 0x44, 0x6D,
+    0xEE, 0x3F, 0x45, 0x6D, 0xFF, 0x03, 0x03, 0x91, 0xC0, 0x03, 0x5F, 0xD6,
 };
 static constexpr uint8_t expected_cfi_kArm64[] = {
     0x44, 0x0E, 0xC0, 0x01, 0x44, 0x93, 0x18, 0x94, 0x16, 0x44, 0x95, 0x14,
@@ -99,15 +98,15 @@
     0x44, 0x9B, 0x08, 0x9C, 0x06, 0x44, 0x9D, 0x04, 0x9E, 0x02, 0x44, 0x05,
     0x48, 0x28, 0x05, 0x49, 0x26, 0x44, 0x05, 0x4A, 0x24, 0x05, 0x4B, 0x22,
     0x44, 0x05, 0x4C, 0x20, 0x05, 0x4D, 0x1E, 0x44, 0x05, 0x4E, 0x1C, 0x05,
-    0x4F, 0x1A, 0x5C, 0x0E, 0xE0, 0x01, 0x44, 0x0E, 0xC0, 0x01, 0x44, 0x0A,
-    0x44, 0xD3, 0xD4, 0x44, 0xD5, 0xD6, 0x44, 0xD7, 0xD8, 0x44, 0xD9, 0xDA,
-    0x44, 0xDB, 0xDC, 0x44, 0xDD, 0xDE, 0x44, 0x06, 0x48, 0x06, 0x49, 0x44,
-    0x06, 0x4A, 0x06, 0x4B, 0x44, 0x06, 0x4C, 0x06, 0x4D, 0x44, 0x06, 0x4E,
-    0x06, 0x4F, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E, 0xC0, 0x01,
+    0x4F, 0x1A, 0x58, 0x0E, 0xE0, 0x01, 0x44, 0x0E, 0xC0, 0x01, 0x0A, 0x44,
+    0xD3, 0xD4, 0x44, 0xD5, 0xD6, 0x44, 0xD7, 0xD8, 0x44, 0xD9, 0xDA, 0x44,
+    0xDB, 0xDC, 0x44, 0xDD, 0xDE, 0x44, 0x06, 0x48, 0x06, 0x49, 0x44, 0x06,
+    0x4A, 0x06, 0x4B, 0x44, 0x06, 0x4C, 0x06, 0x4D, 0x44, 0x06, 0x4E, 0x06,
+    0x4F, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E, 0xC0, 0x01,
 };
 // 0x00000000: sub sp, sp, #0xc0 (192)
 // 0x00000004: .cfi_def_cfa_offset: 192
-// 0x00000004: stp x19, x20, [sp, #96]
+// 0x00000004: stp tr, x20, [sp, #96]
 // 0x00000008: .cfi_offset: r19 at cfa-96
 // 0x00000008: .cfi_offset: r20 at cfa-88
 // 0x00000008: stp x21, x22, [sp, #112]
@@ -137,53 +136,51 @@
 // 0x00000028: stp d14, d15, [sp, #80]
 // 0x0000002c: .cfi_offset_extended: r78 at cfa-112
 // 0x0000002c: .cfi_offset_extended: r79 at cfa-104
-// 0x0000002c: mov x21, tr
-// 0x00000030: str x0, [sp]
-// 0x00000034: str w1, [sp, #200]
-// 0x00000038: str s0, [sp, #204]
-// 0x0000003c: str w2, [sp, #208]
-// 0x00000040: str w3, [sp, #212]
-// 0x00000044: sub sp, sp, #0x20 (32)
-// 0x00000048: .cfi_def_cfa_offset: 224
-// 0x00000048: add sp, sp, #0x20 (32)
-// 0x0000004c: .cfi_def_cfa_offset: 192
-// 0x0000004c: mov tr, x21
-// 0x00000050: .cfi_remember_state
-// 0x00000050: ldp x19, x20, [sp, #96]
-// 0x00000054: .cfi_restore: r19
-// 0x00000054: .cfi_restore: r20
-// 0x00000054: ldp x21, x22, [sp, #112]
-// 0x00000058: .cfi_restore: r21
-// 0x00000058: .cfi_restore: r22
-// 0x00000058: ldp x23, x24, [sp, #128]
-// 0x0000005c: .cfi_restore: r23
-// 0x0000005c: .cfi_restore: r24
-// 0x0000005c: ldp x25, x26, [sp, #144]
-// 0x00000060: .cfi_restore: r25
-// 0x00000060: .cfi_restore: r26
-// 0x00000060: ldp x27, x28, [sp, #160]
-// 0x00000064: .cfi_restore: r27
-// 0x00000064: .cfi_restore: r28
-// 0x00000064: ldp x29, lr, [sp, #176]
-// 0x00000068: .cfi_restore: r29
-// 0x00000068: .cfi_restore: r30
-// 0x00000068: ldp d8, d9, [sp, #32]
-// 0x0000006c: .cfi_restore_extended: r72
-// 0x0000006c: .cfi_restore_extended: r73
-// 0x0000006c: ldp d10, d11, [sp, #48]
-// 0x00000070: .cfi_restore_extended: r74
-// 0x00000070: .cfi_restore_extended: r75
-// 0x00000070: ldp d12, d13, [sp, #64]
-// 0x00000074: .cfi_restore_extended: r76
-// 0x00000074: .cfi_restore_extended: r77
-// 0x00000074: ldp d14, d15, [sp, #80]
-// 0x00000078: .cfi_restore_extended: r78
-// 0x00000078: .cfi_restore_extended: r79
-// 0x00000078: add sp, sp, #0xc0 (192)
-// 0x0000007c: .cfi_def_cfa_offset: 0
-// 0x0000007c: ret
-// 0x00000080: .cfi_restore_state
-// 0x00000080: .cfi_def_cfa_offset: 192
+// 0x0000002c: str x0, [sp]
+// 0x00000030: str w1, [sp, #200]
+// 0x00000034: str s0, [sp, #204]
+// 0x00000038: str w2, [sp, #208]
+// 0x0000003c: str w3, [sp, #212]
+// 0x00000040: sub sp, sp, #0x20 (32)
+// 0x00000044: .cfi_def_cfa_offset: 224
+// 0x00000044: add sp, sp, #0x20 (32)
+// 0x00000048: .cfi_def_cfa_offset: 192
+// 0x00000048: .cfi_remember_state
+// 0x00000048: ldp tr, x20, [sp, #96]
+// 0x0000004c: .cfi_restore: r19
+// 0x0000004c: .cfi_restore: r20
+// 0x0000004c: ldp x21, x22, [sp, #112]
+// 0x00000050: .cfi_restore: r21
+// 0x00000050: .cfi_restore: r22
+// 0x00000050: ldp x23, x24, [sp, #128]
+// 0x00000054: .cfi_restore: r23
+// 0x00000054: .cfi_restore: r24
+// 0x00000054: ldp x25, x26, [sp, #144]
+// 0x00000058: .cfi_restore: r25
+// 0x00000058: .cfi_restore: r26
+// 0x00000058: ldp x27, x28, [sp, #160]
+// 0x0000005c: .cfi_restore: r27
+// 0x0000005c: .cfi_restore: r28
+// 0x0000005c: ldp x29, lr, [sp, #176]
+// 0x00000060: .cfi_restore: r29
+// 0x00000060: .cfi_restore: r30
+// 0x00000060: ldp d8, d9, [sp, #32]
+// 0x00000064: .cfi_restore_extended: r72
+// 0x00000064: .cfi_restore_extended: r73
+// 0x00000064: ldp d10, d11, [sp, #48]
+// 0x00000068: .cfi_restore_extended: r74
+// 0x00000068: .cfi_restore_extended: r75
+// 0x00000068: ldp d12, d13, [sp, #64]
+// 0x0000006c: .cfi_restore_extended: r76
+// 0x0000006c: .cfi_restore_extended: r77
+// 0x0000006c: ldp d14, d15, [sp, #80]
+// 0x00000070: .cfi_restore_extended: r78
+// 0x00000070: .cfi_restore_extended: r79
+// 0x00000070: add sp, sp, #0xc0 (192)
+// 0x00000074: .cfi_def_cfa_offset: 0
+// 0x00000074: ret
+// 0x00000078: .cfi_restore_state
+// 0x00000078: .cfi_def_cfa_offset: 192
 
 static constexpr uint8_t expected_asm_kX86[] = {
     0x57, 0x56, 0x55, 0x83, 0xC4, 0xE4, 0x50, 0x89, 0x4C, 0x24, 0x34, 0xF3,
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index b094747..9aef10e 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -184,7 +184,7 @@
   // Jni function is the native function which the java code wants to call.
   // Jni method is the method that compiled by jni compiler.
   // Call chain: managed code(java) --> jni method --> jni function.
-  // Thread register(X18, scratched by aapcs64) is not saved on stack, it is saved in ETR(X21).
+  // Thread register(X19) is saved on stack.
   return 1 << X19 | 1 << X20 | 1 << X21 | 1 << X22 | 1 << X23 | 1 << X24 |
          1 << X25 | 1 << X26 | 1 << X27 | 1 << X28 | 1 << X29 | 1 << LR;
 }
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 4d7d86c..953dfcb 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -138,7 +138,7 @@
     FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset();
     // Check handle scope offset is within frame
     CHECK_LT(handle_scope_offset.Uint32Value(), frame_size);
-    // Note this LoadRef() doesn't need heap poisoning since its from the ArtMethod.
+    // Note this LoadRef() doesn't need heap unpoisoning since it's from the ArtMethod.
     // Note this LoadRef() does not include read barrier. It will be handled below.
     __ LoadRef(main_jni_conv->InterproceduralScratchRegister(),
                mr_conv->MethodRegister(), ArtMethod::DeclaringClassOffset(), false);
@@ -474,7 +474,7 @@
   DCHECK_EQ(jni_asm->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size));
 
   // 17. Finalize code generation
-  __ EmitSlowPaths();
+  __ FinalizeCode();
   size_t cs = __ CodeSize();
   std::vector<uint8_t> managed_code(cs);
   MemoryRegion code(&managed_code[0], managed_code.size());
diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc
index d010430..a3e889f 100644
--- a/compiler/linker/arm/relative_patcher_thumb2.cc
+++ b/compiler/linker/arm/relative_patcher_thumb2.cc
@@ -82,6 +82,7 @@
       arm::kLoadWord, arm::PC, arm::R0,
       ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value());
   assembler.bkpt(0);
+  assembler.FinalizeCode();
   std::vector<uint8_t> thunk_code(assembler.CodeSize());
   MemoryRegion code(thunk_code.data(), thunk_code.size());
   assembler.FinalizeInstructions(code);
diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc
index ee48789..29355d6 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.cc
+++ b/compiler/linker/arm64/relative_patcher_arm64.cc
@@ -233,7 +233,7 @@
       kArm64PointerSize).Int32Value());
   assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0));
   // Ensure we emit the literal pool.
-  assembler.EmitSlowPaths();
+  assembler.FinalizeCode();
   std::vector<uint8_t> thunk_code(assembler.CodeSize());
   MemoryRegion code(thunk_code.data(), thunk_code.size());
   assembler.FinalizeInstructions(code);
diff --git a/compiler/optimizing/boolean_simplifier.cc b/compiler/optimizing/boolean_simplifier.cc
index daf7d67..329112a 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);
diff --git a/compiler/optimizing/boolean_simplifier.h b/compiler/optimizing/boolean_simplifier.h
index 733ebaa..e12a12c 100644
--- a/compiler/optimizing/boolean_simplifier.h
+++ b/compiler/optimizing/boolean_simplifier.h
@@ -63,7 +63,7 @@
 class HBooleanSimplifier : public HOptimization {
  public:
   explicit HBooleanSimplifier(HGraph* graph)
-    : HOptimization(graph, true, kBooleanSimplifierPassName) {}
+    : HOptimization(graph, kBooleanSimplifierPassName) {}
 
   void Run() OVERRIDE;
 
diff --git a/compiler/optimizing/bounds_check_elimination.h b/compiler/optimizing/bounds_check_elimination.h
index 9e98ccf..24b8ea7 100644
--- a/compiler/optimizing/bounds_check_elimination.h
+++ b/compiler/optimizing/bounds_check_elimination.h
@@ -24,7 +24,7 @@
 class BoundsCheckElimination : public HOptimization {
  public:
   explicit BoundsCheckElimination(HGraph* graph)
-      : HOptimization(graph, true, kBoundsCheckEliminiationPassName) {}
+      : HOptimization(graph, kBoundsCheckEliminiationPassName) {}
 
   void Run() OVERRIDE;
 
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 7924e60..4701bdd 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -641,8 +641,13 @@
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
   graph->AddBlock(block);
   entry->AddSuccessor(block);
-  HInstruction* new_array = new (allocator)
-      HNewArray(constant_10, 0, Primitive::kPrimInt, kQuickAllocArray);
+  HInstruction* new_array = new (allocator) HNewArray(
+      constant_10,
+      graph->GetCurrentMethod(),
+      0,
+      Primitive::kPrimInt,
+      graph->GetDexFile(),
+      kQuickAllocArray);
   block->AddInstruction(new_array);
   block->AddInstruction(new (allocator) HGoto());
 
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index d175efe..fe52c44 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -259,6 +259,207 @@
   return false;
 }
 
+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) {
+  if (code_item.tries_size_ == 0) {
+    return;
+  }
+
+  // Create branch targets at the start/end of the TryItem range. These are
+  // places where the program might fall through into/out of the a block and
+  // where TryBoundary instructions will be inserted later. Other edges which
+  // enter/exit the try blocks are a result of branches/switches.
+  for (size_t idx = 0; idx < code_item.tries_size_; ++idx) {
+    const DexFile::TryItem* try_item = DexFile::GetTryItems(code_item, idx);
+    uint32_t dex_pc_start = try_item->start_addr_;
+    uint32_t dex_pc_end = dex_pc_start + try_item->insn_count_;
+    FindOrCreateBlockStartingAt(dex_pc_start);
+    if (dex_pc_end < code_item.insns_size_in_code_units_) {
+      // TODO: Do not create block if the last instruction cannot fall through.
+      FindOrCreateBlockStartingAt(dex_pc_end);
+    } else {
+      // The TryItem spans until the very end of the CodeItem (or beyond if
+      // invalid) and therefore cannot have any code afterwards.
+    }
+  }
+
+  // Create branch targets for exception handlers.
+  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item, 0);
+  uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+  for (uint32_t idx = 0; idx < handlers_size; ++idx) {
+    CatchHandlerIterator iterator(handlers_ptr);
+    for (; iterator.HasNext(); iterator.Next()) {
+      uint32_t address = iterator.GetHandlerAddress();
+      HBasicBlock* block = FindOrCreateBlockStartingAt(address);
+      block->SetIsCatchBlock();
+    }
+    handlers_ptr = iterator.EndDataPointer();
+  }
+}
+
+void HGraphBuilder::SplitTryBoundaryEdge(HBasicBlock* predecessor,
+                                         HBasicBlock* successor,
+                                         HTryBoundary::BoundaryKind kind,
+                                         const DexFile::CodeItem& code_item,
+                                         const DexFile::TryItem& try_item) {
+  // Split the edge with a single TryBoundary instruction.
+  HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind);
+  HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, successor);
+  try_entry_block->AddInstruction(try_boundary);
+
+  // Link the TryBoundary to the handlers of `try_item`.
+  for (CatchHandlerIterator it(code_item, try_item); it.HasNext(); it.Next()) {
+    try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
+  }
+}
+
+void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) {
+  if (code_item.tries_size_ == 0) {
+    return;
+  }
+
+  // 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);
+
+  // 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 (can_throw) {
+      if (block->IsCatchBlock()) {
+        // Catch blocks are always considered an entry point into the TryItem in
+        // 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());
+          block = block->SplitBefore(first_insn->GetNext()->GetNext());
+        } else {
+          // 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());
+    }
+  }
+
+  // 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);
+        }
+      } 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);
+    }
+  }
+}
+
 bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
   DCHECK(graph_->GetBlocks().IsEmpty());
 
@@ -292,24 +493,7 @@
     return false;
   }
 
-  // Also create blocks for catch handlers.
-  if (code_item.tries_size_ != 0) {
-    const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(code_item, 0);
-    uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
-    for (uint32_t idx = 0; idx < handlers_size; ++idx) {
-      CatchHandlerIterator iterator(handlers_ptr);
-      for (; iterator.HasNext(); iterator.Next()) {
-        uint32_t address = iterator.GetHandlerAddress();
-        HBasicBlock* block = FindBlockStartingAt(address);
-        if (block == nullptr) {
-          block = new (arena_) HBasicBlock(graph_, address);
-          branch_targets_.Put(address, block);
-        }
-        block->SetIsCatchBlock();
-      }
-      handlers_ptr = iterator.EndDataPointer();
-    }
-  }
+  CreateBlocksForTryCatch(code_item);
 
   InitializeParameters(code_item.ins_size_);
 
@@ -325,18 +509,24 @@
     code_ptr += instruction.SizeInCodeUnits();
   }
 
-  // Add the exit block at the end to give it the highest id.
-  graph_->AddBlock(exit_block_);
+  // Add Exit to the exit block.
   exit_block_->AddInstruction(new (arena_) HExit());
   // 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);
 
   return true;
 }
 
-void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
-  HBasicBlock* block = FindBlockStartingAt(index);
+void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) {
+  HBasicBlock* block = FindBlockStartingAt(dex_pc);
   if (block == nullptr) {
     return;
   }
@@ -371,22 +561,19 @@
       (*number_of_branches)++;
       int32_t target = instruction.GetTargetOffset() + dex_pc;
       // Create a block for the target instruction.
-      if (FindBlockStartingAt(target) == nullptr) {
-        block = new (arena_) HBasicBlock(graph_, target);
-        branch_targets_.Put(target, block);
-      }
+      FindOrCreateBlockStartingAt(target);
+
       dex_pc += instruction.SizeInCodeUnits();
       code_ptr += instruction.SizeInCodeUnits();
 
-      if (code_ptr >= code_end) {
-        if (instruction.CanFlowThrough()) {
+      if (instruction.CanFlowThrough()) {
+        if (code_ptr >= code_end) {
           // In the normal case we should never hit this but someone can artificially forge a dex
           // file to fall-through out the method code. In this case we bail out compilation.
           return false;
+        } else {
+          FindOrCreateBlockStartingAt(dex_pc);
         }
-      } else if (FindBlockStartingAt(dex_pc) == nullptr) {
-        block = new (arena_) HBasicBlock(graph_, dex_pc);
-        branch_targets_.Put(dex_pc, block);
       }
     } else if (instruction.IsSwitch()) {
       SwitchTable table(instruction, dex_pc, instruction.Opcode() == Instruction::SPARSE_SWITCH);
@@ -401,16 +588,12 @@
       for (size_t i = 0; i < num_entries; ++i) {
         // The target of the case.
         uint32_t target = dex_pc + table.GetEntryAt(i + offset);
-        if (FindBlockStartingAt(target) == nullptr) {
-          block = new (arena_) HBasicBlock(graph_, target);
-          branch_targets_.Put(target, block);
-        }
+        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.
@@ -421,9 +604,8 @@
         // file to fall-through out the method code. In this case we bail out compilation.
         // (A switch can fall-through so we don't need to check CanFlowThrough().)
         return false;
-      } else if (FindBlockStartingAt(dex_pc) == nullptr) {
-        block = new (arena_) HBasicBlock(graph_, dex_pc);
-        branch_targets_.Put(dex_pc, block);
+      } else {
+        FindOrCreateBlockStartingAt(dex_pc);
       }
     } else {
       code_ptr += instruction.SizeInCodeUnits();
@@ -433,9 +615,19 @@
   return true;
 }
 
-HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
-  DCHECK_GE(index, 0);
-  return branch_targets_.Get(index);
+HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t dex_pc) const {
+  DCHECK_GE(dex_pc, 0);
+  DCHECK_LT(static_cast<size_t>(dex_pc), branch_targets_.Size());
+  return branch_targets_.Get(dex_pc);
+}
+
+HBasicBlock* HGraphBuilder::FindOrCreateBlockStartingAt(int32_t dex_pc) {
+  HBasicBlock* block = FindBlockStartingAt(dex_pc);
+  if (block == nullptr) {
+    block = new (arena_) HBasicBlock(graph_, dex_pc);
+    branch_targets_.Put(dex_pc, block);
+  }
+  return block;
 }
 
 template<typename T>
@@ -483,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);
@@ -540,11 +732,6 @@
 }
 
 static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) {
-  // dex compilation unit is null only when unit testing.
-  if (cu == nullptr) {
-    return false;
-  }
-
   Thread* self = Thread::Current();
   return cu->IsConstructor()
       && driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex());
@@ -552,9 +739,12 @@
 
 void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
   if (type == Primitive::kPrimVoid) {
-    // Note that we might insert redundant barriers when inlining `super` calls.
-    // TODO: add a data flow analysis to get rid of duplicate barriers.
-    if (RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_)) {
+    if (graph_->ShouldGenerateConstructorBarrier()) {
+      // The compilation unit is null during testing.
+      if (dex_compilation_unit_ != nullptr) {
+        DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_))
+          << "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier.";
+      }
       current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore));
     }
     current_block_->AddInstruction(new (arena_) HReturnVoid());
@@ -661,8 +851,8 @@
     DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect)
            || compiler_driver_->GetCompilerOptions().GetCompilePic());
     bool is_recursive =
-        (target_method.dex_method_index == dex_compilation_unit_->GetDexMethodIndex());
-    DCHECK(!is_recursive || (target_method.dex_file == dex_compilation_unit_->GetDexFile()));
+        (target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex())
+        && (target_method.dex_file == outer_compilation_unit_->GetDexFile());
 
     if (optimized_invoke_type == kStatic && !is_string_init) {
       ScopedObjectAccess soa(Thread::Current());
@@ -723,8 +913,12 @@
           clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
         } else {
           clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
-          HLoadClass* load_class =
-              new (arena_) HLoadClass(storage_index, is_outer_class, dex_pc);
+          HLoadClass* load_class = new (arena_) HLoadClass(
+              graph_->GetCurrentMethod(),
+              storage_index,
+              *dex_compilation_unit_->GetDexFile(),
+              is_outer_class,
+              dex_pc);
           current_block_->AddInstruction(load_class);
           clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
           current_block_->AddInstruction(clinit_check);
@@ -732,10 +926,16 @@
       }
     }
 
-    invoke = new (arena_) HInvokeStaticOrDirect(
-        arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index,
-        is_recursive, string_init_offset, invoke_type, optimized_invoke_type,
-        clinit_check_requirement);
+    invoke = new (arena_) HInvokeStaticOrDirect(arena_,
+                                                number_of_arguments,
+                                                return_type,
+                                                dex_pc,
+                                                target_method.dex_method_index,
+                                                is_recursive,
+                                                string_init_offset,
+                                                invoke_type,
+                                                optimized_invoke_type,
+                                                clinit_check_requirement);
   }
 
   size_t start_index = 0;
@@ -789,6 +989,11 @@
     return false;
   }
 
+  if (invoke->IsInvokeStaticOrDirect()) {
+    invoke->SetArgumentAt(argument_index, graph_->GetCurrentMethod());
+    argument_index++;
+  }
+
   if (clinit_check_requirement == HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit) {
     // Add the class initialization check as last input of `invoke`.
     DCHECK(clinit_check != nullptr);
@@ -854,13 +1059,17 @@
         value,
         field_type,
         resolved_field->GetOffset(),
-        resolved_field->IsVolatile()));
+        resolved_field->IsVolatile(),
+        field_index,
+        *dex_file_));
   } else {
     current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
         current_block_->GetLastInstruction(),
         field_type,
         resolved_field->GetOffset(),
-        resolved_field->IsVolatile()));
+        resolved_field->IsVolatile(),
+        field_index,
+        *dex_file_));
 
     UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
   }
@@ -953,7 +1162,11 @@
       *outer_compilation_unit_->GetDexFile(), storage_index);
   bool is_initialized = resolved_field->GetDeclaringClass()->IsInitialized() && is_in_dex_cache;
 
-  HLoadClass* constant = new (arena_) HLoadClass(storage_index, is_outer_class, dex_pc);
+  HLoadClass* constant = new (arena_) HLoadClass(graph_->GetCurrentMethod(),
+                                                 storage_index,
+                                                 *dex_compilation_unit_->GetDexFile(),
+                                                 is_outer_class,
+                                                 dex_pc);
   current_block_->AddInstruction(constant);
 
   HInstruction* cls = constant;
@@ -969,13 +1182,20 @@
     temps.Add(cls);
     HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
     DCHECK_EQ(value->GetType(), field_type);
-    current_block_->AddInstruction(
-        new (arena_) HStaticFieldSet(cls, value, field_type, resolved_field->GetOffset(),
-            resolved_field->IsVolatile()));
+    current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls,
+                                                                value,
+                                                                field_type,
+                                                                resolved_field->GetOffset(),
+                                                                resolved_field->IsVolatile(),
+                                                                field_index,
+                                                                *dex_file_));
   } else {
-    current_block_->AddInstruction(
-        new (arena_) HStaticFieldGet(cls, field_type, resolved_field->GetOffset(),
-            resolved_field->IsVolatile()));
+    current_block_->AddInstruction(new (arena_) HStaticFieldGet(cls,
+                                                                field_type,
+                                                                resolved_field->GetOffset(),
+                                                                resolved_field->IsVolatile(),
+                                                                field_index,
+                                                                *dex_file_));
     UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
   }
   return true;
@@ -1064,7 +1284,12 @@
   QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
       ? kQuickAllocArrayWithAccessCheck
       : kQuickAllocArray;
-  HInstruction* object = new (arena_) HNewArray(length, dex_pc, type_index, entrypoint);
+  HInstruction* object = new (arena_) HNewArray(length,
+                                                graph_->GetCurrentMethod(),
+                                                dex_pc,
+                                                type_index,
+                                                *dex_compilation_unit_->GetDexFile(),
+                                                entrypoint);
   current_block_->AddInstruction(object);
 
   const char* descriptor = dex_file_->StringByTypeIdx(type_index);
@@ -1189,7 +1414,11 @@
   }
   HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
   HLoadClass* cls = new (arena_) HLoadClass(
-      type_index, IsOutermostCompilingClass(type_index), dex_pc);
+      graph_->GetCurrentMethod(),
+      type_index,
+      *dex_compilation_unit_->GetDexFile(),
+      IsOutermostCompilingClass(type_index),
+      dex_pc);
   current_block_->AddInstruction(cls);
   // The class needs a temporary before being used by the type check.
   Temporaries temps(graph_);
@@ -2019,7 +2248,12 @@
             ? kQuickAllocObjectWithAccessCheck
             : kQuickAllocObject;
 
-        current_block_->AddInstruction(new (arena_) HNewInstance(dex_pc, type_index, entrypoint));
+        current_block_->AddInstruction(new (arena_) HNewInstance(
+            graph_->GetCurrentMethod(),
+            dex_pc,
+            type_index,
+            *dex_compilation_unit_->GetDexFile(),
+            entrypoint));
         UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
       }
       break;
@@ -2031,8 +2265,12 @@
       QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
           ? kQuickAllocArrayWithAccessCheck
           : kQuickAllocArray;
-      current_block_->AddInstruction(
-          new (arena_) HNewArray(length, dex_pc, type_index, entrypoint));
+      current_block_->AddInstruction(new (arena_) HNewArray(length,
+                                                            graph_->GetCurrentMethod(),
+                                                            dex_pc,
+                                                            type_index,
+                                                            *dex_compilation_unit_->GetDexFile(),
+                                                            entrypoint));
       UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
       break;
     }
@@ -2062,38 +2300,56 @@
 
     case Instruction::MOVE_RESULT:
     case Instruction::MOVE_RESULT_WIDE:
-    case Instruction::MOVE_RESULT_OBJECT:
+    case Instruction::MOVE_RESULT_OBJECT: {
       if (latest_result_ == nullptr) {
         // Only dead code can lead to this situation, where the verifier
         // does not reject the method.
       } else {
-        UpdateLocal(instruction.VRegA(), latest_result_);
+        // An Invoke/FilledNewArray and its MoveResult could have landed in
+        // different blocks if there was a try/catch block boundary between
+        // them. For Invoke, we insert a StoreLocal after the instruction. For
+        // FilledNewArray, the local needs to be updated after the array was
+        // filled, otherwise we might overwrite an input vreg.
+        HStoreLocal* update_local =
+            new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_);
+        HBasicBlock* block = latest_result_->GetBlock();
+        if (block == current_block_) {
+          // MoveResult and the previous instruction are in the same block.
+          current_block_->AddInstruction(update_local);
+        } else {
+          // The two instructions are in different blocks. Insert the MoveResult
+          // before the final control-flow instruction of the previous block.
+          DCHECK(block->EndsWithControlFlowInstruction());
+          DCHECK(current_block_->GetInstructions().IsEmpty());
+          block->InsertInstructionBefore(update_local, block->GetLastInstruction());
+        }
         latest_result_ = nullptr;
       }
       break;
+    }
 
     case Instruction::CMP_LONG: {
-      Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimLong, kNoBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, kLtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, kLtBias, dex_pc);
       break;
     }
 
@@ -2182,13 +2438,15 @@
     }
 
     case Instruction::CONST_STRING: {
-      current_block_->AddInstruction(new (arena_) HLoadString(instruction.VRegB_21c(), dex_pc));
+      current_block_->AddInstruction(
+          new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_21c(), dex_pc));
       UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
       break;
     }
 
     case Instruction::CONST_STRING_JUMBO: {
-      current_block_->AddInstruction(new (arena_) HLoadString(instruction.VRegB_31c(), dex_pc));
+      current_block_->AddInstruction(
+          new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_31c(), dex_pc));
       UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction());
       break;
     }
@@ -2209,8 +2467,12 @@
         MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
         return false;
       }
-      current_block_->AddInstruction(
-          new (arena_) HLoadClass(type_index, IsOutermostCompilingClass(type_index), dex_pc));
+      current_block_->AddInstruction(new (arena_) HLoadClass(
+          graph_->GetCurrentMethod(),
+          type_index,
+          *dex_compilation_unit_->GetDexFile(),
+          IsOutermostCompilingClass(type_index),
+          dex_pc));
       UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
       break;
     }
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 052aaf8..7098eb8 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -94,8 +94,25 @@
   bool ComputeBranchTargets(const uint16_t* start,
                             const uint16_t* end,
                             size_t* number_of_branches);
-  void MaybeUpdateCurrentBlock(size_t index);
-  HBasicBlock* FindBlockStartingAt(int32_t index) const;
+  void MaybeUpdateCurrentBlock(size_t dex_pc);
+  HBasicBlock* FindBlockStartingAt(int32_t dex_pc) const;
+  HBasicBlock* FindOrCreateBlockStartingAt(int32_t dex_pc);
+
+  // Adds new blocks to `branch_targets_` starting at the limits of TryItems and
+  // their exception handlers.
+  void CreateBlocksForTryCatch(const DexFile::CodeItem& code_item);
+
+  // Splits edges which cross the boundaries of TryItems, inserts TryBoundary
+  // instructions and links them to the corresponding catch blocks.
+  void InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item);
+
+  // Splits a single edge, inserting a TryBoundary of given `kind` and linking
+  // it to exception handlers of `try_item`.
+  void SplitTryBoundaryEdge(HBasicBlock* predecessor,
+                            HBasicBlock* successor,
+                            HTryBoundary::BoundaryKind kind,
+                            const DexFile::CodeItem& code_item,
+                            const DexFile::TryItem& try_item);
 
   void InitializeLocals(uint16_t count);
   HLocal* GetLocalAt(int register_index) const;
@@ -119,7 +136,7 @@
 
   void Binop_23x_cmp(const Instruction& instruction,
                      Primitive::Type type,
-                     HCompare::Bias bias,
+                     ComparisonBias bias,
                      uint32_t dex_pc);
 
   template<typename T>
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index ff04724..4607ebe 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -25,6 +25,7 @@
 #include "dex/verified_method.h"
 #include "driver/dex_compilation_unit.h"
 #include "gc_map_builder.h"
+#include "graph_visualizer.h"
 #include "leb128.h"
 #include "mapping_table.h"
 #include "mirror/array-inl.h"
@@ -145,7 +146,7 @@
 HBasicBlock* CodeGenerator::GetNextBlockToEmit() const {
   for (size_t i = current_block_index_ + 1; i < block_order_->Size(); ++i) {
     HBasicBlock* block = block_order_->Get(i);
-    if (!block->IsSingleGoto()) {
+    if (!block->IsSingleJump()) {
       return block;
     }
   }
@@ -153,27 +154,71 @@
 }
 
 HBasicBlock* CodeGenerator::FirstNonEmptyBlock(HBasicBlock* block) const {
-  while (block->IsSingleGoto()) {
+  while (block->IsSingleJump()) {
     block = block->GetSuccessors().Get(0);
   }
   return block;
 }
 
+class DisassemblyScope {
+ public:
+  DisassemblyScope(HInstruction* instruction, const CodeGenerator& codegen)
+      : codegen_(codegen), instruction_(instruction), start_offset_(static_cast<size_t>(-1)) {
+    if (codegen_.GetDisassemblyInformation() != nullptr) {
+      start_offset_ = codegen_.GetAssembler().CodeSize();
+    }
+  }
+
+  ~DisassemblyScope() {
+    // We avoid building this data when we know it will not be used.
+    if (codegen_.GetDisassemblyInformation() != nullptr) {
+      codegen_.GetDisassemblyInformation()->AddInstructionInterval(
+          instruction_, start_offset_, codegen_.GetAssembler().CodeSize());
+    }
+  }
+
+ private:
+  const CodeGenerator& codegen_;
+  HInstruction* instruction_;
+  size_t start_offset_;
+};
+
+
+void CodeGenerator::GenerateSlowPaths() {
+  size_t code_start = 0;
+  for (size_t i = 0, e = slow_paths_.Size(); i < e; ++i) {
+    if (disasm_info_ != nullptr) {
+      code_start = GetAssembler()->CodeSize();
+    }
+    slow_paths_.Get(i)->EmitNativeCode(this);
+    if (disasm_info_ != nullptr) {
+      disasm_info_->AddSlowPathInterval(slow_paths_.Get(i), code_start, GetAssembler()->CodeSize());
+    }
+  }
+}
+
 void CodeGenerator::CompileInternal(CodeAllocator* allocator, bool is_baseline) {
   is_baseline_ = is_baseline;
   HGraphVisitor* instruction_visitor = GetInstructionVisitor();
   DCHECK_EQ(current_block_index_, 0u);
+
+  size_t frame_start = GetAssembler()->CodeSize();
   GenerateFrameEntry();
   DCHECK_EQ(GetAssembler()->cfi().GetCurrentCFAOffset(), static_cast<int>(frame_size_));
+  if (disasm_info_ != nullptr) {
+    disasm_info_->SetFrameEntryInterval(frame_start, GetAssembler()->CodeSize());
+  }
+
   for (size_t e = block_order_->Size(); current_block_index_ < e; ++current_block_index_) {
     HBasicBlock* block = block_order_->Get(current_block_index_);
     // Don't generate code for an empty block. Its predecessors will branch to its successor
     // directly. Also, the label of that block will not be emitted, so this helps catch
     // errors where we reference that label.
-    if (block->IsSingleGoto()) continue;
+    if (block->IsSingleJump()) continue;
     Bind(block);
     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
       HInstruction* current = it.Current();
+      DisassemblyScope disassembly_scope(current, *this);
       if (is_baseline) {
         InitLocationsBaseline(current);
       }
@@ -182,10 +227,7 @@
     }
   }
 
-  // Generate the slow paths.
-  for (size_t i = 0, e = slow_paths_.Size(); i < e; ++i) {
-    slow_paths_.Get(i)->EmitNativeCode(this);
-  }
+  GenerateSlowPaths();
 
   // Finalize instructions in assember;
   Finalize(allocator);
@@ -288,6 +330,33 @@
   }
 }
 
+void CodeGenerator::CreateCommonInvokeLocationSummary(
+    HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor) {
+  ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetArena();
+  LocationSummary* locations = new (allocator) LocationSummary(invoke, LocationSummary::kCall);
+
+  for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
+    HInstruction* input = invoke->InputAt(i);
+    locations->SetInAt(i, visitor->GetNextLocation(input->GetType()));
+  }
+
+  locations->SetOut(visitor->GetReturnLocation(invoke->GetType()));
+
+  if (invoke->IsInvokeStaticOrDirect()) {
+    HInvokeStaticOrDirect* call = invoke->AsInvokeStaticOrDirect();
+    if (call->IsStringInit()) {
+      locations->AddTemp(visitor->GetMethodLocation());
+    } else if (call->IsRecursive()) {
+      locations->SetInAt(call->GetCurrentMethodInputIndex(), visitor->GetMethodLocation());
+    } else {
+      locations->AddTemp(visitor->GetMethodLocation());
+      locations->SetInAt(call->GetCurrentMethodInputIndex(), Location::RequiresRegister());
+    }
+  } else {
+    locations->AddTemp(visitor->GetMethodLocation());
+  }
+}
+
 void CodeGenerator::BlockIfInRegister(Location location, bool is_out) const {
   // The DCHECKS below check that a register is not specified twice in
   // the summary. The out location can overlap with an input, so we need
@@ -486,19 +555,14 @@
       dex_compilation_unit.GetVerifiedMethod()->GetDexGcMap();
   verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]);
 
-  uint32_t max_native_offset = 0;
-  for (size_t i = 0; i < pc_infos_.Size(); i++) {
-    uint32_t native_offset = pc_infos_.Get(i).native_pc;
-    if (native_offset > max_native_offset) {
-      max_native_offset = native_offset;
-    }
-  }
+  uint32_t max_native_offset = stack_map_stream_.ComputeMaxNativePcOffset();
 
-  GcMapBuilder builder(data, pc_infos_.Size(), max_native_offset, dex_gc_map.RegWidth());
-  for (size_t i = 0; i < pc_infos_.Size(); i++) {
-    struct PcInfo pc_info = pc_infos_.Get(i);
-    uint32_t native_offset = pc_info.native_pc;
-    uint32_t dex_pc = pc_info.dex_pc;
+  size_t num_stack_maps = stack_map_stream_.GetNumberOfStackMaps();
+  GcMapBuilder builder(data, num_stack_maps, max_native_offset, dex_gc_map.RegWidth());
+  for (size_t i = 0; i != num_stack_maps; ++i) {
+    const StackMapStream::StackMapEntry& stack_map_entry = stack_map_stream_.GetStackMap(i);
+    uint32_t native_offset = stack_map_entry.native_pc_offset;
+    uint32_t dex_pc = stack_map_entry.dex_pc;
     const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
     CHECK(references != nullptr) << "Missing ref for dex pc 0x" << std::hex << dex_pc;
     builder.AddEntry(native_offset, references);
@@ -506,17 +570,17 @@
 }
 
 void CodeGenerator::BuildSourceMap(DefaultSrcMap* src_map) const {
-  for (size_t i = 0; i < pc_infos_.Size(); i++) {
-    struct PcInfo pc_info = pc_infos_.Get(i);
-    uint32_t pc2dex_offset = pc_info.native_pc;
-    int32_t pc2dex_dalvik_offset = pc_info.dex_pc;
+  for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
+    const StackMapStream::StackMapEntry& stack_map_entry = stack_map_stream_.GetStackMap(i);
+    uint32_t pc2dex_offset = stack_map_entry.native_pc_offset;
+    int32_t pc2dex_dalvik_offset = stack_map_entry.dex_pc;
     src_map->push_back(SrcMapElem({pc2dex_offset, pc2dex_dalvik_offset}));
   }
 }
 
 void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const {
   uint32_t pc2dex_data_size = 0u;
-  uint32_t pc2dex_entries = pc_infos_.Size();
+  uint32_t pc2dex_entries = stack_map_stream_.GetNumberOfStackMaps();
   uint32_t pc2dex_offset = 0u;
   int32_t pc2dex_dalvik_offset = 0;
   uint32_t dex2pc_data_size = 0u;
@@ -525,11 +589,11 @@
   int32_t dex2pc_dalvik_offset = 0;
 
   for (size_t i = 0; i < pc2dex_entries; i++) {
-    struct PcInfo pc_info = pc_infos_.Get(i);
-    pc2dex_data_size += UnsignedLeb128Size(pc_info.native_pc - pc2dex_offset);
-    pc2dex_data_size += SignedLeb128Size(pc_info.dex_pc - pc2dex_dalvik_offset);
-    pc2dex_offset = pc_info.native_pc;
-    pc2dex_dalvik_offset = pc_info.dex_pc;
+    const StackMapStream::StackMapEntry& stack_map_entry = stack_map_stream_.GetStackMap(i);
+    pc2dex_data_size += UnsignedLeb128Size(stack_map_entry.native_pc_offset - pc2dex_offset);
+    pc2dex_data_size += SignedLeb128Size(stack_map_entry.dex_pc - pc2dex_dalvik_offset);
+    pc2dex_offset = stack_map_entry.native_pc_offset;
+    pc2dex_dalvik_offset = stack_map_entry.dex_pc;
   }
 
   // Walk over the blocks and find which ones correspond to catch block entries.
@@ -564,12 +628,12 @@
   dex2pc_dalvik_offset = 0u;
 
   for (size_t i = 0; i < pc2dex_entries; i++) {
-    struct PcInfo pc_info = pc_infos_.Get(i);
-    DCHECK(pc2dex_offset <= pc_info.native_pc);
-    write_pos = EncodeUnsignedLeb128(write_pos, pc_info.native_pc - pc2dex_offset);
-    write_pos = EncodeSignedLeb128(write_pos, pc_info.dex_pc - pc2dex_dalvik_offset);
-    pc2dex_offset = pc_info.native_pc;
-    pc2dex_dalvik_offset = pc_info.dex_pc;
+    const StackMapStream::StackMapEntry& stack_map_entry = stack_map_stream_.GetStackMap(i);
+    DCHECK(pc2dex_offset <= stack_map_entry.native_pc_offset);
+    write_pos = EncodeUnsignedLeb128(write_pos, stack_map_entry.native_pc_offset - pc2dex_offset);
+    write_pos = EncodeSignedLeb128(write_pos, stack_map_entry.dex_pc - pc2dex_dalvik_offset);
+    pc2dex_offset = stack_map_entry.native_pc_offset;
+    pc2dex_dalvik_offset = stack_map_entry.dex_pc;
   }
 
   for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
@@ -595,9 +659,9 @@
     auto it = table.PcToDexBegin();
     auto it2 = table.DexToPcBegin();
     for (size_t i = 0; i < pc2dex_entries; i++) {
-      struct PcInfo pc_info = pc_infos_.Get(i);
-      CHECK_EQ(pc_info.native_pc, it.NativePcOffset());
-      CHECK_EQ(pc_info.dex_pc, it.DexPc());
+      const StackMapStream::StackMapEntry& stack_map_entry = stack_map_stream_.GetStackMap(i);
+      CHECK_EQ(stack_map_entry.native_pc_offset, it.NativePcOffset());
+      CHECK_EQ(stack_map_entry.dex_pc, it.DexPc());
       ++it;
     }
     for (size_t i = 0; i < graph_->GetBlocks().Size(); ++i) {
@@ -657,23 +721,31 @@
     }
   }
 
-  // Collect PC infos for the mapping table.
-  struct PcInfo pc_info;
-  pc_info.dex_pc = dex_pc;
-  pc_info.native_pc = GetAssembler()->CodeSize();
-  pc_infos_.Add(pc_info);
-
+  uint32_t outer_dex_pc = dex_pc;
+  uint32_t outer_environment_size = 0;
   uint32_t inlining_depth = 0;
+  if (instruction != nullptr) {
+    for (HEnvironment* environment = instruction->GetEnvironment();
+         environment != nullptr;
+         environment = environment->GetParent()) {
+      outer_dex_pc = environment->GetDexPc();
+      outer_environment_size = environment->Size();
+      if (environment != instruction->GetEnvironment()) {
+        inlining_depth++;
+      }
+    }
+  }
+
+  // Collect PC infos for the mapping table.
+  uint32_t native_pc = GetAssembler()->CodeSize();
 
   if (instruction == nullptr) {
     // For stack overflow checks.
-    stack_map_stream_.BeginStackMapEntry(dex_pc, pc_info.native_pc, 0, 0, 0, inlining_depth);
+    stack_map_stream_.BeginStackMapEntry(outer_dex_pc, native_pc, 0, 0, 0, 0);
     stack_map_stream_.EndStackMapEntry();
     return;
   }
   LocationSummary* locations = instruction->GetLocations();
-  HEnvironment* environment = instruction->GetEnvironment();
-  size_t environment_size = instruction->EnvironmentSize();
 
   uint32_t register_mask = locations->GetRegisterMask();
   if (locations->OnlyCallsOnSlowPath()) {
@@ -686,23 +758,34 @@
   }
   // The register mask must be a subset of callee-save registers.
   DCHECK_EQ(register_mask & core_callee_save_mask_, register_mask);
-  stack_map_stream_.BeginStackMapEntry(dex_pc,
-                                       pc_info.native_pc,
+  stack_map_stream_.BeginStackMapEntry(outer_dex_pc,
+                                       native_pc,
                                        register_mask,
                                        locations->GetStackMask(),
-                                       environment_size,
+                                       outer_environment_size,
                                        inlining_depth);
-  if (environment != nullptr) {
-    // TODO: Handle parent environment.
-    DCHECK(environment->GetParent() == nullptr);
-    DCHECK_EQ(environment->GetDexPc(), dex_pc);
+
+  EmitEnvironment(instruction->GetEnvironment(), slow_path);
+  stack_map_stream_.EndStackMapEntry();
+}
+
+void CodeGenerator::EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path) {
+  if (environment == nullptr) return;
+
+  if (environment->GetParent() != nullptr) {
+    // We emit the parent environment first.
+    EmitEnvironment(environment->GetParent(), slow_path);
+    stack_map_stream_.BeginInlineInfoEntry(environment->GetMethodIdx(),
+                                           environment->GetDexPc(),
+                                           environment->GetInvokeType(),
+                                           environment->Size());
   }
 
   // Walk over the environment, and record the location of dex registers.
-  for (size_t i = 0; i < environment_size; ++i) {
+  for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) {
     HInstruction* current = environment->GetInstructionAt(i);
     if (current == nullptr) {
-      stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kNone, 0);
+      stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
       continue;
     }
 
@@ -713,41 +796,44 @@
         if (current->IsLongConstant()) {
           int64_t value = current->AsLongConstant()->GetValue();
           stack_map_stream_.AddDexRegisterEntry(
-              i, DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+              DexRegisterLocation::Kind::kConstant, Low32Bits(value));
           stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value));
+              DexRegisterLocation::Kind::kConstant, High32Bits(value));
+          ++i;
           DCHECK_LT(i, environment_size);
         } else if (current->IsDoubleConstant()) {
           int64_t value = bit_cast<int64_t, double>(current->AsDoubleConstant()->GetValue());
           stack_map_stream_.AddDexRegisterEntry(
-              i, DexRegisterLocation::Kind::kConstant, Low32Bits(value));
+              DexRegisterLocation::Kind::kConstant, Low32Bits(value));
           stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kConstant, High32Bits(value));
+              DexRegisterLocation::Kind::kConstant, High32Bits(value));
+          ++i;
           DCHECK_LT(i, environment_size);
         } else if (current->IsIntConstant()) {
           int32_t value = current->AsIntConstant()->GetValue();
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
         } else if (current->IsNullConstant()) {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, 0);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, 0);
         } else {
           DCHECK(current->IsFloatConstant()) << current->DebugName();
           int32_t value = bit_cast<int32_t, float>(current->AsFloatConstant()->GetValue());
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kConstant, value);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kConstant, value);
         }
         break;
       }
 
       case Location::kStackSlot: {
         stack_map_stream_.AddDexRegisterEntry(
-            i, DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+            DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
         break;
       }
 
       case Location::kDoubleStackSlot: {
         stack_map_stream_.AddDexRegisterEntry(
-            i, DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
+            DexRegisterLocation::Kind::kInStack, location.GetStackIndex());
         stack_map_stream_.AddDexRegisterEntry(
-            ++i, DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize));
+            DexRegisterLocation::Kind::kInStack, location.GetHighStackIndex(kVRegSize));
+        ++i;
         DCHECK_LT(i, environment_size);
         break;
       }
@@ -756,16 +842,18 @@
         int id = location.reg();
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(id)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(id);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
           if (current->GetType() == Primitive::kPrimLong) {
             stack_map_stream_.AddDexRegisterEntry(
-                ++i, DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+                DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInRegister, id);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
           if (current->GetType() == Primitive::kPrimLong) {
-            stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInRegister, id);
+            stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, id);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         }
@@ -776,17 +864,18 @@
         int id = location.reg();
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(id)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(id);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
           if (current->GetType() == Primitive::kPrimDouble) {
             stack_map_stream_.AddDexRegisterEntry(
-                ++i, DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+                DexRegisterLocation::Kind::kInStack, offset + kVRegSize);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInFpuRegister, id);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
           if (current->GetType() == Primitive::kPrimDouble) {
-            stack_map_stream_.AddDexRegisterEntry(
-                ++i, DexRegisterLocation::Kind::kInFpuRegister, id);
+            stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, id);
+            ++i;
             DCHECK_LT(i, environment_size);
           }
         }
@@ -798,16 +887,17 @@
         int high = location.high();
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(low)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(low);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInFpuRegister, low);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, low);
         }
         if (slow_path != nullptr && slow_path->IsFpuRegisterSaved(high)) {
           uint32_t offset = slow_path->GetStackOffsetOfFpuRegister(high);
-          stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
+          ++i;
         } else {
-          stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kInFpuRegister, high);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInFpuRegister, high);
+          ++i;
         }
         DCHECK_LT(i, environment_size);
         break;
@@ -818,23 +908,23 @@
         int high = location.high();
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(low)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(low);
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
         } else {
-          stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kInRegister, low);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, low);
         }
         if (slow_path != nullptr && slow_path->IsCoreRegisterSaved(high)) {
           uint32_t offset = slow_path->GetStackOffsetOfCoreRegister(high);
-          stack_map_stream_.AddDexRegisterEntry(++i, DexRegisterLocation::Kind::kInStack, offset);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInStack, offset);
         } else {
-          stack_map_stream_.AddDexRegisterEntry(
-              ++i, DexRegisterLocation::Kind::kInRegister, high);
+          stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kInRegister, high);
         }
+        ++i;
         DCHECK_LT(i, environment_size);
         break;
       }
 
       case Location::kInvalid: {
-        stack_map_stream_.AddDexRegisterEntry(i, DexRegisterLocation::Kind::kNone, 0);
+        stack_map_stream_.AddDexRegisterEntry(DexRegisterLocation::Kind::kNone, 0);
         break;
       }
 
@@ -842,7 +932,10 @@
         LOG(FATAL) << "Unexpected kind " << location.GetKind();
     }
   }
-  stack_map_stream_.EndStackMapEntry();
+
+  if (environment->GetParent() != nullptr) {
+    stack_map_stream_.EndInlineInfoEntry();
+  }
 }
 
 bool CodeGenerator::CanMoveNullCheckToUser(HNullCheck* null_check) {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index c6317f1..eb63b49 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -22,6 +22,7 @@
 #include "base/bit_field.h"
 #include "driver/compiler_options.h"
 #include "globals.h"
+#include "graph_visualizer.h"
 #include "locations.h"
 #include "memory_region.h"
 #include "nodes.h"
@@ -34,10 +35,15 @@
 // Binary encoding of 2^31 for type double.
 static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
 
+// Minimum value for a primitive integer.
+static int32_t constexpr kPrimIntMin = 0x80000000;
+// Minimum value for a primitive long.
+static int64_t constexpr kPrimLongMin = INT64_C(0x8000000000000000);
+
 // Maximum value for a primitive integer.
 static int32_t constexpr kPrimIntMax = 0x7fffffff;
 // Maximum value for a primitive long.
-static int64_t constexpr kPrimLongMax = 0x7fffffffffffffff;
+static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff);
 
 class Assembler;
 class CodeGenerator;
@@ -59,11 +65,6 @@
   DISALLOW_COPY_AND_ASSIGN(CodeAllocator);
 };
 
-struct PcInfo {
-  uint32_t dex_pc;
-  uintptr_t native_pc;
-};
-
 class SlowPathCode : public ArenaObject<kArenaAllocSlowPaths> {
  public:
   SlowPathCode() {
@@ -77,8 +78,8 @@
 
   virtual void EmitNativeCode(CodeGenerator* codegen) = 0;
 
-  void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
-  void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
+  virtual void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
+  virtual void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
   void RecordPcInfo(CodeGenerator* codegen, HInstruction* instruction, uint32_t dex_pc);
 
   bool IsCoreRegisterSaved(int reg) const {
@@ -97,17 +98,23 @@
     return saved_fpu_stack_offsets_[reg];
   }
 
- private:
+  virtual const char* GetDescription() const = 0;
+
+ protected:
   static constexpr size_t kMaximumNumberOfExpectedRegisters = 32;
   static constexpr uint32_t kRegisterNotSaved = -1;
   uint32_t saved_core_stack_offsets_[kMaximumNumberOfExpectedRegisters];
   uint32_t saved_fpu_stack_offsets_[kMaximumNumberOfExpectedRegisters];
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(SlowPathCode);
 };
 
 class InvokeDexCallingConventionVisitor {
  public:
   virtual Location GetNextLocation(Primitive::Type type) = 0;
+  virtual Location GetReturnLocation(Primitive::Type type) const = 0;
+  virtual Location GetMethodLocation() const = 0;
 
  protected:
   InvokeDexCallingConventionVisitor() {}
@@ -156,6 +163,7 @@
   virtual void Bind(HBasicBlock* block) = 0;
   virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
   virtual Assembler* GetAssembler() = 0;
+  virtual const Assembler& GetAssembler() const = 0;
   virtual size_t GetWordSize() const = 0;
   virtual size_t GetFloatingPointSpillSlotSize() const = 0;
   virtual uintptr_t GetAddressOf(HBasicBlock* block) const = 0;
@@ -286,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
@@ -331,6 +345,12 @@
 
   virtual ParallelMoveResolver* GetMoveResolver() = 0;
 
+  static void CreateCommonInvokeLocationSummary(
+      HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor);
+
+  void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; }
+  DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; }
+
  protected:
   CodeGenerator(HGraph* graph,
                 size_t number_of_core_registers,
@@ -351,16 +371,16 @@
         number_of_register_pairs_(number_of_register_pairs),
         core_callee_save_mask_(core_callee_save_mask),
         fpu_callee_save_mask_(fpu_callee_save_mask),
+        stack_map_stream_(graph->GetArena()),
+        block_order_(nullptr),
         is_baseline_(false),
+        disasm_info_(nullptr),
         graph_(graph),
         compiler_options_(compiler_options),
-        pc_infos_(graph->GetArena(), 32),
         slow_paths_(graph->GetArena(), 8),
-        block_order_(nullptr),
         current_block_index_(0),
         is_leaf_(true),
-        requires_current_method_(false),
-        stack_map_stream_(graph->GetArena()) {}
+        requires_current_method_(false) {}
 
   // Register allocation logic.
   void AllocateRegistersLocally(HInstruction* instruction) const;
@@ -430,24 +450,29 @@
   const uint32_t core_callee_save_mask_;
   const uint32_t fpu_callee_save_mask_;
 
+  StackMapStream stack_map_stream_;
+
+  // The order to use for code generation.
+  const GrowableArray<HBasicBlock*>* block_order_;
+
   // Whether we are using baseline.
   bool is_baseline_;
 
+  DisassemblyInformation* disasm_info_;
+
  private:
   void InitLocationsBaseline(HInstruction* instruction);
   size_t GetStackOffsetOfSavedRegister(size_t index);
+  void GenerateSlowPaths();
   void CompileInternal(CodeAllocator* allocator, bool is_baseline);
   void BlockIfInRegister(Location location, bool is_out = false) const;
+  void EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path);
 
   HGraph* const graph_;
   const CompilerOptions& compiler_options_;
 
-  GrowableArray<PcInfo> pc_infos_;
   GrowableArray<SlowPathCode*> slow_paths_;
 
-  // The order to use for code generation.
-  const GrowableArray<HBasicBlock*>* block_order_;
-
   // The current block index in `block_order_` of the block
   // we are generating code for.
   size_t current_block_index_;
@@ -458,8 +483,6 @@
   // Whether an instruction in the graph accesses the current method.
   bool requires_current_method_;
 
-  StackMapStream stack_map_stream_;
-
   friend class OptimizingCFITest;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 3f28e64..e3683ef 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -18,6 +18,7 @@
 
 #include "arch/arm/instruction_set_features_arm.h"
 #include "art_method.h"
+#include "code_generator_utils.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/accounting/card_table.h"
 #include "intrinsics.h"
@@ -40,6 +41,7 @@
 }
 
 static constexpr int kCurrentMethodStackOffset = 0;
+static constexpr Register kMethodRegisterArgument = R0;
 
 // We unconditionally allocate R5 to ensure we can do long operations
 // with baseline.
@@ -53,7 +55,7 @@
 // S registers. Therefore there is no need to block it.
 static constexpr DRegister DTMP = D31;
 
-#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())->
+#define __ down_cast<ArmAssembler*>(codegen->GetAssembler())->
 #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value()
 
 class NullCheckSlowPathARM : public SlowPathCodeARM {
@@ -67,6 +69,8 @@
         QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM"; }
+
  private:
   HNullCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM);
@@ -83,6 +87,8 @@
         QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM"; }
+
  private:
   HDivZeroCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM);
@@ -116,6 +122,8 @@
     return successor_;
   }
 
+  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM"; }
+
  private:
   HSuspendCheck* const instruction_;
   // If not null, the block to branch to after the suspend check.
@@ -153,6 +161,8 @@
         QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM"; }
+
  private:
   HBoundsCheck* const instruction_;
   const Location index_location_;
@@ -195,6 +205,8 @@
     __ b(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM"; }
+
  private:
   // The class this slow path will load.
   HLoadClass* const cls_;
@@ -234,6 +246,8 @@
     __ b(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
+
  private:
   HLoadString* const instruction_;
 
@@ -284,6 +298,8 @@
     __ b(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM"; }
+
  private:
   HInstruction* const instruction_;
   const Location class_to_check_;
@@ -308,15 +324,15 @@
     arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM"; }
+
  private:
   HInstruction* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM);
 };
 
 #undef __
-
-#undef __
-#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())->
+#define __ down_cast<ArmAssembler*>(GetAssembler())->
 
 inline Condition ARMCondition(IfCondition cond) {
   switch (cond) {
@@ -347,11 +363,11 @@
 }
 
 void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << ArmManagedRegister::FromCoreRegister(Register(reg));
+  stream << Register(reg);
 }
 
 void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << ArmManagedRegister::FromSRegister(SRegister(reg));
+  stream << SRegister(reg);
 }
 
 size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
@@ -390,12 +406,52 @@
       location_builder_(graph, this),
       instruction_visitor_(graph, this),
       move_resolver_(graph->GetArena(), this),
-      assembler_(true),
+      assembler_(),
       isa_features_(isa_features) {
   // Save the PC register to mimic Quick.
   AddAllocatedRegister(Location::RegisterLocation(PC));
 }
 
+void CodeGeneratorARM::Finalize(CodeAllocator* allocator) {
+  // Ensure that we fix up branches and literal loads and emit the literal pool.
+  __ FinalizeCode();
+
+  // Adjust native pc offsets in stack maps.
+  for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
+    uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
+    uint32_t new_position = __ GetAdjustedPosition(old_position);
+    stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
+  }
+  // Adjust native pc offsets of block labels.
+  for (size_t block_idx = 0u, end = block_order_->Size(); block_idx != end; ++block_idx) {
+    HBasicBlock* block = block_order_->Get(block_idx);
+    // Get the label directly from block_labels_ rather than through GetLabelOf() to avoid
+    // FirstNonEmptyBlock() which could lead to adjusting a label more than once.
+    DCHECK_LT(static_cast<size_t>(block->GetBlockId()), block_labels_.Size());
+    Label* block_label = &block_labels_.GetRawStorage()[block->GetBlockId()];
+    DCHECK_EQ(block_label->IsBound(), !block->IsSingleJump());
+    if (block_label->IsBound()) {
+      __ AdjustLabelPosition(block_label);
+    }
+  }
+  // Adjust pc offsets for the disassembly information.
+  if (disasm_info_ != nullptr) {
+    GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
+    frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
+    frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
+    for (auto& it : *disasm_info_->GetInstructionIntervals()) {
+      it.second.start = __ GetAdjustedPosition(it.second.start);
+      it.second.end = __ GetAdjustedPosition(it.second.end);
+    }
+    for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
+      it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
+      it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
+    }
+  }
+
+  CodeGenerator::Finalize(allocator);
+}
+
 Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const {
   switch (type) {
     case Primitive::kPrimLong: {
@@ -543,7 +599,7 @@
   uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR;
   __ PushList(push_mask);
   __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask));
-  __ cfi().RelOffsetForMany(DWARFReg(R0), 0, push_mask, kArmWordSize);
+  __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, push_mask, kArmWordSize);
   if (fpu_spill_mask_ != 0) {
     SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_));
     __ vpushs(start_register, POPCOUNT(fpu_spill_mask_));
@@ -553,7 +609,7 @@
   int adjust = GetFrameSize() - FrameEntrySpillSize();
   __ AddConstant(SP, -adjust);
   __ cfi().AdjustCFAOffset(adjust);
-  __ StoreToOffset(kStoreWord, R0, SP, 0);
+  __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0);
 }
 
 void CodeGeneratorARM::GenerateFrameExit() {
@@ -679,7 +735,7 @@
   return Location();
 }
 
-Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) {
+Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) const {
   switch (type) {
     case Primitive::kPrimBoolean:
     case Primitive::kPrimByte:
@@ -705,9 +761,14 @@
     case Primitive::kPrimVoid:
       return Location();
   }
+
   UNREACHABLE();
 }
 
+Location InvokeDexCallingConventionVisitorARM::GetMethodLocation() const {
+  return Location::RegisterLocation(kMethodRegisterArgument);
+}
+
 void CodeGeneratorARM::Move32(Location destination, Location source) {
   if (source.Equals(destination)) {
     return;
@@ -802,11 +863,11 @@
 
 void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
   LocationSummary* locations = instruction->GetLocations();
-  if (locations != nullptr && locations->Out().Equals(location)) {
+  if (instruction->IsCurrentMethod()) {
+    Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
+  } else if (locations != nullptr && locations->Out().Equals(location)) {
     return;
-  }
-
-  if (locations != nullptr && locations->Out().IsConstant()) {
+  } else if (locations != nullptr && locations->Out().IsConstant()) {
     HConstant* const_to_move = locations->Out().GetConstant();
     if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
       int32_t value = GetInt32ValueOf(const_to_move);
@@ -899,12 +960,7 @@
       || !IsLeafMethod());
 }
 
-void LocationsBuilderARM::VisitGoto(HGoto* got) {
-  got->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
-  HBasicBlock* successor = got->GetSuccessor();
+void InstructionCodeGeneratorARM::HandleGoto(HInstruction* got, HBasicBlock* successor) {
   DCHECK(!successor->IsExitBlock());
 
   HBasicBlock* block = got->GetBlock();
@@ -925,6 +981,25 @@
   }
 }
 
+void LocationsBuilderARM::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) {
+  HandleGoto(got, got->GetSuccessor());
+}
+
+void LocationsBuilderARM::VisitTryBoundary(HTryBoundary* try_boundary) {
+  try_boundary->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM::VisitTryBoundary(HTryBoundary* try_boundary) {
+  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
+  if (!successor->IsExitBlock()) {
+    HandleGoto(try_boundary, successor);
+  }
+}
+
 void LocationsBuilderARM::VisitExit(HExit* exit) {
   exit->SetLocations(nullptr);
 }
@@ -953,9 +1028,8 @@
     if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
       // Condition has been materialized, compare the output to 0
       DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
-      __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
-             ShifterOperand(0));
-      __ b(true_target, NE);
+      __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
+                                   true_target);
     } else {
       // Condition has not been materialized, use its inputs as the
       // comparison and its condition as the branch condition.
@@ -1027,19 +1101,19 @@
   GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
 }
 
-void LocationsBuilderARM::VisitCondition(HCondition* comp) {
+void LocationsBuilderARM::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
+      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
   locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)));
-  if (comp->NeedsMaterialization()) {
+  locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+  if (cond->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
   }
 }
 
-void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) {
-  if (!comp->NeedsMaterialization()) return;
-  LocationSummary* locations = comp->GetLocations();
+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()) {
@@ -1056,11 +1130,11 @@
       __ cmp(left, ShifterOperand(temp));
     }
   }
-  __ it(ARMCondition(comp->GetCondition()), kItElse);
+  __ it(ARMCondition(cond->GetCondition()), kItElse);
   __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1),
-         ARMCondition(comp->GetCondition()));
+         ARMCondition(cond->GetCondition()));
   __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0),
-         ARMOppositeCondition(comp->GetCondition()));
+         ARMOppositeCondition(cond->GetCondition()));
 }
 
 void LocationsBuilderARM::VisitEqual(HEqual* comp) {
@@ -1253,11 +1327,6 @@
   HandleInvoke(invoke);
 }
 
-void CodeGeneratorARM::LoadCurrentMethod(Register reg) {
-  DCHECK(RequiresCurrentMethod());
-  __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
-}
-
 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) {
   if (invoke->GetLocations()->Intrinsified()) {
     IntrinsicCodeGeneratorARM intrinsic(codegen);
@@ -1276,24 +1345,15 @@
     return;
   }
 
-  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
-
-  codegen_->GenerateStaticOrDirectCall(invoke, temp);
+  LocationSummary* locations = invoke->GetLocations();
+  codegen_->GenerateStaticOrDirectCall(
+      invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
 void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(Location::RegisterLocation(R0));
-
   InvokeDexCallingConventionVisitorARM calling_convention_visitor;
-  for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
-    HInstruction* input = invoke->InputAt(i);
-    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
-  }
-
-  locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType()));
+  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
 }
 
 void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -1318,13 +1378,10 @@
   Location receiver = locations->InAt(0);
   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   // temp = object->GetClass();
-  if (receiver.IsStackSlot()) {
-    __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
-    __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
-  } else {
-    __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
-  }
+  DCHECK(receiver.IsRegister());
+  __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
   // temp = temp->GetMethodAt(method_offset);
   uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
       kArmWordSize).Int32Value();
@@ -1364,6 +1421,7 @@
     __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
   }
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
   // temp = temp->GetImtEntryAt(method_offset);
   uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
       kArmWordSize).Int32Value();
@@ -1454,11 +1512,12 @@
   Primitive::Type input_type = conversion->GetInputType();
   DCHECK_NE(result_type, input_type);
 
-  // The float-to-long and double-to-long type conversions rely on a
-  // call to the runtime.
+  // The float-to-long, double-to-long and long-to-float type conversions
+  // rely on a call to the runtime.
   LocationSummary::CallKind call_kind =
-      ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
-       && result_type == Primitive::kPrimLong)
+      (((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
+        && result_type == Primitive::kPrimLong)
+       || (input_type == Primitive::kPrimLong && result_type == Primitive::kPrimFloat))
       ? LocationSummary::kCall
       : LocationSummary::kNoCall;
   LocationSummary* locations =
@@ -1601,15 +1660,14 @@
           locations->SetOut(Location::RequiresFpuRegister());
           break;
 
-        case Primitive::kPrimLong:
+        case Primitive::kPrimLong: {
           // Processing a Dex `long-to-float' instruction.
-          locations->SetInAt(0, Location::RequiresRegister());
-          locations->SetOut(Location::RequiresFpuRegister());
-          locations->AddTemp(Location::RequiresRegister());
-          locations->AddTemp(Location::RequiresRegister());
-          locations->AddTemp(Location::RequiresFpuRegister());
-          locations->AddTemp(Location::RequiresFpuRegister());
+          InvokeRuntimeCallingConvention calling_convention;
+          locations->SetInAt(0, Location::RegisterPairLocation(
+              calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
+          locations->SetOut(Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
           break;
+        }
 
         case Primitive::kPrimDouble:
           // Processing a Dex `double-to-float' instruction.
@@ -1640,8 +1698,7 @@
           // Processing a Dex `long-to-double' instruction.
           locations->SetInAt(0, Location::RequiresRegister());
           locations->SetOut(Location::RequiresFpuRegister());
-          locations->AddTemp(Location::RequiresRegister());
-          locations->AddTemp(Location::RequiresRegister());
+          locations->AddTemp(Location::RequiresFpuRegister());
           locations->AddTemp(Location::RequiresFpuRegister());
           break;
 
@@ -1818,47 +1875,13 @@
           break;
         }
 
-        case Primitive::kPrimLong: {
+        case Primitive::kPrimLong:
           // Processing a Dex `long-to-float' instruction.
-          Register low = in.AsRegisterPairLow<Register>();
-          Register high = in.AsRegisterPairHigh<Register>();
-          SRegister output = out.AsFpuRegister<SRegister>();
-          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
-          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
-          SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
-          DRegister temp1_d = FromLowSToD(temp1_s);
-          SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>();
-          DRegister temp2_d = FromLowSToD(temp2_s);
-
-          // Operations use doubles for precision reasons (each 32-bit
-          // half of a long fits in the 53-bit mantissa of a double,
-          // but not in the 24-bit mantissa of a float).  This is
-          // especially important for the low bits.  The result is
-          // eventually converted to float.
-
-          // temp1_d = int-to-double(high)
-          __ vmovsr(temp1_s, high);
-          __ vcvtdi(temp1_d, temp1_s);
-          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
-          // as an immediate value into `temp2_d` does not work, as
-          // this instruction only transfers 8 significant bits of its
-          // immediate operand.  Instead, use two 32-bit core
-          // registers to load `k2Pow32EncodingForDouble` into
-          // `temp2_d`.
-          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
-          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
-          __ vmovdrr(temp2_d, constant_low, constant_high);
-          // temp1_d = temp1_d * 2^32
-          __ vmuld(temp1_d, temp1_d, temp2_d);
-          // temp2_d = unsigned-to-double(low)
-          __ vmovsr(temp2_s, low);
-          __ vcvtdu(temp2_d, temp2_s);
-          // temp1_d = temp1_d + temp2_d
-          __ vaddd(temp1_d, temp1_d, temp2_d);
-          // output = double-to-float(temp1_d);
-          __ vcvtsd(output, temp1_d);
+          codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pL2f),
+                                  conversion,
+                                  conversion->GetDexPc(),
+                                  nullptr);
           break;
-        }
 
         case Primitive::kPrimDouble:
           // Processing a Dex `double-to-float' instruction.
@@ -1893,29 +1916,21 @@
           Register high = in.AsRegisterPairHigh<Register>();
           SRegister out_s = out.AsFpuRegisterPairLow<SRegister>();
           DRegister out_d = FromLowSToD(out_s);
-          Register constant_low = locations->GetTemp(0).AsRegister<Register>();
-          Register constant_high = locations->GetTemp(1).AsRegister<Register>();
-          SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>();
+          SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
           DRegister temp_d = FromLowSToD(temp_s);
+          SRegister constant_s = locations->GetTemp(1).AsFpuRegisterPairLow<SRegister>();
+          DRegister constant_d = FromLowSToD(constant_s);
 
-          // out_d = int-to-double(high)
-          __ vmovsr(out_s, high);
-          __ vcvtdi(out_d, out_s);
-          // Using vmovd to load the `k2Pow32EncodingForDouble` constant
-          // as an immediate value into `temp_d` does not work, as
-          // this instruction only transfers 8 significant bits of its
-          // immediate operand.  Instead, use two 32-bit core
-          // registers to load `k2Pow32EncodingForDouble` into `temp_d`.
-          __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble));
-          __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble));
-          __ vmovdrr(temp_d, constant_low, constant_high);
-          // out_d = out_d * 2^32
-          __ vmuld(out_d, out_d, temp_d);
-          // temp_d = unsigned-to-double(low)
-          __ vmovsr(temp_s, low);
-          __ vcvtdu(temp_d, temp_s);
-          // out_d = out_d + temp_d
-          __ vaddd(out_d, out_d, temp_d);
+          // temp_d = int-to-double(high)
+          __ vmovsr(temp_s, high);
+          __ vcvtdi(temp_d, temp_s);
+          // constant_d = k2Pow32EncodingForDouble
+          __ LoadDImmediate(constant_d, bit_cast<double, int64_t>(k2Pow32EncodingForDouble));
+          // out_d = unsigned-to-double(low)
+          __ vmovsr(out_s, low);
+          __ vcvtdu(out_d, out_s);
+          // out_d += temp_d * constant_d
+          __ vmlad(out_d, temp_d, constant_d);
           break;
         }
 
@@ -2180,11 +2195,134 @@
   }
 }
 
+void InstructionCodeGeneratorARM::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = locations->Out().AsRegister<Register>();
+  Register dividend = locations->InAt(0).AsRegister<Register>();
+  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  DCHECK(imm == 1 || imm == -1);
+
+  if (instruction->IsRem()) {
+    __ LoadImmediate(out, 0);
+  } else {
+    if (imm == 1) {
+      __ Mov(out, dividend);
+    } else {
+      __ rsb(out, dividend, ShifterOperand(0));
+    }
+  }
+}
+
+void InstructionCodeGeneratorARM::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = locations->Out().AsRegister<Register>();
+  Register dividend = locations->InAt(0).AsRegister<Register>();
+  Register temp = locations->GetTemp(0).AsRegister<Register>();
+  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  uint32_t abs_imm = static_cast<uint32_t>(std::abs(imm));
+  DCHECK(IsPowerOfTwo(abs_imm));
+  int ctz_imm = CTZ(abs_imm);
+
+  if (ctz_imm == 1) {
+    __ Lsr(temp, dividend, 32 - ctz_imm);
+  } else {
+    __ Asr(temp, dividend, 31);
+    __ Lsr(temp, temp, 32 - ctz_imm);
+  }
+  __ add(out, temp, ShifterOperand(dividend));
+
+  if (instruction->IsDiv()) {
+    __ Asr(out, out, ctz_imm);
+    if (imm < 0) {
+      __ rsb(out, out, ShifterOperand(0));
+    }
+  } else {
+    __ ubfx(out, out, 0, ctz_imm);
+    __ sub(out, out, ShifterOperand(temp));
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = locations->Out().AsRegister<Register>();
+  Register dividend = locations->InAt(0).AsRegister<Register>();
+  Register temp1 = locations->GetTemp(0).AsRegister<Register>();
+  Register temp2 = locations->GetTemp(1).AsRegister<Register>();
+  int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+
+  int64_t magic;
+  int shift;
+  CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
+
+  __ LoadImmediate(temp1, magic);
+  __ smull(temp2, temp1, dividend, temp1);
+
+  if (imm > 0 && magic < 0) {
+    __ add(temp1, temp1, ShifterOperand(dividend));
+  } else if (imm < 0 && magic > 0) {
+    __ sub(temp1, temp1, ShifterOperand(dividend));
+  }
+
+  if (shift != 0) {
+    __ Asr(temp1, temp1, shift);
+  }
+
+  if (instruction->IsDiv()) {
+    __ sub(out, temp1, ShifterOperand(temp1, ASR, 31));
+  } else {
+    __ sub(temp1, temp1, ShifterOperand(temp1, ASR, 31));
+    // TODO: Strength reduction for mls.
+    __ LoadImmediate(temp2, imm);
+    __ mls(out, temp1, temp2, dividend);
+  }
+}
+
+void InstructionCodeGeneratorARM::GenerateDivRemConstantIntegral(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  DCHECK(instruction->GetResultType() == Primitive::kPrimInt);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+  if (imm == 0) {
+    // Do not generate anything. DivZeroCheck would prevent any code to be executed.
+  } else if (imm == 1 || imm == -1) {
+    DivRemOneOrMinusOne(instruction);
+  } else if (IsPowerOfTwo(std::abs(imm))) {
+    DivRemByPowerOfTwo(instruction);
+  } else {
+    DCHECK(imm <= -2 || imm >= 2);
+    GenerateDivRemWithAnyConstant(instruction);
+  }
+}
+
 void LocationsBuilderARM::VisitDiv(HDiv* div) {
   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   if (div->GetResultType() == Primitive::kPrimLong) {
     // pLdiv runtime call.
     call_kind = LocationSummary::kCall;
+  } else if (div->GetResultType() == Primitive::kPrimInt && div->InputAt(1)->IsConstant()) {
+    // sdiv will be replaced by other instruction sequence.
   } else if (div->GetResultType() == Primitive::kPrimInt &&
              !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
     // pIdivmod runtime call.
@@ -2195,7 +2333,20 @@
 
   switch (div->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (div->InputAt(1)->IsConstant()) {
+        locations->SetInAt(0, Location::RequiresRegister());
+        locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
+        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+        int32_t abs_imm = std::abs(div->InputAt(1)->AsIntConstant()->GetValue());
+        if (abs_imm <= 1) {
+          // No temp register required.
+        } else {
+          locations->AddTemp(Location::RequiresRegister());
+          if (!IsPowerOfTwo(abs_imm)) {
+            locations->AddTemp(Location::RequiresRegister());
+          }
+        }
+      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::RequiresRegister());
         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2239,7 +2390,9 @@
 
   switch (div->GetResultType()) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (second.IsConstant()) {
+        GenerateDivRemConstantIntegral(div);
+      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         __ sdiv(out.AsRegister<Register>(),
                 first.AsRegister<Register>(),
                 second.AsRegister<Register>());
@@ -2291,8 +2444,11 @@
 
   // Most remainders are implemented in the runtime.
   LocationSummary::CallKind call_kind = LocationSummary::kCall;
-  if (rem->GetResultType() == Primitive::kPrimInt &&
-      codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+  if (rem->GetResultType() == Primitive::kPrimInt && rem->InputAt(1)->IsConstant()) {
+    // sdiv will be replaced by other instruction sequence.
+    call_kind = LocationSummary::kNoCall;
+  } else if ((rem->GetResultType() == Primitive::kPrimInt)
+             && codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
     // Have hardware divide instruction for int, do it with three instructions.
     call_kind = LocationSummary::kNoCall;
   }
@@ -2301,7 +2457,20 @@
 
   switch (type) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+      if (rem->InputAt(1)->IsConstant()) {
+        locations->SetInAt(0, Location::RequiresRegister());
+        locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
+        locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+        int32_t abs_imm = std::abs(rem->InputAt(1)->AsIntConstant()->GetValue());
+        if (abs_imm <= 1) {
+          // No temp register required.
+        } else {
+          locations->AddTemp(Location::RequiresRegister());
+          if (!IsPowerOfTwo(abs_imm)) {
+            locations->AddTemp(Location::RequiresRegister());
+          }
+        }
+      } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         locations->SetInAt(0, Location::RequiresRegister());
         locations->SetInAt(1, Location::RequiresRegister());
         locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
@@ -2358,7 +2527,9 @@
   Primitive::Type type = rem->GetResultType();
   switch (type) {
     case Primitive::kPrimInt: {
-      if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
+        if (second.IsConstant()) {
+          GenerateDivRemConstantIntegral(rem);
+        } else if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) {
         Register reg1 = first.AsRegister<Register>();
         Register reg2 = second.AsRegister<Register>();
         Register temp = locations->GetTemp(0).AsRegister<Register>();
@@ -2419,8 +2590,7 @@
   switch (instruction->GetType()) {
     case Primitive::kPrimInt: {
       if (value.IsRegister()) {
-        __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
-        __ b(slow_path->GetEntryLabel(), EQ);
+        __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
       } else {
         DCHECK(value.IsConstant()) << value;
         if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
@@ -2601,14 +2771,15 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetOut(Location::RegisterLocation(R0));
 }
 
 void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
   __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
                           instruction,
                           instruction->GetDexPc(),
@@ -2620,15 +2791,16 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   locations->SetOut(Location::RegisterLocation(R0));
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
 }
 
 void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
   __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(),
                           instruction,
                           instruction->GetDexPc(),
@@ -2647,9 +2819,19 @@
   locations->SetOut(location);
 }
 
-void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) {
+void InstructionCodeGeneratorARM::VisitParameterValue(
+    HParameterValue* instruction ATTRIBUTE_UNUSED) {
   // Nothing to do, the parameter is already at its location.
-  UNUSED(instruction);
+}
+
+void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
+}
+
+void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
+  // Nothing to do, the method is already at its location.
 }
 
 void LocationsBuilderARM::VisitNot(HNot* not_) {
@@ -2782,22 +2964,22 @@
 
 void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) {
   // TODO (ported from quick): revisit Arm barrier kinds
-  DmbOptions flavour = DmbOptions::ISH;  // quiet c++ warnings
+  DmbOptions flavor = DmbOptions::ISH;  // quiet c++ warnings
   switch (kind) {
     case MemBarrierKind::kAnyStore:
     case MemBarrierKind::kLoadAny:
     case MemBarrierKind::kAnyAny: {
-      flavour = DmbOptions::ISH;
+      flavor = DmbOptions::ISH;
       break;
     }
     case MemBarrierKind::kStoreStore: {
-      flavour = DmbOptions::ISHST;
+      flavor = DmbOptions::ISHST;
       break;
     }
     default:
       LOG(FATAL) << "Unexpected memory barrier " << kind;
   }
-  __ dmb(flavour);
+  __ dmb(flavor);
 }
 
 void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr,
@@ -2831,8 +3013,7 @@
   __ ldrexd(temp1, temp2, addr);
   codegen_->MaybeRecordImplicitNullCheck(instruction);
   __ strexd(temp1, value_lo, value_hi, addr);
-  __ cmp(temp1, ShifterOperand(0));
-  __ b(&fail, NE);
+  __ CompareAndBranchIfNonZero(temp1, &fail);
 }
 
 void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
@@ -2853,10 +3034,12 @@
   bool generate_volatile = field_info.IsVolatile()
       && is_wide
       && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
   // Temporary registers for the write barrier.
   // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark.
-  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
-    locations->AddTemp(Location::RequiresRegister());
+  if (needs_write_barrier) {
+    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     locations->AddTemp(Location::RequiresRegister());
   } else if (generate_volatile) {
     // Arm encoding have some additional constraints for ldrexd/strexd:
@@ -2877,7 +3060,8 @@
 }
 
 void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction,
-                                                 const FieldInfo& field_info) {
+                                                 const FieldInfo& field_info,
+                                                 bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
 
   LocationSummary* locations = instruction->GetLocations();
@@ -2888,6 +3072,8 @@
   bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd();
   Primitive::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
 
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
@@ -2908,7 +3094,18 @@
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
+      if (kPoisonHeapReferences && needs_write_barrier) {
+        // Note that in the case where `value` is a null reference,
+        // we do not enter this block, as a null reference does not
+        // need poisoning.
+        DCHECK_EQ(field_type, Primitive::kPrimNot);
+        Register temp = locations->GetTemp(0).AsRegister<Register>();
+        __ Mov(temp, value.AsRegister<Register>());
+        __ PoisonHeapReference(temp);
+        __ StoreToOffset(kStoreWord, temp, base, offset);
+      } else {
+        __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset);
+      }
       break;
     }
 
@@ -2966,7 +3163,8 @@
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     Register card = locations->GetTemp(1).AsRegister<Register>();
-    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+    codegen_->MarkGCCard(
+        temp, card, base, value.AsRegister<Register>(), value_can_be_null);
   }
 
   if (is_volatile) {
@@ -3086,6 +3284,10 @@
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   }
+
+  if (field_type == Primitive::kPrimNot) {
+    __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
+  }
 }
 
 void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -3093,7 +3295,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3117,7 +3319,7 @@
 }
 
 void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3146,8 +3348,7 @@
   LocationSummary* locations = instruction->GetLocations();
   Location obj = locations->InAt(0);
 
-  __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
-  __ b(slow_path->GetEntryLabel(), EQ);
+  __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
 }
 
 void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3174,8 +3375,9 @@
   LocationSummary* locations = instruction->GetLocations();
   Register obj = locations->InAt(0).AsRegister<Register>();
   Location index = locations->InAt(1);
+  Primitive::Type type = instruction->GetType();
 
-  switch (instruction->GetType()) {
+  switch (type) {
     case Primitive::kPrimBoolean: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
       Register out = locations->Out().AsRegister<Register>();
@@ -3234,7 +3436,8 @@
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
+      static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
+                    "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       Register out = locations->Out().AsRegister<Register>();
       if (index.IsConstant()) {
@@ -3291,10 +3494,15 @@
     }
 
     case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+  if (type == Primitive::kPrimNot) {
+    Register out = locations->Out().AsRegister<Register>();
+    __ MaybeUnpoisonHeapReference(out);
+  }
 }
 
 void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) {
@@ -3322,7 +3530,7 @@
 
     if (needs_write_barrier) {
       // Temporary registers for the write barrier.
-      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
       locations->AddTemp(Location::RequiresRegister());
     }
   }
@@ -3373,24 +3581,37 @@
       if (!needs_runtime_call) {
         uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
         Register value = locations->InAt(2).AsRegister<Register>();
+        Register source = value;
+        if (kPoisonHeapReferences && needs_write_barrier) {
+          // Note that in the case where `value` is a null reference,
+          // we do not enter this block, as a null reference does not
+          // need poisoning.
+          DCHECK_EQ(value_type, Primitive::kPrimNot);
+          Register temp = locations->GetTemp(0).AsRegister<Register>();
+          __ Mov(temp, value);
+          __ PoisonHeapReference(temp);
+          source = temp;
+        }
         if (index.IsConstant()) {
           size_t offset =
               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
-          __ StoreToOffset(kStoreWord, value, obj, offset);
+          __ StoreToOffset(kStoreWord, source, obj, offset);
         } else {
           DCHECK(index.IsRegister()) << index;
           __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4));
-          __ StoreToOffset(kStoreWord, value, IP, data_offset);
+          __ StoreToOffset(kStoreWord, source, IP, data_offset);
         }
         codegen_->MaybeRecordImplicitNullCheck(instruction);
         if (needs_write_barrier) {
           DCHECK_EQ(value_type, Primitive::kPrimNot);
           Register temp = locations->GetTemp(0).AsRegister<Register>();
           Register card = locations->GetTemp(1).AsRegister<Register>();
-          codegen_->MarkGCCard(temp, card, obj, value);
+          codegen_->MarkGCCard(temp, card, obj, value, instruction->GetValueCanBeNull());
         }
       } else {
         DCHECK_EQ(value_type, Primitive::kPrimNot);
+        // Note: if heap poisoning is enabled, pAputObject takes cares
+        // of poisoning the reference.
         codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
                                 instruction,
                                 instruction->GetDexPc(),
@@ -3492,13 +3713,21 @@
   __ b(slow_path->GetEntryLabel(), CS);
 }
 
-void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) {
+void CodeGeneratorARM::MarkGCCard(Register temp,
+                                  Register card,
+                                  Register object,
+                                  Register value,
+                                  bool can_be_null) {
   Label is_null;
-  __ CompareAndBranchIfZero(value, &is_null);
+  if (can_be_null) {
+    __ CompareAndBranchIfZero(value, &is_null);
+  }
   __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value());
   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
   __ strb(card, Address(card, temp));
-  __ Bind(&is_null);
+  if (can_be_null) {
+    __ Bind(&is_null);
+  }
 }
 
 void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
@@ -3555,13 +3784,11 @@
 
   __ LoadFromOffset(
       kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
-  __ cmp(IP, ShifterOperand(0));
-  // TODO: Figure out the branch offsets and use cbz/cbnz.
   if (successor == nullptr) {
-    __ b(slow_path->GetEntryLabel(), NE);
+    __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
     __ Bind(slow_path->GetReturnLabel());
   } else {
-    __ b(codegen_->GetLabelOf(successor), EQ);
+    __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
     __ b(slow_path->GetEntryLabel());
   }
 }
@@ -3789,28 +4016,32 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
-  Register out = cls->GetLocations()->Out().AsRegister<Register>();
+  LocationSummary* locations = cls->GetLocations();
+  Register out = locations->Out().AsRegister<Register>();
+  Register current_method = locations->InAt(0).AsRegister<Register>();
   if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
-    codegen_->LoadCurrentMethod(out);
-    __ LoadFromOffset(kLoadWord, out, out, ArtMethod::DeclaringClassOffset().Int32Value());
+    __ LoadFromOffset(
+        kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
   } else {
     DCHECK(cls->CanCallRuntime());
-    codegen_->LoadCurrentMethod(out);
-    __ LoadFromOffset(
-        kLoadWord, out, out, ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
+    __ LoadFromOffset(kLoadWord,
+                      out,
+                      current_method,
+                      ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
     __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
+    __ MaybeUnpoisonHeapReference(out);
 
     SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
     codegen_->AddSlowPath(slow_path);
-    __ cmp(out, ShifterOperand(0));
-    __ b(slow_path->GetEntryLabel(), EQ);
+    __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
     if (cls->MustGenerateClinitCheck()) {
       GenerateClassInitializationCheck(slow_path, out);
     } else {
@@ -3851,6 +4082,7 @@
 void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -3858,13 +4090,16 @@
   SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
   codegen_->AddSlowPath(slow_path);
 
-  Register out = load->GetLocations()->Out().AsRegister<Register>();
-  codegen_->LoadCurrentMethod(out);
-  __ LoadFromOffset(kLoadWord, out, out, ArtMethod::DeclaringClassOffset().Int32Value());
+  LocationSummary* locations = load->GetLocations();
+  Register out = locations->Out().AsRegister<Register>();
+  Register current_method = locations->InAt(0).AsRegister<Register>();
+  __ LoadFromOffset(
+      kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
   __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
+  __ MaybeUnpoisonHeapReference(out);
   __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
-  __ cmp(out, ShifterOperand(0));
-  __ b(slow_path->GetEntryLabel(), EQ);
+  __ MaybeUnpoisonHeapReference(out);
+  __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
 
@@ -3917,11 +4152,11 @@
   // Return 0 if `obj` is null.
   // avoid null check if we know obj is not null.
   if (instruction->MustDoNullCheck()) {
-    __ cmp(obj, ShifterOperand(0));
-    __ b(&zero, EQ);
+    __ CompareAndBranchIfZero(obj, &zero);
   }
   // Compare the class of `obj` with `cls`.
   __ LoadFromOffset(kLoadWord, out, obj, class_offset);
+  __ MaybeUnpoisonHeapReference(out);
   __ cmp(out, ShifterOperand(cls));
   if (instruction->IsClassFinal()) {
     // Classes must be equal for the instanceof to succeed.
@@ -3971,12 +4206,14 @@
 
   // avoid null check if we know obj is not null.
   if (instruction->MustDoNullCheck()) {
-    __ cmp(obj, ShifterOperand(0));
-    __ b(slow_path->GetExitLabel(), EQ);
+    __ CompareAndBranchIfZero(obj, slow_path->GetExitLabel());
   }
   // Compare the class of `obj` with `cls`.
   __ LoadFromOffset(kLoadWord, temp, obj, class_offset);
+  __ MaybeUnpoisonHeapReference(temp);
   __ cmp(temp, ShifterOperand(cls));
+  // The checkcast succeeds if the classes are equal (fast path).
+  // Otherwise, we need to go into the slow path to check the types.
   __ b(slow_path->GetEntryLabel(), NE);
   __ Bind(slow_path->GetExitLabel());
 }
@@ -4068,9 +4305,7 @@
   }
 }
 
-void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
-  DCHECK_EQ(temp, kArtMethodRegister);
-
+void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
   // TODO: Implement all kinds of calls:
   // 1) boot -> boot
   // 2) app -> boot
@@ -4079,32 +4314,40 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   if (invoke->IsStringInit()) {
+    Register reg = temp.AsRegister<Register>();
     // temp = thread->string_init_entrypoint
-    __ LoadFromOffset(kLoadWord, temp, TR, invoke->GetStringInitOffset());
+    __ LoadFromOffset(kLoadWord, reg, TR, invoke->GetStringInitOffset());
     // LR = temp[offset_of_quick_compiled_code]
-    __ LoadFromOffset(kLoadWord, LR, temp,
+    __ LoadFromOffset(kLoadWord, LR, reg,
                       ArtMethod::EntryPointFromQuickCompiledCodeOffset(
                           kArmWordSize).Int32Value());
     // LR()
     __ blx(LR);
+  } else if (invoke->IsRecursive()) {
+    __ bl(GetFrameEntryLabel());
   } else {
-    // temp = method;
-    LoadCurrentMethod(temp);
-    if (!invoke->IsRecursive()) {
-      // temp = temp->dex_cache_resolved_methods_;
-      __ LoadFromOffset(
-          kLoadWord, temp, temp, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
-      // temp = temp[index_in_cache]
-      __ LoadFromOffset(
-          kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
-      // LR = temp[offset_of_quick_compiled_code]
-      __ LoadFromOffset(kLoadWord, LR, temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
-          kArmWordSize).Int32Value());
-      // LR()
-      __ blx(LR);
+    Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
+    Register method_reg;
+    Register reg = temp.AsRegister<Register>();
+    if (current_method.IsRegister()) {
+      method_reg = current_method.AsRegister<Register>();
     } else {
-      __ bl(GetFrameEntryLabel());
+      DCHECK(invoke->GetLocations()->Intrinsified());
+      DCHECK(!current_method.IsValid());
+      method_reg = reg;
+      __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset);
     }
+    // reg = current_method->dex_cache_resolved_methods_;
+    __ LoadFromOffset(
+        kLoadWord, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
+    // reg = reg[index_in_cache]
+    __ LoadFromOffset(
+        kLoadWord, reg, reg, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex()));
+    // LR = reg[offset_of_quick_compiled_code]
+    __ LoadFromOffset(kLoadWord, LR, reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+        kArmWordSize).Int32Value());
+    // LR()
+    __ blx(LR);
   }
 
   DCHECK(!IsLeafMethod());
@@ -4122,5 +4365,8 @@
   LOG(FATAL) << "Unreachable";
 }
 
+#undef __
+#undef QUICK_ENTRY_POINT
+
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 2fe464d..1d10293 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -87,7 +87,8 @@
   virtual ~InvokeDexCallingConventionVisitorARM() {}
 
   Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type);
+  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetMethodLocation() const OVERRIDE;
 
  private:
   InvokeDexCallingConvention calling_convention;
@@ -137,12 +138,18 @@
       : HGraphVisitor(graph), codegen_(codegen) {}
 
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
-  void Visit##name(H##name* instr);
+  void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
  private:
   void HandleInvoke(HInvoke* invoke);
   void HandleBitwiseOperation(HBinaryOperation* operation);
@@ -161,12 +168,18 @@
   InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
 
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
-  void Visit##name(H##name* instr);
+  void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
   ArmAssembler* GetAssembler() const { return assembler_; }
 
  private:
@@ -184,7 +197,9 @@
                                HInstruction* instruction);
   void GenerateWideAtomicLoad(Register addr, uint32_t offset,
                               Register out_lo, Register out_hi);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   void GenerateImplicitNullCheck(HNullCheck* instruction);
   void GenerateExplicitNullCheck(HNullCheck* instruction);
@@ -192,6 +207,11 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void DivRemOneOrMinusOne(HBinaryOperation* instruction);
+  void DivRemByPowerOfTwo(HBinaryOperation* instruction);
+  void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
+  void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
+  void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   ArmAssembler* const assembler_;
   CodeGeneratorARM* const codegen_;
@@ -236,6 +256,10 @@
     return &assembler_;
   }
 
+  const ArmAssembler& GetAssembler() const OVERRIDE {
+    return assembler_;
+  }
+
   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
     return GetLabelOf(block)->Position();
   }
@@ -265,15 +289,12 @@
   // Helper method to move a 64bits value between two locations.
   void Move64(Location destination, Location source);
 
-  // Load current method into `reg`.
-  void LoadCurrentMethod(Register reg);
-
   // Generate code to invoke a runtime entry point.
   void InvokeRuntime(
       int32_t offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path);
 
   // Emit a write barrier.
-  void MarkGCCard(Register temp, Register card, Register object, Register value);
+  void MarkGCCard(Register temp, Register card, Register object, Register value, bool can_be_null);
 
   Label* GetLabelOf(HBasicBlock* block) const {
     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
@@ -283,6 +304,8 @@
     block_labels_.SetSize(GetGraph()->GetBlocks().Size());
   }
 
+  void Finalize(CodeAllocator* allocator) OVERRIDE;
+
   const ArmInstructionSetFeatures& GetInstructionSetFeatures() const {
     return isa_features_;
   }
@@ -295,7 +318,7 @@
 
   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
 
-  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp);
+  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
 
  private:
   // Labels for each block that will be compiled.
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 55ef66f..f64e801 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -18,6 +18,7 @@
 
 #include "arch/arm64/instruction_set_features_arm64.h"
 #include "art_method.h"
+#include "code_generator_utils.h"
 #include "common_arm64.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
@@ -64,6 +65,7 @@
 using helpers::WRegisterFrom;
 using helpers::XRegisterFrom;
 using helpers::ARM64EncodableConstantOrRegister;
+using helpers::ArtVixlRegCodeCoherentForRegSet;
 
 static constexpr int kCurrentMethodStackOffset = 0;
 
@@ -82,7 +84,6 @@
 }
 
 Location ARM64ReturnLocation(Primitive::Type return_type) {
-  DCHECK_NE(return_type, Primitive::kPrimVoid);
   // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the
   // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`,
   // but we use the exact registers for clarity.
@@ -92,6 +93,8 @@
     return LocationFrom(d0);
   } else if (return_type == Primitive::kPrimLong) {
     return LocationFrom(x0);
+  } else if (return_type == Primitive::kPrimVoid) {
+    return Location::NoLocation();
   } else {
     return LocationFrom(w0);
   }
@@ -104,6 +107,88 @@
 #define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()->
 #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value()
 
+// Calculate memory accessing operand for save/restore live registers.
+static void SaveRestoreLiveRegistersHelper(CodeGenerator* codegen,
+                                           RegisterSet* register_set,
+                                           int64_t spill_offset,
+                                           bool is_save) {
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(register_set->GetCoreRegisters(),
+                                         codegen->GetNumberOfCoreRegisters(),
+                                         register_set->GetFloatingPointRegisters(),
+                                         codegen->GetNumberOfFloatingPointRegisters()));
+
+  CPURegList core_list = CPURegList(CPURegister::kRegister, kXRegSize,
+      register_set->GetCoreRegisters() & (~callee_saved_core_registers.list()));
+  CPURegList fp_list = CPURegList(CPURegister::kFPRegister, kDRegSize,
+      register_set->GetFloatingPointRegisters() & (~callee_saved_fp_registers.list()));
+
+  MacroAssembler* masm = down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler();
+  UseScratchRegisterScope temps(masm);
+
+  Register base = masm->StackPointer();
+  int64_t core_spill_size = core_list.TotalSizeInBytes();
+  int64_t fp_spill_size = fp_list.TotalSizeInBytes();
+  int64_t reg_size = kXRegSizeInBytes;
+  int64_t max_ls_pair_offset = spill_offset + core_spill_size + fp_spill_size - 2 * reg_size;
+  uint32_t ls_access_size = WhichPowerOf2(reg_size);
+  if (((core_list.Count() > 1) || (fp_list.Count() > 1)) &&
+      !masm->IsImmLSPair(max_ls_pair_offset, ls_access_size)) {
+    // If the offset does not fit in the instruction's immediate field, use an alternate register
+    // to compute the base address(float point registers spill base address).
+    Register new_base = temps.AcquireSameSizeAs(base);
+    __ Add(new_base, base, Operand(spill_offset + core_spill_size));
+    base = new_base;
+    spill_offset = -core_spill_size;
+    int64_t new_max_ls_pair_offset = fp_spill_size - 2 * reg_size;
+    DCHECK(masm->IsImmLSPair(spill_offset, ls_access_size));
+    DCHECK(masm->IsImmLSPair(new_max_ls_pair_offset, ls_access_size));
+  }
+
+  if (is_save) {
+    __ StoreCPURegList(core_list, MemOperand(base, spill_offset));
+    __ StoreCPURegList(fp_list, MemOperand(base, spill_offset + core_spill_size));
+  } else {
+    __ LoadCPURegList(core_list, MemOperand(base, spill_offset));
+    __ LoadCPURegList(fp_list, MemOperand(base, spill_offset + core_spill_size));
+  }
+}
+
+void SlowPathCodeARM64::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
+  RegisterSet* register_set = locations->GetLiveRegisters();
+  size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
+  for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
+    if (!codegen->IsCoreCalleeSaveRegister(i) && register_set->ContainsCoreRegister(i)) {
+      // If the register holds an object, update the stack mask.
+      if (locations->RegisterContainsObject(i)) {
+        locations->SetStackBit(stack_offset / kVRegSize);
+      }
+      DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+      DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+      saved_core_stack_offsets_[i] = stack_offset;
+      stack_offset += kXRegSizeInBytes;
+    }
+  }
+
+  for (size_t i = 0, e = codegen->GetNumberOfFloatingPointRegisters(); i < e; ++i) {
+    if (!codegen->IsFloatingPointCalleeSaveRegister(i) &&
+        register_set->ContainsFloatingPointRegister(i)) {
+      DCHECK_LT(stack_offset, codegen->GetFrameSize() - codegen->FrameEntrySpillSize());
+      DCHECK_LT(i, kMaximumNumberOfExpectedRegisters);
+      saved_fpu_stack_offsets_[i] = stack_offset;
+      stack_offset += kDRegSizeInBytes;
+    }
+  }
+
+  SaveRestoreLiveRegistersHelper(codegen, register_set,
+                                 codegen->GetFirstRegisterSlotInSlowPath(), true /* is_save */);
+}
+
+void SlowPathCodeARM64::RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
+  RegisterSet* register_set = locations->GetLiveRegisters();
+  SaveRestoreLiveRegistersHelper(codegen, register_set,
+                                 codegen->GetFirstRegisterSlotInSlowPath(), false /* is_save */);
+}
+
 class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 {
  public:
   BoundsCheckSlowPathARM64(HBoundsCheck* instruction,
@@ -128,6 +213,8 @@
     CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
   }
 
+  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathARM64"; }
+
  private:
   HBoundsCheck* const instruction_;
   const Location index_location_;
@@ -148,6 +235,8 @@
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathARM64"; }
+
  private:
   HDivZeroCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64);
@@ -193,6 +282,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathARM64"; }
+
  private:
   // The class this slow path will load.
   HLoadClass* const cls_;
@@ -234,6 +325,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM64"; }
+
  private:
   HLoadString* const instruction_;
 
@@ -252,6 +345,8 @@
     CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
   }
 
+  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathARM64"; }
+
  private:
   HNullCheck* const instruction_;
 
@@ -288,6 +383,8 @@
     return successor_;
   }
 
+  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathARM64"; }
+
  private:
   HSuspendCheck* const instruction_;
   // If not null, the block to branch to after the suspend check.
@@ -344,6 +441,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM64"; }
+
  private:
   HInstruction* const instruction_;
   const Location class_to_check_;
@@ -368,6 +467,8 @@
     arm64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathARM64"; }
+
  private:
   HInstruction* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM64);
@@ -398,6 +499,10 @@
   return next_location;
 }
 
+Location InvokeDexCallingConventionVisitorARM64::GetMethodLocation() const {
+  return LocationFrom(kArtMethodRegister);
+}
+
 CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph,
                                        const Arm64InstructionSetFeatures& isa_features,
                                        const CompilerOptions& compiler_options)
@@ -528,6 +633,19 @@
   GetAssembler()->cfi().DefCFAOffset(GetFrameSize());
 }
 
+vixl::CPURegList CodeGeneratorARM64::GetFramePreservedCoreRegisters() const {
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(core_spill_mask_, GetNumberOfCoreRegisters(), 0, 0));
+  return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
+                          core_spill_mask_);
+}
+
+vixl::CPURegList CodeGeneratorARM64::GetFramePreservedFPRegisters() const {
+  DCHECK(ArtVixlRegCodeCoherentForRegSet(0, 0, fpu_spill_mask_,
+                                         GetNumberOfFloatingPointRegisters()));
+  return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
+                          fpu_spill_mask_);
+}
+
 void CodeGeneratorARM64::Bind(HBasicBlock* block) {
   __ Bind(GetLabelOf(block));
 }
@@ -536,16 +654,16 @@
                               Location location,
                               HInstruction* move_for) {
   LocationSummary* locations = instruction->GetLocations();
-  if (locations != nullptr && locations->Out().Equals(location)) {
-    return;
-  }
-
   Primitive::Type type = instruction->GetType();
   DCHECK_NE(type, Primitive::kPrimVoid);
 
-  if (instruction->IsIntConstant()
-      || instruction->IsLongConstant()
-      || instruction->IsNullConstant()) {
+  if (instruction->IsCurrentMethod()) {
+    MoveLocation(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
+  } else if (locations != nullptr && locations->Out().Equals(location)) {
+    return;
+  } else if (instruction->IsIntConstant()
+             || instruction->IsLongConstant()
+             || instruction->IsNullConstant()) {
     int64_t value = GetInt64ValueOf(instruction->AsConstant());
     if (location.IsRegister()) {
       Register dst = RegisterFrom(location, type);
@@ -603,16 +721,20 @@
   return Location::NoLocation();
 }
 
-void CodeGeneratorARM64::MarkGCCard(Register object, Register value) {
+void CodeGeneratorARM64::MarkGCCard(Register object, Register value, bool value_can_be_null) {
   UseScratchRegisterScope temps(GetVIXLAssembler());
   Register card = temps.AcquireX();
   Register temp = temps.AcquireW();   // Index within the CardTable - 32bit.
   vixl::Label done;
-  __ Cbz(value, &done);
+  if (value_can_be_null) {
+    __ Cbz(value, &done);
+  }
   __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value()));
   __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
   __ Strb(card, MemOperand(card, temp.X()));
-  __ Bind(&done);
+  if (value_can_be_null) {
+    __ Bind(&done);
+  }
 }
 
 void CodeGeneratorARM64::SetupBlockedRegisters(bool is_baseline) const {
@@ -690,11 +812,11 @@
 }
 
 void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << Arm64ManagedRegister::FromXRegister(XRegister(reg));
+  stream << XRegister(reg);
 }
 
 void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << Arm64ManagedRegister::FromDRegister(DRegister(reg));
+  stream << DRegister(reg);
 }
 
 void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
@@ -965,12 +1087,6 @@
   }
 }
 
-void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) {
-  DCHECK(RequiresCurrentMethod());
-  CHECK(current_method.IsX());
-  __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset));
-}
-
 void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset,
                                        HInstruction* instruction,
                                        uint32_t dex_pc,
@@ -978,14 +1094,12 @@
   BlockPoolsScope block_pools(GetVIXLAssembler());
   __ Ldr(lr, MemOperand(tr, entry_point_offset));
   __ Blr(lr);
-  if (instruction != nullptr) {
-    RecordPcInfo(instruction, dex_pc, slow_path);
-    DCHECK(instruction->IsSuspendCheck()
-        || instruction->IsBoundsCheck()
-        || instruction->IsNullCheck()
-        || instruction->IsDivZeroCheck()
-        || !IsLeafMethod());
-    }
+  RecordPcInfo(instruction, dex_pc, slow_path);
+  DCHECK(instruction->IsSuspendCheck()
+         || instruction->IsBoundsCheck()
+         || instruction->IsNullCheck()
+         || instruction->IsDivZeroCheck()
+         || !IsLeafMethod());
 }
 
 void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path,
@@ -1136,6 +1250,7 @@
 void InstructionCodeGeneratorARM64::HandleFieldGet(HInstruction* instruction,
                                                    const FieldInfo& field_info) {
   DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
+  Primitive::Type field_type = field_info.GetFieldType();
   BlockPoolsScope block_pools(GetVIXLAssembler());
 
   MemOperand field = HeapOperand(InputRegisterAt(instruction, 0), field_info.GetFieldOffset());
@@ -1146,15 +1261,19 @@
       // NB: LoadAcquire will record the pc info if needed.
       codegen_->LoadAcquire(instruction, OutputCPURegister(instruction), field);
     } else {
-      codegen_->Load(field_info.GetFieldType(), OutputCPURegister(instruction), field);
+      codegen_->Load(field_type, OutputCPURegister(instruction), field);
       codegen_->MaybeRecordImplicitNullCheck(instruction);
       // For IRIW sequential consistency kLoadAny is not sufficient.
       GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
     }
   } else {
-    codegen_->Load(field_info.GetFieldType(), OutputCPURegister(instruction), field);
+    codegen_->Load(field_type, OutputCPURegister(instruction), field);
     codegen_->MaybeRecordImplicitNullCheck(instruction);
   }
+
+  if (field_type == Primitive::kPrimNot) {
+    GetAssembler()->MaybeUnpoisonHeapReference(OutputCPURegister(instruction).W());
+  }
 }
 
 void LocationsBuilderARM64::HandleFieldSet(HInstruction* instruction) {
@@ -1169,33 +1288,49 @@
 }
 
 void InstructionCodeGeneratorARM64::HandleFieldSet(HInstruction* instruction,
-                                                   const FieldInfo& field_info) {
+                                                   const FieldInfo& field_info,
+                                                   bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
   BlockPoolsScope block_pools(GetVIXLAssembler());
 
   Register obj = InputRegisterAt(instruction, 0);
   CPURegister value = InputCPURegisterAt(instruction, 1);
+  CPURegister source = value;
   Offset offset = field_info.GetFieldOffset();
   Primitive::Type field_type = field_info.GetFieldType();
   bool use_acquire_release = codegen_->GetInstructionSetFeatures().PreferAcquireRelease();
 
-  if (field_info.IsVolatile()) {
-    if (use_acquire_release) {
-      codegen_->StoreRelease(field_type, value, HeapOperand(obj, offset));
-      codegen_->MaybeRecordImplicitNullCheck(instruction);
-    } else {
-      GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
-      codegen_->Store(field_type, value, HeapOperand(obj, offset));
-      codegen_->MaybeRecordImplicitNullCheck(instruction);
-      GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+  {
+    // We use a block to end the scratch scope before the write barrier, thus
+    // freeing the temporary registers so they can be used in `MarkGCCard`.
+    UseScratchRegisterScope temps(GetVIXLAssembler());
+
+    if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
+      DCHECK(value.IsW());
+      Register temp = temps.AcquireW();
+      __ Mov(temp, value.W());
+      GetAssembler()->PoisonHeapReference(temp.W());
+      source = temp;
     }
-  } else {
-    codegen_->Store(field_type, value, HeapOperand(obj, offset));
-    codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+    if (field_info.IsVolatile()) {
+      if (use_acquire_release) {
+        codegen_->StoreRelease(field_type, source, HeapOperand(obj, offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+      } else {
+        GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
+        codegen_->Store(field_type, source, HeapOperand(obj, offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
+      }
+    } else {
+      codegen_->Store(field_type, source, HeapOperand(obj, offset));
+      codegen_->MaybeRecordImplicitNullCheck(instruction);
+    }
   }
 
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
-    codegen_->MarkGCCard(obj, Register(value));
+    codegen_->MarkGCCard(obj, Register(value), value_can_be_null);
   }
 }
 
@@ -1342,13 +1477,16 @@
     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);
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+  if (type == Primitive::kPrimNot) {
+    GetAssembler()->MaybeUnpoisonHeapReference(OutputCPURegister(instruction).W());
+  }
 }
 
 void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) {
@@ -1391,12 +1529,15 @@
   bool needs_runtime_call = locations->WillCall();
 
   if (needs_runtime_call) {
+    // Note: if heap poisoning is enabled, pAputObject takes cares
+    // of poisoning the reference.
     codegen_->InvokeRuntime(
         QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc(), nullptr);
     CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
   } else {
     Register obj = InputRegisterAt(instruction, 0);
     CPURegister value = InputCPURegisterAt(instruction, 2);
+    CPURegister source = value;
     Location index = locations->InAt(1);
     size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value();
     MemOperand destination = HeapOperand(obj);
@@ -1407,21 +1548,31 @@
       // freeing the temporary registers so they can be used in `MarkGCCard`.
       UseScratchRegisterScope temps(masm);
 
+      if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
+        DCHECK(value.IsW());
+        Register temp = temps.AcquireW();
+        __ Mov(temp, value.W());
+        GetAssembler()->PoisonHeapReference(temp.W());
+        source = temp;
+      }
+
       if (index.IsConstant()) {
         offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type);
         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, value, destination);
+      codegen_->Store(value_type, source, destination);
       codegen_->MaybeRecordImplicitNullCheck(instruction);
     }
     if (CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue())) {
-      codegen_->MarkGCCard(obj, value.W());
+      codegen_->MarkGCCard(obj, value.W(), instruction->GetValueCanBeNull());
     }
   }
 }
@@ -1470,7 +1621,10 @@
   }
   // Compare the class of `obj` with `cls`.
   __ Ldr(obj_cls, HeapOperand(obj, mirror::Object::ClassOffset()));
+  GetAssembler()->MaybeUnpoisonHeapReference(obj_cls.W());
   __ Cmp(obj_cls, cls);
+  // The checkcast succeeds if the classes are equal (fast path).
+  // Otherwise, we need to go into the slow path to check the types.
   __ B(ne, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
@@ -1604,6 +1758,152 @@
 #undef DEFINE_CONDITION_VISITORS
 #undef FOR_EACH_CONDITION_INSTRUCTION
 
+void InstructionCodeGeneratorARM64::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = OutputRegister(instruction);
+  Register dividend = InputRegisterAt(instruction, 0);
+  int64_t imm = Int64FromConstant(second.GetConstant());
+  DCHECK(imm == 1 || imm == -1);
+
+  if (instruction->IsRem()) {
+    __ Mov(out, 0);
+  } else {
+    if (imm == 1) {
+      __ Mov(out, dividend);
+    } else {
+      __ Neg(out, dividend);
+    }
+  }
+}
+
+void InstructionCodeGeneratorARM64::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = OutputRegister(instruction);
+  Register dividend = InputRegisterAt(instruction, 0);
+  int64_t imm = Int64FromConstant(second.GetConstant());
+  uint64_t abs_imm = static_cast<uint64_t>(std::abs(imm));
+  DCHECK(IsPowerOfTwo(abs_imm));
+  int ctz_imm = CTZ(abs_imm);
+
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp = temps.AcquireSameSizeAs(out);
+
+  if (instruction->IsDiv()) {
+    __ Add(temp, dividend, abs_imm - 1);
+    __ Cmp(dividend, 0);
+    __ Csel(out, temp, dividend, lt);
+    if (imm > 0) {
+      __ Asr(out, out, ctz_imm);
+    } else {
+      __ Neg(out, Operand(out, ASR, ctz_imm));
+    }
+  } else {
+    int bits = instruction->GetResultType() == Primitive::kPrimInt ? 32 : 64;
+    __ Asr(temp, dividend, bits - 1);
+    __ Lsr(temp, temp, bits - ctz_imm);
+    __ Add(out, dividend, temp);
+    __ And(out, out, abs_imm - 1);
+    __ Sub(out, out, temp);
+  }
+}
+
+void InstructionCodeGeneratorARM64::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+
+  LocationSummary* locations = instruction->GetLocations();
+  Location second = locations->InAt(1);
+  DCHECK(second.IsConstant());
+
+  Register out = OutputRegister(instruction);
+  Register dividend = InputRegisterAt(instruction, 0);
+  int64_t imm = Int64FromConstant(second.GetConstant());
+
+  Primitive::Type type = instruction->GetResultType();
+  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+  int64_t magic;
+  int shift;
+  CalculateMagicAndShiftForDivRem(imm, type == Primitive::kPrimLong /* is_long */, &magic, &shift);
+
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  Register temp = temps.AcquireSameSizeAs(out);
+
+  // temp = get_high(dividend * magic)
+  __ Mov(temp, magic);
+  if (type == Primitive::kPrimLong) {
+    __ Smulh(temp, dividend, temp);
+  } else {
+    __ Smull(temp.X(), dividend, temp);
+    __ Lsr(temp.X(), temp.X(), 32);
+  }
+
+  if (imm > 0 && magic < 0) {
+    __ Add(temp, temp, dividend);
+  } else if (imm < 0 && magic > 0) {
+    __ Sub(temp, temp, dividend);
+  }
+
+  if (shift != 0) {
+    __ Asr(temp, temp, shift);
+  }
+
+  if (instruction->IsDiv()) {
+    __ Sub(out, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+  } else {
+    __ Sub(temp, temp, Operand(temp, ASR, type == Primitive::kPrimLong ? 63 : 31));
+    // TODO: Strength reduction for msub.
+    Register temp_imm = temps.AcquireSameSizeAs(out);
+    __ Mov(temp_imm, imm);
+    __ Msub(out, temp, temp_imm, dividend);
+  }
+}
+
+void InstructionCodeGeneratorARM64::GenerateDivRemIntegral(HBinaryOperation* instruction) {
+  DCHECK(instruction->IsDiv() || instruction->IsRem());
+  Primitive::Type type = instruction->GetResultType();
+  DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong);
+
+  LocationSummary* locations = instruction->GetLocations();
+  Register out = OutputRegister(instruction);
+  Location second = locations->InAt(1);
+
+  if (second.IsConstant()) {
+    int64_t imm = Int64FromConstant(second.GetConstant());
+
+    if (imm == 0) {
+      // Do not generate anything. DivZeroCheck would prevent any code to be executed.
+    } else if (imm == 1 || imm == -1) {
+      DivRemOneOrMinusOne(instruction);
+    } else if (IsPowerOfTwo(std::abs(imm))) {
+      DivRemByPowerOfTwo(instruction);
+    } else {
+      DCHECK(imm <= -2 || imm >= 2);
+      GenerateDivRemWithAnyConstant(instruction);
+    }
+  } else {
+    Register dividend = InputRegisterAt(instruction, 0);
+    Register divisor = InputRegisterAt(instruction, 1);
+    if (instruction->IsDiv()) {
+      __ Sdiv(out, dividend, divisor);
+    } else {
+      UseScratchRegisterScope temps(GetVIXLAssembler());
+      Register temp = temps.AcquireSameSizeAs(out);
+      __ Sdiv(temp, dividend, divisor);
+      __ Msub(out, temp, divisor, dividend);
+    }
+  }
+}
+
 void LocationsBuilderARM64::VisitDiv(HDiv* div) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
@@ -1611,7 +1911,7 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
@@ -1632,7 +1932,7 @@
   switch (type) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
-      __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1));
+      GenerateDivRemIntegral(div);
       break;
 
     case Primitive::kPrimFloat:
@@ -1710,12 +2010,7 @@
   // Will be generated at use site.
 }
 
-void LocationsBuilderARM64::VisitGoto(HGoto* got) {
-  got->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
-  HBasicBlock* successor = got->GetSuccessor();
+void InstructionCodeGeneratorARM64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
   DCHECK(!successor->IsExitBlock());
   HBasicBlock* block = got->GetBlock();
   HInstruction* previous = got->GetPrevious();
@@ -1734,6 +2029,25 @@
   }
 }
 
+void LocationsBuilderARM64::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) {
+  HandleGoto(got, got->GetSuccessor());
+}
+
+void LocationsBuilderARM64::VisitTryBoundary(HTryBoundary* try_boundary) {
+  try_boundary->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorARM64::VisitTryBoundary(HTryBoundary* try_boundary) {
+  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
+  if (!successor->IsExitBlock()) {
+    HandleGoto(try_boundary, successor);
+  }
+}
+
 void InstructionCodeGeneratorARM64::GenerateTestAndBranch(HInstruction* instruction,
                                                           vixl::Label* true_target,
                                                           vixl::Label* false_target,
@@ -1847,7 +2161,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) {
@@ -1877,6 +2191,7 @@
 
   // Compare the class of `obj` with `cls`.
   __ Ldr(out, HeapOperand(obj, mirror::Object::ClassOffset()));
+  GetAssembler()->MaybeUnpoisonHeapReference(out.W());
   __ Cmp(out, cls);
   if (instruction->IsClassFinal()) {
     // Classes must be equal for the instanceof to succeed.
@@ -1917,20 +2232,8 @@
 }
 
 void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(LocationFrom(x0));
-
   InvokeDexCallingConventionVisitorARM64 calling_convention_visitor;
-  for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
-    HInstruction* input = invoke->InputAt(i);
-    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
-  }
-
-  Primitive::Type return_type = invoke->GetType();
-  if (return_type != Primitive::kPrimVoid) {
-    locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
-  }
+  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
 }
 
 void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) {
@@ -1962,6 +2265,7 @@
     __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
   }
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
   // temp = temp->GetImtEntryAt(method_offset);
   __ Ldr(temp, MemOperand(temp, method_offset));
   // lr = temp->GetEntryPoint();
@@ -2003,9 +2307,8 @@
   return false;
 }
 
-void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) {
+void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
   // Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
-  DCHECK(temp.Is(kArtMethodRegister));
   size_t index_in_cache = GetCachePointerOffset(invoke->GetDexMethodIndex());
 
   // TODO: Implement all kinds of calls:
@@ -2016,30 +2319,39 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   if (invoke->IsStringInit()) {
+    Register reg = XRegisterFrom(temp);
     // temp = thread->string_init_entrypoint
-    __ Ldr(temp.X(), MemOperand(tr, invoke->GetStringInitOffset()));
+    __ Ldr(reg.X(), MemOperand(tr, invoke->GetStringInitOffset()));
     // LR = temp->entry_point_from_quick_compiled_code_;
     __ Ldr(lr, MemOperand(
-        temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize).Int32Value()));
+        reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize).Int32Value()));
     // lr()
     __ Blr(lr);
+  } else if (invoke->IsRecursive()) {
+    __ Bl(&frame_entry_label_);
   } else {
-    // temp = method;
-    LoadCurrentMethod(temp.X());
-    if (!invoke->IsRecursive()) {
-      // temp = temp->dex_cache_resolved_methods_;
-      __ Ldr(temp.W(), MemOperand(temp.X(),
-                                  ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
-      // temp = temp[index_in_cache];
-      __ Ldr(temp.X(), MemOperand(temp, index_in_cache));
-      // lr = temp->entry_point_from_quick_compiled_code_;
-      __ Ldr(lr, MemOperand(temp.X(), ArtMethod::EntryPointFromQuickCompiledCodeOffset(
-          kArm64WordSize).Int32Value()));
-      // lr();
-      __ Blr(lr);
+    Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
+    Register reg = XRegisterFrom(temp);
+    Register method_reg;
+    if (current_method.IsRegister()) {
+      method_reg = XRegisterFrom(current_method);
     } else {
-      __ Bl(&frame_entry_label_);
+      DCHECK(invoke->GetLocations()->Intrinsified());
+      DCHECK(!current_method.IsValid());
+      method_reg = reg;
+      __ Ldr(reg.X(), MemOperand(sp, kCurrentMethodStackOffset));
     }
+
+    // temp = current_method->dex_cache_resolved_methods_;
+    __ Ldr(reg.W(), MemOperand(method_reg.X(),
+                               ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
+    // temp = temp[index_in_cache];
+    __ Ldr(reg.X(), MemOperand(reg, index_in_cache));
+    // lr = temp->entry_point_from_quick_compiled_code_;
+    __ Ldr(lr, MemOperand(reg.X(), ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+        kArm64WordSize).Int32Value()));
+    // lr();
+    __ Blr(lr);
   }
 
   DCHECK(!IsLeafMethod());
@@ -2055,8 +2367,9 @@
   }
 
   BlockPoolsScope block_pools(GetVIXLAssembler());
-  Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
-  codegen_->GenerateStaticOrDirectCall(invoke, temp);
+  LocationSummary* locations = invoke->GetLocations();
+  codegen_->GenerateStaticOrDirectCall(
+      invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
@@ -2075,15 +2388,10 @@
 
   BlockPoolsScope block_pools(GetVIXLAssembler());
 
-  // temp = object->GetClass();
-  if (receiver.IsStackSlot()) {
-    __ Ldr(temp.W(), MemOperand(sp, receiver.GetStackIndex()));
-    __ Ldr(temp.W(), HeapOperand(temp.W(), class_offset));
-  } else {
-    DCHECK(receiver.IsRegister());
-    __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
-  }
+  DCHECK(receiver.IsRegister());
+  __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
   // temp = temp->GetMethodAt(method_offset);
   __ Ldr(temp, MemOperand(temp, method_offset));
   // lr = temp->GetEntryPoint();
@@ -2098,21 +2406,22 @@
   LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
                                                               : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
   Register out = OutputRegister(cls);
+  Register current_method = InputRegisterAt(cls, 0);
   if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
-    codegen_->LoadCurrentMethod(out.X());
-    __ Ldr(out, MemOperand(out.X(), ArtMethod::DeclaringClassOffset().Int32Value()));
+    __ Ldr(out, MemOperand(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
   } else {
     DCHECK(cls->CanCallRuntime());
-    codegen_->LoadCurrentMethod(out.X());
-    __ Ldr(out, MemOperand(out.X(), ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
+    __ Ldr(out, MemOperand(current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
     __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+    GetAssembler()->MaybeUnpoisonHeapReference(out.W());
 
     SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64(
         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
@@ -2150,6 +2459,7 @@
 void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -2158,10 +2468,12 @@
   codegen_->AddSlowPath(slow_path);
 
   Register out = OutputRegister(load);
-  codegen_->LoadCurrentMethod(out.X());
-  __ Ldr(out, MemOperand(out.X(), ArtMethod::DeclaringClassOffset().Int32Value()));
+  Register current_method = InputRegisterAt(load, 0);
+  __ Ldr(out, MemOperand(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
   __ Ldr(out, HeapOperand(out, mirror::Class::DexCacheStringsOffset()));
+  GetAssembler()->MaybeUnpoisonHeapReference(out.W());
   __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  GetAssembler()->MaybeUnpoisonHeapReference(out.W());
   __ Cbz(out, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
@@ -2283,9 +2595,9 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(2)));
   locations->SetOut(LocationFrom(x0));
   locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(2)));
   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
                        void*, uint32_t, int32_t, ArtMethod*>();
 }
@@ -2295,10 +2607,9 @@
   InvokeRuntimeCallingConvention calling_convention;
   Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
   DCHECK(type_index.Is(w0));
-  Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimLong);
-  DCHECK(current_method.Is(x2));
-  codegen_->LoadCurrentMethod(current_method.X());
   __ Mov(type_index, instruction->GetTypeIndex());
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   codegen_->InvokeRuntime(
       GetThreadOffset<kArm64WordSize>(instruction->GetEntrypoint()).Int32Value(),
       instruction,
@@ -2312,7 +2623,7 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(1)));
   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
   CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
 }
@@ -2321,10 +2632,9 @@
   LocationSummary* locations = instruction->GetLocations();
   Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
   DCHECK(type_index.Is(w0));
-  Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot);
-  DCHECK(current_method.Is(w1));
-  codegen_->LoadCurrentMethod(current_method.X());
   __ Mov(type_index, instruction->GetTypeIndex());
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   codegen_->InvokeRuntime(
       GetThreadOffset<kArm64WordSize>(instruction->GetEntrypoint()).Int32Value(),
       instruction,
@@ -2426,9 +2736,20 @@
   locations->SetOut(location);
 }
 
-void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) {
+void InstructionCodeGeneratorARM64::VisitParameterValue(
+    HParameterValue* instruction ATTRIBUTE_UNUSED) {
   // Nothing to do, the parameter is already at its location.
-  UNUSED(instruction);
+}
+
+void LocationsBuilderARM64::VisitCurrentMethod(HCurrentMethod* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(LocationFrom(kArtMethodRegister));
+}
+
+void InstructionCodeGeneratorARM64::VisitCurrentMethod(
+    HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
+  // Nothing to do, the method is already at its location.
 }
 
 void LocationsBuilderARM64::VisitPhi(HPhi* instruction) {
@@ -2454,7 +2775,7 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
       locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
       break;
 
@@ -2479,14 +2800,7 @@
   switch (type) {
     case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
-      UseScratchRegisterScope temps(GetVIXLAssembler());
-      Register dividend = InputRegisterAt(rem, 0);
-      Register divisor = InputRegisterAt(rem, 1);
-      Register output = OutputRegister(rem);
-      Register temp = temps.AcquireSameSizeAs(output);
-
-      __ Sdiv(temp, dividend, divisor);
-      __ Msub(output, temp, divisor, dividend);
+      GenerateDivRemIntegral(rem);
       break;
     }
 
@@ -2596,7 +2910,7 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 3486cde..2c61038 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -44,7 +44,7 @@
 };
 static constexpr size_t kParameterFPRegistersLength = arraysize(kParameterFPRegisters);
 
-const vixl::Register tr = vixl::x18;                        // Thread Register
+const vixl::Register tr = vixl::x19;                        // Thread Register
 static const vixl::Register kArtMethodRegister = vixl::x0;  // Method register on invoke.
 
 const vixl::CPURegList vixl_reserved_core_registers(vixl::ip0, vixl::ip1);
@@ -52,10 +52,10 @@
 
 const vixl::CPURegList runtime_reserved_core_registers(tr, vixl::lr);
 
-// Callee-saved registers defined by AAPCS64.
+// Callee-saved registers AAPCS64 (without x19 - Thread Register)
 const vixl::CPURegList callee_saved_core_registers(vixl::CPURegister::kRegister,
                                                    vixl::kXRegSize,
-                                                   vixl::x19.code(),
+                                                   vixl::x20.code(),
                                                    vixl::x30.code());
 const vixl::CPURegList callee_saved_fp_registers(vixl::CPURegister::kFPRegister,
                                                  vixl::kDRegSize,
@@ -70,6 +70,9 @@
   vixl::Label* GetEntryLabel() { return &entry_label_; }
   vixl::Label* GetExitLabel() { return &exit_label_; }
 
+  void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
+  void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE;
+
  private:
   vixl::Label entry_label_;
   vixl::Label exit_label_;
@@ -112,7 +115,7 @@
                           kParameterFPRegistersLength,
                           kArm64PointerSize) {}
 
-  Location GetReturnLocation(Primitive::Type return_type) {
+  Location GetReturnLocation(Primitive::Type return_type) const {
     return ARM64ReturnLocation(return_type);
   }
 
@@ -127,9 +130,10 @@
   virtual ~InvokeDexCallingConventionVisitorARM64() {}
 
   Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type return_type) {
+  Location GetReturnLocation(Primitive::Type return_type) const OVERRIDE {
     return calling_convention.GetReturnLocation(return_type);
   }
+  Location GetMethodLocation() const OVERRIDE;
 
  private:
   InvokeDexCallingConvention calling_convention;
@@ -143,10 +147,16 @@
 
 #define DECLARE_VISIT_INSTRUCTION(name, super) \
   void Visit##name(H##name* instr) OVERRIDE;
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)
+
 #undef DECLARE_VISIT_INSTRUCTION
 
-  void LoadCurrentMethod(XRegister reg);
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
 
   Arm64Assembler* GetAssembler() const { return assembler_; }
   vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
@@ -156,7 +166,9 @@
   void GenerateMemoryBarrier(MemBarrierKind kind);
   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
   void HandleBinaryOp(HBinaryOperation* instr);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   void HandleShift(HBinaryOperation* instr);
   void GenerateImplicitNullCheck(HNullCheck* instruction);
@@ -165,6 +177,11 @@
                              vixl::Label* true_target,
                              vixl::Label* false_target,
                              vixl::Label* always_true_target);
+  void DivRemOneOrMinusOne(HBinaryOperation* instruction);
+  void DivRemByPowerOfTwo(HBinaryOperation* instruction);
+  void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
+  void GenerateDivRemIntegral(HBinaryOperation* instruction);
+  void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   Arm64Assembler* const assembler_;
   CodeGeneratorARM64* const codegen_;
@@ -179,9 +196,17 @@
 
 #define DECLARE_VISIT_INSTRUCTION(name, super) \
   void Visit##name(H##name* instr) OVERRIDE;
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION)
+
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
  private:
   void HandleBinaryOp(HBinaryOperation* instr);
   void HandleFieldSet(HInstruction* instruction);
@@ -229,15 +254,8 @@
   void GenerateFrameEntry() OVERRIDE;
   void GenerateFrameExit() OVERRIDE;
 
-  vixl::CPURegList GetFramePreservedCoreRegisters() const {
-    return vixl::CPURegList(vixl::CPURegister::kRegister, vixl::kXRegSize,
-                            core_spill_mask_);
-  }
-
-  vixl::CPURegList GetFramePreservedFPRegisters() const {
-    return vixl::CPURegList(vixl::CPURegister::kFPRegister, vixl::kDRegSize,
-                            fpu_spill_mask_);
-  }
+  vixl::CPURegList GetFramePreservedCoreRegisters() const;
+  vixl::CPURegList GetFramePreservedFPRegisters() const;
 
   void Bind(HBasicBlock* block) OVERRIDE;
 
@@ -265,10 +283,11 @@
   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
   Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+  const Arm64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
   vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; }
 
   // Emit a write barrier.
-  void MarkGCCard(vixl::Register object, vixl::Register value);
+  void MarkGCCard(vixl::Register object, vixl::Register value, bool value_can_be_null);
 
   // Register allocation.
 
@@ -279,10 +298,10 @@
 
   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
 
-  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
   // The number of registers that can be allocated. The register allocator may
   // decide to reserve and not use a few of them.
@@ -324,7 +343,6 @@
                     Primitive::Type type = Primitive::kPrimVoid);
   void Load(Primitive::Type type, vixl::CPURegister dst, const vixl::MemOperand& src);
   void Store(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
-  void LoadCurrentMethod(vixl::Register current_method);
   void LoadAcquire(HInstruction* instruction, vixl::CPURegister dst, const vixl::MemOperand& src);
   void StoreRelease(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst);
 
@@ -340,7 +358,7 @@
     return false;
   }
 
-  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, vixl::Register temp);
+  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
 
  private:
   // Labels for each block that will be compiled.
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 69a90ad..aa4fd26 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -67,6 +67,10 @@
   return Mips64ReturnLocation(type);
 }
 
+Location InvokeDexCallingConventionVisitorMIPS64::GetMethodLocation() const {
+  return Location::RegisterLocation(kMethodRegisterArgument);
+}
+
 Location InvokeDexCallingConventionVisitorMIPS64::GetNextLocation(Primitive::Type type) {
   Location next_location;
   if (type == Primitive::kPrimVoid) {
@@ -134,6 +138,8 @@
     CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
   }
 
+  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS64"; }
+
  private:
   HBoundsCheck* const instruction_;
   const Location index_location_;
@@ -156,6 +162,8 @@
     CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS64"; }
+
  private:
   HDivZeroCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS64);
@@ -201,6 +209,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS64"; }
+
  private:
   // The class this slow path will load.
   HLoadClass* const cls_;
@@ -246,6 +256,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS64"; }
+
  private:
   HLoadString* const instruction_;
 
@@ -266,6 +278,8 @@
     CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
   }
 
+  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS64"; }
+
  private:
   HNullCheck* const instruction_;
 
@@ -300,6 +314,8 @@
     return &return_label_;
   }
 
+  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS64"; }
+
  private:
   HSuspendCheck* const instruction_;
   // If not null, the block to branch to after the suspend check.
@@ -363,6 +379,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS64"; }
+
  private:
   HInstruction* const instruction_;
   const Location class_to_check_;
@@ -387,6 +405,8 @@
     mips64_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS64"; }
+
  private:
   HInstruction* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS64);
@@ -785,16 +805,16 @@
                                Location location,
                                HInstruction* move_for) {
   LocationSummary* locations = instruction->GetLocations();
-  if (locations != nullptr && locations->Out().Equals(location)) {
-    return;
-  }
-
   Primitive::Type type = instruction->GetType();
   DCHECK_NE(type, Primitive::kPrimVoid);
 
-  if (instruction->IsIntConstant()
-      || instruction->IsLongConstant()
-      || instruction->IsNullConstant()) {
+  if (instruction->IsCurrentMethod()) {
+    MoveLocation(location, Location::DoubleStackSlot(kCurrentMethodStackOffset), type);
+  } else if (locations != nullptr && locations->Out().Equals(location)) {
+    return;
+  } else if (instruction->IsIntConstant()
+             || instruction->IsLongConstant()
+             || instruction->IsNullConstant()) {
     if (location.IsRegister()) {
       // Move to GPR from constant
       GpuRegister dst = location.AsRegister<GpuRegister>();
@@ -947,11 +967,6 @@
   stream << Mips64ManagedRegister::FromFpuRegister(FpuRegister(reg));
 }
 
-void CodeGeneratorMIPS64::LoadCurrentMethod(GpuRegister current_method) {
-  DCHECK(RequiresCurrentMethod());
-  __ Ld(current_method, SP, kCurrentMethodStackOffset);
-}
-
 void CodeGeneratorMIPS64::InvokeRuntime(int32_t entry_point_offset,
                                         HInstruction* instruction,
                                         uint32_t dex_pc,
@@ -1923,12 +1938,7 @@
   // Will be generated at use site.
 }
 
-void LocationsBuilderMIPS64::VisitGoto(HGoto* got) {
-  got->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorMIPS64::VisitGoto(HGoto* got) {
-  HBasicBlock* successor = got->GetSuccessor();
+void InstructionCodeGeneratorMIPS64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
   DCHECK(!successor->IsExitBlock());
   HBasicBlock* block = got->GetBlock();
   HInstruction* previous = got->GetPrevious();
@@ -1947,6 +1957,25 @@
   }
 }
 
+void LocationsBuilderMIPS64::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitGoto(HGoto* got) {
+  HandleGoto(got, got->GetSuccessor());
+}
+
+void LocationsBuilderMIPS64::VisitTryBoundary(HTryBoundary* try_boundary) {
+  try_boundary->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitTryBoundary(HTryBoundary* try_boundary) {
+  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
+  if (!successor->IsExitBlock()) {
+    HandleGoto(try_boundary, successor);
+  }
+}
+
 void InstructionCodeGeneratorMIPS64::GenerateTestAndBranch(HInstruction* instruction,
                                                            Label* true_target,
                                                            Label* false_target,
@@ -2297,20 +2326,8 @@
 }
 
 void LocationsBuilderMIPS64::HandleInvoke(HInvoke* invoke) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
-
   InvokeDexCallingConventionVisitorMIPS64 calling_convention_visitor;
-  for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
-    HInstruction* input = invoke->InputAt(i);
-    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
-  }
-
-  Primitive::Type return_type = invoke->GetType();
-  if (return_type != Primitive::kPrimVoid) {
-    locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type));
-  }
+  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
 }
 
 void LocationsBuilderMIPS64::VisitInvokeInterface(HInvokeInterface* invoke) {
@@ -2363,6 +2380,17 @@
 
   // TODO - intrinsic function
   HandleInvoke(invoke);
+
+  // While SetupBlockedRegisters() blocks registers S2-S8 due to their
+  // clobbering somewhere else, reduce further register pressure by avoiding
+  // allocation of a register for the current method pointer like on x86 baseline.
+  // TODO: remove this once all the issues with register saving/restoring are
+  // sorted out.
+  LocationSummary* locations = invoke->GetLocations();
+  Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
+  if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
+    locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
+  }
 }
 
 static bool TryGenerateIntrinsicCode(HInvoke* invoke,
@@ -2374,8 +2402,7 @@
   return false;
 }
 
-void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
-                                                     GpuRegister temp) {
+void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
   // All registers are assumed to be correctly set up per the calling convention.
 
   // TODO: Implement all kinds of calls:
@@ -2386,44 +2413,54 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   if (invoke->IsStringInit()) {
+    GpuRegister reg = temp.AsRegister<GpuRegister>();
     // temp = thread->string_init_entrypoint
     __ LoadFromOffset(kLoadDoubleword,
-                      temp,
+                      reg,
                       TR,
                       invoke->GetStringInitOffset());
     // T9 = temp->entry_point_from_quick_compiled_code_;
     __ LoadFromOffset(kLoadDoubleword,
                       T9,
-                      temp,
+                      reg,
                       ArtMethod::EntryPointFromQuickCompiledCodeOffset(
                           kMips64WordSize).Int32Value());
     // T9()
     __ Jalr(T9);
+  } else if (invoke->IsRecursive()) {
+    __ Jalr(&frame_entry_label_, T9);
   } else {
-    // temp = method;
-    LoadCurrentMethod(temp);
-    if (!invoke->IsRecursive()) {
-      // temp = temp->dex_cache_resolved_methods_;
-      __ LoadFromOffset(kLoadUnsignedWord,
-                        temp,
-                        temp,
-                        ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
-      // temp = temp[index_in_cache]
-      __ LoadFromOffset(kLoadDoubleword,
-                        temp,
-                        temp,
-                        CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex()));
-      // T9 = temp[offset_of_quick_compiled_code]
-      __ LoadFromOffset(kLoadDoubleword,
-                        T9,
-                        temp,
-                        ArtMethod::EntryPointFromQuickCompiledCodeOffset(
-                            kMips64WordSize).Int32Value());
-      // T9()
-      __ Jalr(T9);
+    Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
+    GpuRegister reg = temp.AsRegister<GpuRegister>();
+    GpuRegister method_reg;
+    if (current_method.IsRegister()) {
+      method_reg = current_method.AsRegister<GpuRegister>();
     } else {
-      __ Jalr(&frame_entry_label_, T9);
+      // TODO: use the appropriate DCHECK() here if possible.
+      // DCHECK(invoke->GetLocations()->Intrinsified());
+      DCHECK(!current_method.IsValid());
+      method_reg = reg;
+      __ Ld(reg, SP, kCurrentMethodStackOffset);
     }
+
+    // temp = temp->dex_cache_resolved_methods_;
+    __ LoadFromOffset(kLoadUnsignedWord,
+                      reg,
+                      method_reg,
+                      ArtMethod::DexCacheResolvedMethodsOffset().Int32Value());
+    // temp = temp[index_in_cache]
+    __ LoadFromOffset(kLoadDoubleword,
+                      reg,
+                      reg,
+                      CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex()));
+    // T9 = temp[offset_of_quick_compiled_code]
+    __ LoadFromOffset(kLoadDoubleword,
+                      T9,
+                      reg,
+                      ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+                          kMips64WordSize).Int32Value());
+    // T9()
+    __ Jalr(T9);
   }
 
   DCHECK(!IsLeafMethod());
@@ -2438,9 +2475,11 @@
     return;
   }
 
-  GpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<GpuRegister>();
-
-  codegen_->GenerateStaticOrDirectCall(invoke, temp);
+  LocationSummary* locations = invoke->GetLocations();
+  codegen_->GenerateStaticOrDirectCall(invoke,
+                                       locations->HasTemps()
+                                           ? locations->GetTemp(0)
+                                           : Location::NoLocation());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
@@ -2455,13 +2494,8 @@
   Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize);
 
   // temp = object->GetClass();
-  if (receiver.IsStackSlot()) {
-    __ LoadFromOffset(kLoadUnsignedWord, temp, SP, receiver.GetStackIndex());
-    __ LoadFromOffset(kLoadUnsignedWord, temp, temp, class_offset);
-  } else {
-    DCHECK(receiver.IsRegister());
-    __ LoadFromOffset(kLoadUnsignedWord, temp, receiver.AsRegister<GpuRegister>(), class_offset);
-  }
+  DCHECK(receiver.IsRegister());
+  __ LoadFromOffset(kLoadUnsignedWord, temp, receiver.AsRegister<GpuRegister>(), class_offset);
   codegen_->MaybeRecordImplicitNullCheck(invoke);
   // temp = temp->GetMethodAt(method_offset);
   __ LoadFromOffset(kLoadDoubleword, temp, temp, method_offset);
@@ -2477,22 +2511,23 @@
   LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath
                                                               : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
-  GpuRegister out = cls->GetLocations()->Out().AsRegister<GpuRegister>();
+  LocationSummary* locations = cls->GetLocations();
+  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
+  GpuRegister current_method = locations->InAt(0).AsRegister<GpuRegister>();
   if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
-    codegen_->LoadCurrentMethod(out);
-    __ LoadFromOffset(
-        kLoadUnsignedWord, out, out, ArtMethod::DeclaringClassOffset().Int32Value());
+    __ LoadFromOffset(kLoadUnsignedWord, out, current_method,
+                      ArtMethod::DeclaringClassOffset().Int32Value());
   } else {
     DCHECK(cls->CanCallRuntime());
-    codegen_->LoadCurrentMethod(out);
-    __ LoadFromOffset(
-        kLoadUnsignedWord, out, out, ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
+    __ LoadFromOffset(kLoadUnsignedWord, out, current_method,
+                      ArtMethod::DexCacheResolvedTypesOffset().Int32Value());
     __ LoadFromOffset(kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
     SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS64(
         cls,
@@ -2532,6 +2567,7 @@
 void LocationsBuilderMIPS64::VisitLoadString(HLoadString* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -2539,10 +2575,11 @@
   SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load);
   codegen_->AddSlowPath(slow_path);
 
-  GpuRegister out = load->GetLocations()->Out().AsRegister<GpuRegister>();
-  codegen_->LoadCurrentMethod(out);
-  __ LoadFromOffset(
-      kLoadUnsignedWord, out, out, ArtMethod::DeclaringClassOffset().Int32Value());
+  LocationSummary* locations = load->GetLocations();
+  GpuRegister out = locations->Out().AsRegister<GpuRegister>();
+  GpuRegister current_method = locations->InAt(0).AsRegister<GpuRegister>();
+  __ LoadFromOffset(kLoadUnsignedWord, out, current_method,
+                    ArtMethod::DeclaringClassOffset().Int32Value());
   __ LoadFromOffset(kLoadUnsignedWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
   __ LoadFromOffset(kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
   __ Beqzc(out, slow_path->GetEntryLabel());
@@ -2694,16 +2731,15 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
 }
 
 void InstructionCodeGeneratorMIPS64::VisitNewArray(HNewArray* instruction) {
-  InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
+  LocationSummary* locations = instruction->GetLocations();
   // Move an uint16_t value to a register.
-  __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex());
   codegen_->InvokeRuntime(
       GetThreadOffset<kMips64WordSize>(instruction->GetEntrypoint()).Int32Value(),
       instruction,
@@ -2717,15 +2753,14 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
 }
 
 void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) {
-  InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  LocationSummary* locations = instruction->GetLocations();
   // Move an uint16_t value to a register.
-  __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex());
   codegen_->InvokeRuntime(
       GetThreadOffset<kMips64WordSize>(instruction->GetEntrypoint()).Int32Value(),
       instruction,
@@ -2839,6 +2874,17 @@
   // Nothing to do, the parameter is already at its location.
 }
 
+void LocationsBuilderMIPS64::VisitCurrentMethod(HCurrentMethod* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
+}
+
+void InstructionCodeGeneratorMIPS64::VisitCurrentMethod(HCurrentMethod* instruction
+                                                        ATTRIBUTE_UNUSED) {
+  // Nothing to do, the method is already at its location.
+}
+
 void LocationsBuilderMIPS64::VisitPhi(HPhi* instruction) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 0ce0add..ae7c568 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -82,7 +82,8 @@
   virtual ~InvokeDexCallingConventionVisitorMIPS64() {}
 
   Location GetNextLocation(Primitive::Type type) OVERRIDE;
-  Location GetReturnLocation(Primitive::Type type) const;
+  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetMethodLocation() const OVERRIDE;
 
  private:
   InvokeDexCallingConvention calling_convention;
@@ -145,12 +146,18 @@
       : HGraphVisitor(graph), codegen_(codegen) {}
 
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
-  void Visit##name(H##name* instr);
+  void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
  private:
   void HandleInvoke(HInvoke* invoke);
   void HandleBinaryOp(HBinaryOperation* operation);
@@ -170,12 +177,18 @@
   InstructionCodeGeneratorMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen);
 
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
-  void Visit##name(H##name* instr);
+  void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
   Mips64Assembler* GetAssembler() const { return assembler_; }
 
  private:
@@ -195,6 +208,7 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   Mips64Assembler* const assembler_;
   CodeGeneratorMIPS64* const codegen_;
@@ -227,6 +241,7 @@
   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
   Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
+  const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
 
   void MarkGCCard(GpuRegister object, GpuRegister value);
 
@@ -269,8 +284,6 @@
 
   void SwapLocations(Location loc1, Location loc2, Primitive::Type type);
 
-  void LoadCurrentMethod(GpuRegister current_method);
-
   // Generate code to invoke a runtime entry point.
   void InvokeRuntime(int32_t offset,
                      HInstruction* instruction,
@@ -281,7 +294,7 @@
 
   bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const { return false; }
 
-  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, GpuRegister temp);
+  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
 
  private:
   // Labels for each block that will be compiled.
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 60fd29b..be71443 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -36,6 +36,7 @@
 namespace x86 {
 
 static constexpr int kCurrentMethodStackOffset = 0;
+static constexpr Register kMethodRegisterArgument = EAX;
 
 static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
 
@@ -43,7 +44,7 @@
 
 static constexpr int kFakeReturnRegister = Register(8);
 
-#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
+#define __ down_cast<X86Assembler*>(codegen->GetAssembler())->
 
 class NullCheckSlowPathX86 : public SlowPathCodeX86 {
  public:
@@ -55,6 +56,8 @@
     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
   }
 
+  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86"; }
+
  private:
   HNullCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
@@ -70,6 +73,8 @@
     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86"; }
+
  private:
   HDivZeroCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
@@ -89,6 +94,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86"; }
+
  private:
   Register reg_;
   bool is_div_;
@@ -121,6 +128,8 @@
     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
   }
 
+  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86"; }
+
  private:
   HBoundsCheck* const instruction_;
   const Location index_location_;
@@ -157,6 +166,8 @@
     return successor_;
   }
 
+  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86"; }
+
  private:
   HSuspendCheck* const instruction_;
   HBasicBlock* const successor_;
@@ -187,6 +198,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86"; }
+
  private:
   HLoadString* const instruction_;
 
@@ -227,6 +240,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86"; }
+
  private:
   // The class this slow path will load.
   HLoadClass* const cls_;
@@ -292,6 +307,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86"; }
+
  private:
   HInstruction* const instruction_;
   const Location class_to_check_;
@@ -317,13 +334,15 @@
     codegen->RecordPcInfo(instruction_, dex_pc, this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86"; }
+
  private:
   HInstruction* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86);
 };
 
 #undef __
-#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
+#define __ down_cast<X86Assembler*>(GetAssembler())->
 
 inline Condition X86Condition(IfCondition cond) {
   switch (cond) {
@@ -340,11 +359,11 @@
 }
 
 void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << X86ManagedRegister::FromCpuRegister(Register(reg));
+  stream << Register(reg);
 }
 
 void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
+  stream << XmmRegister(reg);
 }
 
 size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
@@ -498,7 +517,7 @@
   int adjust = GetFrameSize() - FrameEntrySpillSize();
   __ subl(ESP, Immediate(adjust));
   __ cfi().AdjustCFAOffset(adjust);
-  __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
+  __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
 }
 
 void CodeGeneratorX86::GenerateFrameExit() {
@@ -526,11 +545,6 @@
   __ Bind(GetLabelOf(block));
 }
 
-void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
-  DCHECK(RequiresCurrentMethod());
-  __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
-}
-
 Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
   switch (load->GetType()) {
     case Primitive::kPrimLong:
@@ -555,6 +569,34 @@
   UNREACHABLE();
 }
 
+Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+      return Location::RegisterLocation(EAX);
+
+    case Primitive::kPrimLong:
+      return Location::RegisterPairLocation(EAX, EDX);
+
+    case Primitive::kPrimVoid:
+      return Location::NoLocation();
+
+    case Primitive::kPrimDouble:
+    case Primitive::kPrimFloat:
+      return Location::FpuRegisterLocation(XMM0);
+  }
+
+  UNREACHABLE();
+}
+
+Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
+  return Location::RegisterLocation(kMethodRegisterArgument);
+}
+
 Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
   switch (type) {
     case Primitive::kPrimBoolean:
@@ -717,11 +759,11 @@
 
 void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
   LocationSummary* locations = instruction->GetLocations();
-  if (locations != nullptr && locations->Out().Equals(location)) {
+  if (instruction->IsCurrentMethod()) {
+    Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
+  } else if (locations != nullptr && locations->Out().Equals(location)) {
     return;
-  }
-
-  if (locations != nullptr && locations->Out().IsConstant()) {
+  } else if (locations != nullptr && locations->Out().IsConstant()) {
     HConstant* const_to_move = locations->Out().GetConstant();
     if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
       Immediate imm(GetInt32ValueOf(const_to_move));
@@ -800,12 +842,7 @@
   }
 }
 
-void LocationsBuilderX86::VisitGoto(HGoto* got) {
-  got->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
-  HBasicBlock* successor = got->GetSuccessor();
+void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
   DCHECK(!successor->IsExitBlock());
 
   HBasicBlock* block = got->GetBlock();
@@ -825,6 +862,25 @@
   }
 }
 
+void LocationsBuilderX86::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
+  HandleGoto(got, got->GetSuccessor());
+}
+
+void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
+  try_boundary->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
+  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
+  if (!successor->IsExitBlock()) {
+    HandleGoto(try_boundary, successor);
+  }
+}
+
 void LocationsBuilderX86::VisitExit(HExit* exit) {
   exit->SetLocations(nullptr);
 }
@@ -833,6 +889,180 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
+                                                  Label* true_label,
+                                                  Label* false_label) {
+  bool gt_bias = cond->IsGtBias();
+  IfCondition if_cond = cond->GetCondition();
+  Condition ccode = X86Condition(if_cond);
+  switch (if_cond) {
+    case kCondEQ:
+      if (!gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      break;
+    case kCondNE:
+      if (!gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      break;
+    case kCondLT:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelow;
+      break;
+    case kCondLE:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelowEqual;
+      break;
+    case kCondGT:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAbove;
+      break;
+    case kCondGE:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAboveEqual;
+      break;
+  }
+  __ j(ccode, 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_low = left.AsRegisterPairLow<Register>();
+  Register left_high = left.AsRegisterPairHigh<Register>();
+  IfCondition true_high_cond = if_cond;
+  IfCondition false_high_cond = cond->GetOppositeCondition();
+  Condition final_condition = X86Condition(if_cond);
+
+  // Set the conditions for the test, remembering that == needs to be
+  // decided using the low words.
+  switch (if_cond) {
+    case kCondEQ:
+      false_high_cond = kCondNE;
+      break;
+    case kCondNE:
+      false_high_cond = kCondEQ;
+      break;
+    case kCondLT:
+      false_high_cond = kCondGT;
+      final_condition = kBelow;
+      break;
+    case kCondLE:
+      true_high_cond = kCondLT;
+      final_condition = kBelowEqual;
+      break;
+    case kCondGT:
+      false_high_cond = kCondLT;
+      final_condition = kAbove;
+      break;
+    case kCondGE:
+      true_high_cond = kCondGT;
+      final_condition = kAboveEqual;
+      break;
+  }
+
+  if (right.IsConstant()) {
+    int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+    int32_t val_low = Low32Bits(value);
+    int32_t val_high = High32Bits(value);
+
+    if (val_high == 0) {
+      __ testl(left_high, left_high);
+    } else {
+      __ cmpl(left_high, Immediate(val_high));
+    }
+    if (if_cond == kCondNE) {
+      __ j(X86Condition(true_high_cond), true_label);
+    } else if (if_cond == kCondEQ) {
+      __ j(X86Condition(false_high_cond), false_label);
+    } else {
+      __ j(X86Condition(true_high_cond), true_label);
+      __ j(X86Condition(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_low = right.AsRegisterPairLow<Register>();
+    Register right_high = right.AsRegisterPairHigh<Register>();
+
+    __ cmpl(left_high, right_high);
+    if (if_cond == kCondNE) {
+      __ j(X86Condition(true_high_cond), true_label);
+    } else if (if_cond == kCondEQ) {
+      __ j(X86Condition(false_high_cond), false_label);
+    } else {
+      __ j(X86Condition(true_high_cond), true_label);
+      __ j(X86Condition(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:
+      DCHECK(right.IsFpuRegister());
+      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimDouble:
+      DCHECK(right.IsFpuRegister());
+      __ 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,
@@ -854,9 +1084,12 @@
         !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);
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
+        && type == Primitive::kPrimInt;
     if (materialized) {
       if (!eflags_set) {
         // Materialized condition, compare against 0.
@@ -871,6 +1104,16 @@
         __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
       }
     } else {
+      // 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
@@ -976,46 +1219,103 @@
     default:
       LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
   }
-  store->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
   UNUSED(store);
 }
 
-void LocationsBuilderX86::VisitCondition(HCondition* comp) {
+void LocationsBuilderX86::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
-  if (comp->NeedsMaterialization()) {
-    // We need a byte register.
-    locations->SetOut(Location::RegisterLocation(ECX));
+      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
+  // 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* comp) {
-  if (comp->NeedsMaterialization()) {
-    LocationSummary* locations = comp->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(comp->GetCondition()), reg);
+void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
+  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(X86Condition(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) {
@@ -1207,6 +1507,17 @@
   }
 
   HandleInvoke(invoke);
+
+  if (codegen_->IsBaseline()) {
+    // Baseline does not have enough registers if the current method also
+    // needs a register. We therefore do not require a register for it, and let
+    // the code generation of the invoke handle it.
+    LocationSummary* locations = invoke->GetLocations();
+    Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
+    if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
+      locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
+    }
+  }
 }
 
 static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
@@ -1227,8 +1538,9 @@
     return;
   }
 
+  LocationSummary* locations = invoke->GetLocations();
   codegen_->GenerateStaticOrDirectCall(
-      invoke, invoke->GetLocations()->GetTemp(0).AsRegister<Register>());
+      invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
@@ -1237,40 +1549,8 @@
 }
 
 void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(Location::RegisterLocation(EAX));
-
   InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
-  for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
-    HInstruction* input = invoke->InputAt(i);
-    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
-  }
-
-  switch (invoke->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-      locations->SetOut(Location::RegisterLocation(EAX));
-      break;
-
-    case Primitive::kPrimLong:
-      locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
-      break;
-
-    case Primitive::kPrimVoid:
-      break;
-
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
-      locations->SetOut(Location::FpuRegisterLocation(XMM0));
-      break;
-  }
-
-  invoke->SetLocations(locations);
+  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
 }
 
 void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -1281,13 +1561,10 @@
   Location receiver = locations->InAt(0);
   uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
   // temp = object->GetClass();
-  if (receiver.IsStackSlot()) {
-    __ movl(temp, Address(ESP, receiver.GetStackIndex()));
-    __ movl(temp, Address(temp, class_offset));
-  } else {
-    __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
-  }
+  DCHECK(receiver.IsRegister());
+  __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
   // temp = temp->GetMethodAt(method_offset);
   __ movl(temp, Address(temp, method_offset));
   // call temp->GetEntryPoint();
@@ -1324,7 +1601,8 @@
   } else {
     __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
   }
-    codegen_->MaybeRecordImplicitNullCheck(invoke);
+  codegen_->MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
   // temp = temp->GetImtEntryAt(method_offset);
   __ movl(temp, Address(temp, method_offset));
   // call temp->GetEntryPoint();
@@ -1959,6 +2237,8 @@
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
+        } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
+          __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
         } else {
           __ leal(out.AsRegister<Register>(), Address(
               first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
@@ -2963,14 +3243,14 @@
   locations->SetOut(Location::RegisterLocation(EAX));
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
 }
 
 void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
   __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
-
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
 
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
@@ -2983,15 +3263,16 @@
   locations->SetOut(Location::RegisterLocation(EAX));
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
 }
 
 void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
   __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
 
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
 
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
@@ -3010,8 +3291,17 @@
   locations->SetOut(location);
 }
 
-void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
-  UNUSED(instruction);
+void InstructionCodeGeneratorX86::VisitParameterValue(
+    HParameterValue* instruction ATTRIBUTE_UNUSED) {
+}
+
+void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
+}
+
+void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
 }
 
 void LocationsBuilderX86::VisitNot(HNot* not_) {
@@ -3194,7 +3484,7 @@
 
 
 void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
-                                                  Register temp) {
+                                                  Location temp) {
   // TODO: Implement all kinds of calls:
   // 1) boot -> boot
   // 2) app -> boot
@@ -3204,40 +3494,57 @@
 
   if (invoke->IsStringInit()) {
     // temp = thread->string_init_entrypoint
-    __ fs()->movl(temp, Address::Absolute(invoke->GetStringInitOffset()));
+    Register reg = temp.AsRegister<Register>();
+    __ fs()->movl(reg, Address::Absolute(invoke->GetStringInitOffset()));
     // (temp + offset_of_quick_compiled_code)()
     __ call(Address(
-        temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+        reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+  } else if (invoke->IsRecursive()) {
+    __ call(GetFrameEntryLabel());
   } else {
-    // temp = method;
-    LoadCurrentMethod(temp);
-    if (!invoke->IsRecursive()) {
-      // temp = temp->dex_cache_resolved_methods_;
-      __ movl(temp, Address(temp, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
-      // temp = temp[index_in_cache]
-      __ movl(temp, Address(temp,
-                            CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
-      // (temp + offset_of_quick_compiled_code)()
-      __ call(Address(temp,
-          ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+    Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
+
+    Register method_reg;
+    Register reg = temp.AsRegister<Register>();
+    if (current_method.IsRegister()) {
+      method_reg = current_method.AsRegister<Register>();
     } else {
-      __ call(GetFrameEntryLabel());
+      DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified());
+      DCHECK(!current_method.IsValid());
+      method_reg = reg;
+      __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
     }
+    // temp = temp->dex_cache_resolved_methods_;
+    __ movl(reg, Address(method_reg, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
+    // temp = temp[index_in_cache]
+    __ movl(reg, Address(reg,
+                         CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
+    // (temp + offset_of_quick_compiled_code)()
+    __ call(Address(reg,
+        ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
   }
 
   DCHECK(!IsLeafMethod());
 }
 
-void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
+void CodeGeneratorX86::MarkGCCard(Register temp,
+                                  Register card,
+                                  Register object,
+                                  Register value,
+                                  bool value_can_be_null) {
   Label is_null;
-  __ testl(value, value);
-  __ j(kEqual, &is_null);
+  if (value_can_be_null) {
+    __ testl(value, value);
+    __ j(kEqual, &is_null);
+  }
   __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
   __ movl(temp, object);
   __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
   __ movb(Address(temp, card, TIMES_1, 0),
           X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
-  __ Bind(&is_null);
+  if (value_can_be_null) {
+    __ Bind(&is_null);
+  }
 }
 
 void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
@@ -3342,6 +3649,10 @@
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   }
+
+  if (field_type == Primitive::kPrimNot) {
+    __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
+  }
 }
 
 void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
@@ -3365,9 +3676,9 @@
   } else {
     locations->SetInAt(1, Location::RequiresRegister());
   }
-  // Temporary registers for the write barrier.
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
-    locations->AddTemp(Location::RequiresRegister());
+    // Temporary registers for the write barrier.
+    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     // Ensure the card is in a byte register.
     locations->AddTemp(Location::RegisterLocation(ECX));
   } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
@@ -3382,7 +3693,8 @@
 }
 
 void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
-                                                 const FieldInfo& field_info) {
+                                                 const FieldInfo& field_info,
+                                                 bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
 
   LocationSummary* locations = instruction->GetLocations();
@@ -3391,6 +3703,8 @@
   bool is_volatile = field_info.IsVolatile();
   Primitive::Type field_type = field_info.GetFieldType();
   uint32_t offset = field_info.GetFieldOffset().Uint32Value();
+  bool needs_write_barrier =
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
 
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
@@ -3411,7 +3725,18 @@
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      __ movl(Address(base, offset), value.AsRegister<Register>());
+      if (kPoisonHeapReferences && needs_write_barrier) {
+        // Note that in the case where `value` is a null reference,
+        // we do not enter this block, as the reference does not
+        // need poisoning.
+        DCHECK_EQ(field_type, Primitive::kPrimNot);
+        Register temp = locations->GetTemp(0).AsRegister<Register>();
+        __ movl(temp, value.AsRegister<Register>());
+        __ PoisonHeapReference(temp);
+        __ movl(Address(base, offset), temp);
+      } else {
+        __ movl(Address(base, offset), value.AsRegister<Register>());
+      }
       break;
     }
 
@@ -3452,10 +3777,10 @@
     codegen_->MaybeRecordImplicitNullCheck(instruction);
   }
 
-  if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
+  if (needs_write_barrier) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     Register card = locations->GetTemp(1).AsRegister<Register>();
-    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
   }
 
   if (is_volatile) {
@@ -3476,7 +3801,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
@@ -3484,7 +3809,7 @@
 }
 
 void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3681,6 +4006,11 @@
   if (type != Primitive::kPrimLong) {
     codegen_->MaybeRecordImplicitNullCheck(instruction);
   }
+
+  if (type == Primitive::kPrimNot) {
+    Register out = locations->Out().AsRegister<Register>();
+    __ MaybeUnpoisonHeapReference(out);
+  }
 }
 
 void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
@@ -3720,9 +4050,9 @@
     } else {
       locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
     }
-    // Temporary registers for the write barrier.
     if (needs_write_barrier) {
-      locations->AddTemp(Location::RequiresRegister());
+      // Temporary registers for the write barrier.
+      locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
       // Ensure the card is in a byte register.
       locations->AddTemp(Location::RegisterLocation(ECX));
     }
@@ -3796,21 +4126,43 @@
           size_t offset =
               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
           if (value.IsRegister()) {
-            __ movl(Address(obj, offset), value.AsRegister<Register>());
+            if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
+              Register temp = locations->GetTemp(0).AsRegister<Register>();
+              __ movl(temp, value.AsRegister<Register>());
+              __ PoisonHeapReference(temp);
+              __ movl(Address(obj, offset), temp);
+            } else {
+              __ movl(Address(obj, offset), value.AsRegister<Register>());
+            }
           } else {
             DCHECK(value.IsConstant()) << value;
-            __ movl(Address(obj, offset),
-                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+            int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+            // `value_type == Primitive::kPrimNot` implies `v == 0`.
+            DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
+            // Note: if heap poisoning is enabled, no need to poison
+            // (negate) `v` if it is a reference, as it would be null.
+            __ movl(Address(obj, offset), Immediate(v));
           }
         } else {
           DCHECK(index.IsRegister()) << index;
           if (value.IsRegister()) {
-            __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
-                    value.AsRegister<Register>());
+            if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
+              Register temp = locations->GetTemp(0).AsRegister<Register>();
+              __ movl(temp, value.AsRegister<Register>());
+              __ PoisonHeapReference(temp);
+              __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), temp);
+            } else {
+              __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
+                      value.AsRegister<Register>());
+            }
           } else {
             DCHECK(value.IsConstant()) << value;
-            __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
-                    Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+            int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+            // `value_type == Primitive::kPrimNot` implies `v == 0`.
+            DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
+            // Note: if heap poisoning is enabled, no need to poison
+            // (negate) `v` if it is a reference, as it would be null.
+            __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), Immediate(v));
           }
         }
         codegen_->MaybeRecordImplicitNullCheck(instruction);
@@ -3818,11 +4170,14 @@
         if (needs_write_barrier) {
           Register temp = locations->GetTemp(0).AsRegister<Register>();
           Register card = locations->GetTemp(1).AsRegister<Register>();
-          codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
+          codegen_->MarkGCCard(
+              temp, card, obj, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
         }
       } else {
         DCHECK_EQ(value_type, Primitive::kPrimNot);
         DCHECK(!codegen_->IsLeafMethod());
+        // Note: if heap poisoning is enabled, pAputObject takes cares
+        // of poisoning the reference.
         __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
         codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
       }
@@ -3900,7 +4255,6 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
-  instruction->SetLocations(locations);
 }
 
 void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
@@ -4270,21 +4624,24 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
-  Register out = cls->GetLocations()->Out().AsRegister<Register>();
+  LocationSummary* locations = cls->GetLocations();
+  Register out = locations->Out().AsRegister<Register>();
+  Register current_method = locations->InAt(0).AsRegister<Register>();
   if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
-    codegen_->LoadCurrentMethod(out);
-    __ movl(out, Address(out, ArtMethod::DeclaringClassOffset().Int32Value()));
+    __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
   } else {
     DCHECK(cls->CanCallRuntime());
-    codegen_->LoadCurrentMethod(out);
-    __ movl(out, Address(out, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
+    __ movl(out, Address(
+        current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
     __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+    __ MaybeUnpoisonHeapReference(out);
 
     SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
@@ -4329,6 +4686,7 @@
 void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -4336,11 +4694,14 @@
   SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
   codegen_->AddSlowPath(slow_path);
 
-  Register out = load->GetLocations()->Out().AsRegister<Register>();
-  codegen_->LoadCurrentMethod(out);
-  __ movl(out, Address(out, ArtMethod::DeclaringClassOffset().Int32Value()));
+  LocationSummary* locations = load->GetLocations();
+  Register out = locations->Out().AsRegister<Register>();
+  Register current_method = locations->InAt(0).AsRegister<Register>();
+  __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
   __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
+  __ MaybeUnpoisonHeapReference(out);
   __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  __ MaybeUnpoisonHeapReference(out);
   __ testl(out, out);
   __ j(kEqual, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
@@ -4395,8 +4756,9 @@
     __ testl(obj, obj);
     __ j(kEqual, &zero);
   }
-  __ movl(out, Address(obj, class_offset));
   // Compare the class of `obj` with `cls`.
+  __ movl(out, Address(obj, class_offset));
+  __ MaybeUnpoisonHeapReference(out);
   if (cls.IsRegister()) {
     __ cmpl(out, cls.AsRegister<Register>());
   } else {
@@ -4454,16 +4816,17 @@
     __ testl(obj, obj);
     __ j(kEqual, slow_path->GetExitLabel());
   }
-
-  __ movl(temp, Address(obj, class_offset));
   // Compare the class of `obj` with `cls`.
+  __ movl(temp, Address(obj, class_offset));
+  __ MaybeUnpoisonHeapReference(temp);
   if (cls.IsRegister()) {
     __ cmpl(temp, cls.AsRegister<Register>());
   } else {
     DCHECK(cls.IsStackSlot()) << cls;
     __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
   }
-
+  // The checkcast succeeds if the classes are equal (fast path).
+  // Otherwise, we need to go into the slow path to check the types.
   __ j(kNotEqual, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
@@ -4627,5 +4990,7 @@
   LOG(FATAL) << "Unreachable";
 }
 
+#undef __
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 43214fe..65d6e0a 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -83,6 +83,8 @@
   virtual ~InvokeDexCallingConventionVisitorX86() {}
 
   Location GetNextLocation(Primitive::Type type) OVERRIDE;
+  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetMethodLocation() const OVERRIDE;
 
  private:
   InvokeDexCallingConvention calling_convention;
@@ -122,10 +124,16 @@
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
   void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
  private:
   void HandleBitwiseOperation(HBinaryOperation* instruction);
   void HandleInvoke(HInvoke* invoke);
@@ -146,10 +154,16 @@
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
   void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
   X86Assembler* GetAssembler() const { return assembler_; }
 
  private:
@@ -163,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);
@@ -172,7 +186,9 @@
   void GenerateShrLong(const Location& loc, int shift);
   void GenerateUShrLong(const Location& loc, int shift);
   void GenerateMemoryBarrier(MemBarrierKind kind);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not.
   // `is_wide` specifies whether it is long/double or not.
@@ -185,6 +201,14 @@
                              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_;
   CodeGeneratorX86* const codegen_;
@@ -229,6 +253,10 @@
     return &assembler_;
   }
 
+  const X86Assembler& GetAssembler() const OVERRIDE {
+    return assembler_;
+  }
+
   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
     return GetLabelOf(block)->Position();
   }
@@ -259,12 +287,14 @@
   void Move64(Location destination, Location source);
 
   // Generate a call to a static or direct method.
-  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp);
+  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
 
   // Emit a write barrier.
-  void MarkGCCard(Register temp, Register card, Register object, Register value);
-
-  void LoadCurrentMethod(Register reg);
+  void MarkGCCard(Register temp,
+                  Register card,
+                  Register object,
+                  Register value,
+                  bool value_can_be_null);
 
   Label* GetLabelOf(HBasicBlock* block) const {
     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index d767dfe..ddaa60d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -39,14 +39,14 @@
 static constexpr Register TMP = R11;
 
 static constexpr int kCurrentMethodStackOffset = 0;
+static constexpr Register kMethodRegisterArgument = RDI;
 
 static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 };
 static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 };
 
 static constexpr int kC2ConditionMask = 0x400;
 
-
-#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
+#define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())->
 
 class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 {
  public:
@@ -59,6 +59,8 @@
     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
   }
 
+  const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86_64"; }
+
  private:
   HNullCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
@@ -75,6 +77,8 @@
     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86_64"; }
+
  private:
   HDivZeroCheck* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64);
@@ -105,6 +109,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86_64"; }
+
  private:
   const CpuRegister cpu_reg_;
   const Primitive::Type type_;
@@ -140,6 +146,8 @@
     return successor_;
   }
 
+  const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86_64"; }
+
  private:
   HSuspendCheck* const instruction_;
   HBasicBlock* const successor_;
@@ -174,6 +182,8 @@
     RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
   }
 
+  const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86_64"; }
+
  private:
   HBoundsCheck* const instruction_;
   const Location index_location_;
@@ -203,7 +213,7 @@
     __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
     __ gs()->call(Address::Absolute((do_clinit_
           ? QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeStaticStorage)
-          : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)) , true));
+          : QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pInitializeType)), true));
     RecordPcInfo(codegen, at_, dex_pc_);
 
     Location out = locations->Out();
@@ -217,6 +227,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86_64"; }
+
  private:
   // The class this slow path will load.
   HLoadClass* const cls_;
@@ -257,6 +269,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
+
  private:
   HLoadString* const instruction_;
 
@@ -312,6 +326,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86_64"; }
+
  private:
   HInstruction* const instruction_;
   const Location class_to_check_;
@@ -337,13 +353,15 @@
     codegen->RecordPcInfo(instruction_, dex_pc, this);
   }
 
+  const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86_64"; }
+
  private:
   HInstruction* const instruction_;
   DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86_64);
 };
 
 #undef __
-#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
+#define __ down_cast<X86_64Assembler*>(GetAssembler())->
 
 inline Condition X86_64Condition(IfCondition cond) {
   switch (cond) {
@@ -360,7 +378,7 @@
 }
 
 void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
-                                                     CpuRegister temp) {
+                                                     Location temp) {
   // All registers are assumed to be correctly set up.
 
   // TODO: Implement all kinds of calls:
@@ -371,37 +389,46 @@
   // Currently we implement the app -> app logic, which looks up in the resolve cache.
 
   if (invoke->IsStringInit()) {
+    CpuRegister reg = temp.AsRegister<CpuRegister>();
     // temp = thread->string_init_entrypoint
-    __ gs()->movq(temp, Address::Absolute(invoke->GetStringInitOffset(), true));
+    __ gs()->movq(reg, Address::Absolute(invoke->GetStringInitOffset(), true));
     // (temp + offset_of_quick_compiled_code)()
-    __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+    __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
         kX86_64WordSize).SizeValue()));
+  } else if (invoke->IsRecursive()) {
+    __ call(&frame_entry_label_);
   } else {
-    // temp = method;
-    LoadCurrentMethod(temp);
-    if (!invoke->IsRecursive()) {
-      // temp = temp->dex_cache_resolved_methods_;
-      __ movl(temp, Address(temp, ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
-      // temp = temp[index_in_cache]
-      __ movq(temp, Address(
-          temp, CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
-      // (temp + offset_of_quick_compiled_code)()
-      __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
-          kX86_64WordSize).SizeValue()));
+    CpuRegister reg = temp.AsRegister<CpuRegister>();
+    Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
+    Register method_reg;
+    if (current_method.IsRegister()) {
+      method_reg = current_method.AsRegister<Register>();
     } else {
-      __ call(&frame_entry_label_);
+      DCHECK(invoke->GetLocations()->Intrinsified());
+      DCHECK(!current_method.IsValid());
+      method_reg = reg.AsRegister();
+      __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
     }
+    // temp = temp->dex_cache_resolved_methods_;
+    __ movl(reg, Address(CpuRegister(method_reg),
+                         ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
+    // temp = temp[index_in_cache]
+    __ movq(reg, Address(
+        reg, CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
+    // (temp + offset_of_quick_compiled_code)()
+    __ call(Address(reg, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+        kX86_64WordSize).SizeValue()));
   }
 
   DCHECK(!IsLeafMethod());
 }
 
 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
-  stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
+  stream << Register(reg);
 }
 
 void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
-  stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
+  stream << FloatRegister(reg);
 }
 
 size_t CodeGeneratorX86_64::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
@@ -546,7 +573,8 @@
     }
   }
 
-  __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
+  __ movq(Address(CpuRegister(RSP), kCurrentMethodStackOffset),
+          CpuRegister(kMethodRegisterArgument));
 }
 
 void CodeGeneratorX86_64::GenerateFrameExit() {
@@ -584,11 +612,6 @@
   __ Bind(GetLabelOf(block));
 }
 
-void CodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
-  DCHECK(RequiresCurrentMethod());
-  __ movq(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
-}
-
 Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
   switch (load->GetType()) {
     case Primitive::kPrimLong:
@@ -690,11 +713,11 @@
                                Location location,
                                HInstruction* move_for) {
   LocationSummary* locations = instruction->GetLocations();
-  if (locations != nullptr && locations->Out().Equals(location)) {
+  if (instruction->IsCurrentMethod()) {
+    Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
+  } else if (locations != nullptr && locations->Out().Equals(location)) {
     return;
-  }
-
-  if (locations != nullptr && locations->Out().IsConstant()) {
+  } else if (locations != nullptr && locations->Out().IsConstant()) {
     HConstant* const_to_move = locations->Out().GetConstant();
     if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
       Immediate imm(GetInt32ValueOf(const_to_move));
@@ -763,12 +786,7 @@
   }
 }
 
-void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
-  got->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
-  HBasicBlock* successor = got->GetSuccessor();
+void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) {
   DCHECK(!successor->IsExitBlock());
 
   HBasicBlock* block = got->GetBlock();
@@ -788,6 +806,25 @@
   }
 }
 
+void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
+  got->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
+  HandleGoto(got, got->GetSuccessor());
+}
+
+void LocationsBuilderX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
+  try_boundary->SetLocations(nullptr);
+}
+
+void InstructionCodeGeneratorX86_64::VisitTryBoundary(HTryBoundary* try_boundary) {
+  HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
+  if (!successor->IsExitBlock()) {
+    HandleGoto(try_boundary, successor);
+  }
+}
+
 void LocationsBuilderX86_64::VisitExit(HExit* exit) {
   exit->SetLocations(nullptr);
 }
@@ -796,6 +833,134 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
+                                                     Label* true_label,
+                                                     Label* false_label) {
+  bool gt_bias = cond->IsGtBias();
+  IfCondition if_cond = cond->GetCondition();
+  Condition ccode = X86_64Condition(if_cond);
+  switch (if_cond) {
+    case kCondEQ:
+      if (!gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      break;
+    case kCondNE:
+      if (!gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      break;
+    case kCondLT:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelow;
+      break;
+    case kCondLE:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelowEqual;
+      break;
+    case kCondGT:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAbove;
+      break;
+    case kCondGE:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAboveEqual;
+      break;
+  }
+  __ j(ccode, 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 an 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_64Condition(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,
@@ -817,9 +982,13 @@
         !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);
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
+        && !Primitive::IsFloatingPointType(type);
+
     if (materialized) {
       if (!eflags_set) {
         // Materialized condition, compare against 0.
@@ -835,6 +1004,13 @@
         __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
       }
     } else {
+      // 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()) {
@@ -945,38 +1121,125 @@
   UNUSED(store);
 }
 
-void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
+void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
-  if (comp->NeedsMaterialization()) {
+      new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
+  // 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* comp) {
-  if (comp->NeedsMaterialization()) {
-    LocationSummary* locations = comp->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(comp->GetCondition()), reg);
+void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
+  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_64Condition(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_64Condition(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) {
@@ -1244,6 +1507,32 @@
   codegen_->GenerateFrameExit();
 }
 
+Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(Primitive::Type type) const {
+  switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot:
+    case Primitive::kPrimLong:
+      return Location::RegisterLocation(RAX);
+
+    case Primitive::kPrimVoid:
+      return Location::NoLocation();
+
+    case Primitive::kPrimDouble:
+    case Primitive::kPrimFloat:
+      return Location::FpuRegisterLocation(XMM0);
+  }
+
+  UNREACHABLE();
+}
+
+Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
+  return Location::RegisterLocation(kMethodRegisterArgument);
+}
+
 Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Type type) {
   switch (type) {
     case Primitive::kPrimBoolean:
@@ -1331,42 +1620,15 @@
     return;
   }
 
+  LocationSummary* locations = invoke->GetLocations();
   codegen_->GenerateStaticOrDirectCall(
-      invoke,
-      invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>());
+      invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
 void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
-  LocationSummary* locations =
-      new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
-  locations->AddTemp(Location::RegisterLocation(RDI));
-
   InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor;
-  for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
-    HInstruction* input = invoke->InputAt(i);
-    locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
-  }
-
-  switch (invoke->GetType()) {
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-    case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-    case Primitive::kPrimLong:
-      locations->SetOut(Location::RegisterLocation(RAX));
-      break;
-
-    case Primitive::kPrimVoid:
-      break;
-
-    case Primitive::kPrimDouble:
-    case Primitive::kPrimFloat:
-      locations->SetOut(Location::FpuRegisterLocation(XMM0));
-      break;
-  }
+  CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
 }
 
 void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
@@ -1390,13 +1652,10 @@
   Location receiver = locations->InAt(0);
   size_t class_offset = mirror::Object::ClassOffset().SizeValue();
   // temp = object->GetClass();
-  if (receiver.IsStackSlot()) {
-    __ movl(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
-    __ movl(temp, Address(temp, class_offset));
-  } else {
-    __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
-  }
+  DCHECK(receiver.IsRegister());
+  __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
   // temp = temp->GetMethodAt(method_offset);
   __ movq(temp, Address(temp, method_offset));
   // call temp->GetEntryPoint();
@@ -1434,6 +1693,7 @@
     __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
   }
   codegen_->MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
   // temp = temp->GetImtEntryAt(method_offset);
   __ movq(temp, Address(temp, method_offset));
   // call temp->GetEntryPoint();
@@ -2118,6 +2378,8 @@
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addl(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+        } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
+          __ addl(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
         } else {
           __ leal(out.AsRegister<CpuRegister>(), Address(
               first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
@@ -2141,6 +2403,8 @@
       if (second.IsRegister()) {
         if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
           __ addq(out.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>());
+        } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
+          __ addq(out.AsRegister<CpuRegister>(), first.AsRegister<CpuRegister>());
         } else {
           __ leaq(out.AsRegister<CpuRegister>(), Address(
               first.AsRegister<CpuRegister>(), second.AsRegister<CpuRegister>(), TIMES_1, 0));
@@ -3016,15 +3280,16 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
   locations->SetOut(Location::RegisterLocation(RAX));
 }
 
 void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
   codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
                            instruction->GetTypeIndex());
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   __ gs()->call(
       Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
 
@@ -3037,17 +3302,18 @@
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
   InvokeRuntimeCallingConvention calling_convention;
   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
-  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
   locations->SetOut(Location::RegisterLocation(RAX));
   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
 }
 
 void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  codegen_->LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(2)));
   codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
                            instruction->GetTypeIndex());
 
+  // Note: if heap poisoning is enabled, the entry point takes cares
+  // of poisoning the reference.
   __ gs()->call(
       Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true));
 
@@ -3067,9 +3333,20 @@
   locations->SetOut(location);
 }
 
-void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
+void InstructionCodeGeneratorX86_64::VisitParameterValue(
+    HParameterValue* instruction ATTRIBUTE_UNUSED) {
   // Nothing to do, the parameter is already at its location.
-  UNUSED(instruction);
+}
+
+void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
+}
+
+void InstructionCodeGeneratorX86_64::VisitCurrentMethod(
+    HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
+  // Nothing to do, the method is already at its location.
 }
 
 void LocationsBuilderX86_64::VisitNot(HNot* not_) {
@@ -3225,6 +3502,10 @@
   if (is_volatile) {
     GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
   }
+
+  if (field_type == Primitive::kPrimNot) {
+    __ MaybeUnpoisonHeapReference(out.AsRegister<CpuRegister>());
+  }
 }
 
 void LocationsBuilderX86_64::HandleFieldSet(HInstruction* instruction,
@@ -3233,8 +3514,9 @@
 
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+  Primitive::Type field_type = field_info.GetFieldType();
   bool needs_write_barrier =
-      CodeGenerator::StoreNeedsWriteBarrier(field_info.GetFieldType(), instruction->InputAt(1));
+      CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
 
   locations->SetInAt(0, Location::RequiresRegister());
   if (Primitive::IsFloatingPointType(instruction->InputAt(1)->GetType())) {
@@ -3244,13 +3526,17 @@
   }
   if (needs_write_barrier) {
     // Temporary registers for the write barrier.
+    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     locations->AddTemp(Location::RequiresRegister());
+  } else if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
+    // Temporary register for the reference poisoning.
     locations->AddTemp(Location::RequiresRegister());
   }
 }
 
 void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
-                                                    const FieldInfo& field_info) {
+                                                    const FieldInfo& field_info,
+                                                    bool value_can_be_null) {
   DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
 
   LocationSummary* locations = instruction->GetLocations();
@@ -3291,9 +3577,20 @@
     case Primitive::kPrimNot: {
       if (value.IsConstant()) {
         int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
-        __ movw(Address(base, offset), Immediate(v));
+        // `field_type == Primitive::kPrimNot` implies `v == 0`.
+        DCHECK((field_type != Primitive::kPrimNot) || (v == 0));
+        // Note: if heap poisoning is enabled, no need to poison
+        // (negate) `v` if it is a reference, as it would be null.
+        __ movl(Address(base, offset), Immediate(v));
       } else {
-        __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
+        if (kPoisonHeapReferences && field_type == Primitive::kPrimNot) {
+          CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+          __ movl(temp, value.AsRegister<CpuRegister>());
+          __ PoisonHeapReference(temp);
+          __ movl(Address(base, offset), temp);
+        } else {
+          __ movl(Address(base, offset), value.AsRegister<CpuRegister>());
+        }
       }
       break;
     }
@@ -3330,7 +3627,7 @@
   if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
     CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
     CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
-    codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>());
+    codegen_->MarkGCCard(temp, card, base, value.AsRegister<CpuRegister>(), value_can_be_null);
   }
 
   if (is_volatile) {
@@ -3343,7 +3640,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
@@ -3367,7 +3664,7 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitStaticFieldSet(HStaticFieldSet* instruction) {
-  HandleFieldSet(instruction, instruction->GetFieldInfo());
+  HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
 }
 
 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
@@ -3437,8 +3734,9 @@
   LocationSummary* locations = instruction->GetLocations();
   CpuRegister obj = locations->InAt(0).AsRegister<CpuRegister>();
   Location index = locations->InAt(1);
+  Primitive::Type type = instruction->GetType();
 
-  switch (instruction->GetType()) {
+  switch (type) {
     case Primitive::kPrimBoolean: {
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
       CpuRegister out = locations->Out().AsRegister<CpuRegister>();
@@ -3489,7 +3787,8 @@
 
     case Primitive::kPrimInt:
     case Primitive::kPrimNot: {
-      DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
+      static_assert(sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
+                    "art::mirror::HeapReference<mirror::Object> and int32_t have different sizes.");
       uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
       CpuRegister out = locations->Out().AsRegister<CpuRegister>();
       if (index.IsConstant()) {
@@ -3538,10 +3837,15 @@
     }
 
     case Primitive::kPrimVoid:
-      LOG(FATAL) << "Unreachable type " << instruction->GetType();
+      LOG(FATAL) << "Unreachable type " << type;
       UNREACHABLE();
   }
   codegen_->MaybeRecordImplicitNullCheck(instruction);
+
+  if (type == Primitive::kPrimNot) {
+    CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+    __ MaybeUnpoisonHeapReference(out);
+  }
 }
 
 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
@@ -3573,7 +3877,7 @@
 
     if (needs_write_barrier) {
       // Temporary registers for the write barrier.
-      locations->AddTemp(Location::RequiresRegister());
+      locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
       locations->AddTemp(Location::RequiresRegister());
     }
   }
@@ -3649,20 +3953,42 @@
           size_t offset =
               (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
           if (value.IsRegister()) {
-            __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
+            if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
+              CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+              __ movl(temp, value.AsRegister<CpuRegister>());
+              __ PoisonHeapReference(temp);
+              __ movl(Address(obj, offset), temp);
+            } else {
+              __ movl(Address(obj, offset), value.AsRegister<CpuRegister>());
+            }
           } else {
             DCHECK(value.IsConstant()) << value;
             int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+            // `value_type == Primitive::kPrimNot` implies `v == 0`.
+            DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
+            // Note: if heap poisoning is enabled, no need to poison
+            // (negate) `v` if it is a reference, as it would be null.
             __ movl(Address(obj, offset), Immediate(v));
           }
         } else {
           DCHECK(index.IsRegister()) << index;
           if (value.IsRegister()) {
-            __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
-                    value.AsRegister<CpuRegister>());
+            if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
+              CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+              __ movl(temp, value.AsRegister<CpuRegister>());
+              __ PoisonHeapReference(temp);
+              __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset), temp);
+            } else {
+              __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
+                      value.AsRegister<CpuRegister>());
+            }
           } else {
             DCHECK(value.IsConstant()) << value;
             int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
+            // `value_type == Primitive::kPrimNot` implies `v == 0`.
+            DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
+            // Note: if heap poisoning is enabled, no need to poison
+            // (negate) `v` if it is a reference, as it would be null.
             __ movl(Address(obj, index.AsRegister<CpuRegister>(), TIMES_4, data_offset),
                     Immediate(v));
           }
@@ -3672,10 +3998,13 @@
           DCHECK_EQ(value_type, Primitive::kPrimNot);
           CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
           CpuRegister card = locations->GetTemp(1).AsRegister<CpuRegister>();
-          codegen_->MarkGCCard(temp, card, obj, value.AsRegister<CpuRegister>());
+          codegen_->MarkGCCard(
+              temp, card, obj, value.AsRegister<CpuRegister>(), instruction->GetValueCanBeNull());
         }
       } else {
         DCHECK_EQ(value_type, Primitive::kPrimNot);
+        // Note: if heap poisoning is enabled, pAputObject takes cares
+        // of poisoning the reference.
         __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject),
                                         true));
         DCHECK(!codegen_->IsLeafMethod());
@@ -3817,16 +4146,21 @@
 void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
                                      CpuRegister card,
                                      CpuRegister object,
-                                     CpuRegister value) {
+                                     CpuRegister value,
+                                     bool value_can_be_null) {
   Label is_null;
-  __ testl(value, value);
-  __ j(kEqual, &is_null);
+  if (value_can_be_null) {
+    __ testl(value, value);
+    __ j(kEqual, &is_null);
+  }
   __ gs()->movq(card, Address::Absolute(
       Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
   __ movq(temp, object);
   __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
-  __ movb(Address(temp, card, TIMES_1, 0),  card);
-  __ Bind(&is_null);
+  __ movb(Address(temp, card, TIMES_1, 0), card);
+  if (value_can_be_null) {
+    __ Bind(&is_null);
+  }
 }
 
 void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
@@ -4117,21 +4451,25 @@
       : LocationSummary::kNoCall;
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
-  CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>();
+  LocationSummary* locations = cls->GetLocations();
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+  CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
   if (cls->IsReferrersClass()) {
     DCHECK(!cls->CanCallRuntime());
     DCHECK(!cls->MustGenerateClinitCheck());
-    codegen_->LoadCurrentMethod(out);
-    __ movl(out, Address(out, ArtMethod::DeclaringClassOffset().Int32Value()));
+    __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
   } else {
     DCHECK(cls->CanCallRuntime());
-    codegen_->LoadCurrentMethod(out);
-    __ movl(out, Address(out, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
+    __ movl(out, Address(
+        current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
     __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+    __ MaybeUnpoisonHeapReference(out);
+
     SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64(
         cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
     codegen_->AddSlowPath(slow_path);
@@ -4166,6 +4504,7 @@
 void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+  locations->SetInAt(0, Location::RequiresRegister());
   locations->SetOut(Location::RequiresRegister());
 }
 
@@ -4173,11 +4512,14 @@
   SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
   codegen_->AddSlowPath(slow_path);
 
-  CpuRegister out = load->GetLocations()->Out().AsRegister<CpuRegister>();
-  codegen_->LoadCurrentMethod(CpuRegister(out));
-  __ movl(out, Address(out, ArtMethod::DeclaringClassOffset().Int32Value()));
+  LocationSummary* locations = load->GetLocations();
+  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
+  CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
+  __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
   __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
+  __ MaybeUnpoisonHeapReference(out);
   __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
+  __ MaybeUnpoisonHeapReference(out);
   __ testl(out, out);
   __ j(kEqual, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
@@ -4236,6 +4578,7 @@
   }
   // Compare the class of `obj` with `cls`.
   __ movl(out, Address(obj, class_offset));
+  __ MaybeUnpoisonHeapReference(out);
   if (cls.IsRegister()) {
     __ cmpl(out, cls.AsRegister<CpuRegister>());
   } else {
@@ -4294,13 +4637,15 @@
   }
   // Compare the class of `obj` with `cls`.
   __ movl(temp, Address(obj, class_offset));
+  __ MaybeUnpoisonHeapReference(temp);
   if (cls.IsRegister()) {
     __ cmpl(temp, cls.AsRegister<CpuRegister>());
   } else {
     DCHECK(cls.IsStackSlot()) << cls;
     __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
   }
-  // Classes must be equal for the checkcast to succeed.
+  // The checkcast succeeds if the classes are equal (fast path).
+  // Otherwise, we need to go into the slow path to check the types.
   __ j(kNotEqual, slow_path->GetEntryLabel());
   __ Bind(slow_path->GetExitLabel());
 }
@@ -4519,5 +4864,7 @@
   return Address::RIP(fixup);
 }
 
+#undef __
+
 }  // namespace x86_64
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 4be401a..4b90381 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -76,6 +76,8 @@
   virtual ~InvokeDexCallingConventionVisitorX86_64() {}
 
   Location GetNextLocation(Primitive::Type type) OVERRIDE;
+  Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
+  Location GetMethodLocation() const OVERRIDE;
 
  private:
   InvokeDexCallingConvention calling_convention;
@@ -132,10 +134,16 @@
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
   void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
  private:
   void HandleInvoke(HInvoke* invoke);
   void HandleBitwiseOperation(HBinaryOperation* operation);
@@ -156,10 +164,16 @@
 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
   void Visit##name(H##name* instr) OVERRIDE;
 
-  FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
+  FOR_EACH_CONCRETE_INSTRUCTION_X86_64(DECLARE_VISIT_INSTRUCTION)
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void VisitInstruction(HInstruction* instruction) OVERRIDE {
+    LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
+               << " (id " << instruction->GetId() << ")";
+  }
+
   X86_64Assembler* GetAssembler() const { return assembler_; }
 
  private:
@@ -169,14 +183,16 @@
   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);
   void GenerateDivRemIntegral(HBinaryOperation* instruction);
   void HandleShift(HBinaryOperation* operation);
   void GenerateMemoryBarrier(MemBarrierKind kind);
-  void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
+  void HandleFieldSet(HInstruction* instruction,
+                      const FieldInfo& field_info,
+                      bool value_can_be_null);
   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
   void GenerateImplicitNullCheck(HNullCheck* instruction);
   void GenerateExplicitNullCheck(HNullCheck* instruction);
@@ -186,6 +202,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 HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   X86_64Assembler* const assembler_;
   CodeGeneratorX86_64* const codegen_;
@@ -229,6 +252,10 @@
     return &assembler_;
   }
 
+  const X86_64Assembler& GetAssembler() const OVERRIDE {
+    return assembler_;
+  }
+
   ParallelMoveResolverX86_64* GetMoveResolver() OVERRIDE {
     return &move_resolver_;
   }
@@ -250,13 +277,15 @@
   }
 
   // Emit a write barrier.
-  void MarkGCCard(CpuRegister temp, CpuRegister card, CpuRegister object, CpuRegister value);
+  void MarkGCCard(CpuRegister temp,
+                  CpuRegister card,
+                  CpuRegister object,
+                  CpuRegister value,
+                  bool value_can_be_null);
 
   // Helper method to move a value between two locations.
   void Move(Location destination, Location source);
 
-  void LoadCurrentMethod(CpuRegister reg);
-
   Label* GetLabelOf(HBasicBlock* block) const {
     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
   }
@@ -269,7 +298,7 @@
     return false;
   }
 
-  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, CpuRegister temp);
+  void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
 
   const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const {
     return isa_features_;
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index 53f1f3c..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());
 }
@@ -218,6 +227,28 @@
   return Location::RequiresRegister();
 }
 
+// Check if registers in art register set have the same register code in vixl. If the register
+// codes are same, we can initialize vixl register list simply by the register masks. Currently,
+// only SP/WSP and ZXR/WZR codes are different between art and vixl.
+// Note: This function is only used for debug checks.
+static inline bool ArtVixlRegCodeCoherentForRegSet(uint32_t art_core_registers,
+                                                   size_t num_core,
+                                                   uint32_t art_fpu_registers,
+                                                   size_t num_fpu) {
+  // The register masks won't work if the number of register is larger than 32.
+  DCHECK_GE(sizeof(art_core_registers) * 8, num_core);
+  DCHECK_GE(sizeof(art_fpu_registers) * 8, num_fpu);
+  for (size_t art_reg_code = 0;  art_reg_code < num_core; ++art_reg_code) {
+    if (RegisterSet::Contains(art_core_registers, art_reg_code)) {
+      if (art_reg_code != static_cast<size_t>(VIXLRegCodeFromART(art_reg_code))) {
+        return false;
+      }
+    }
+  }
+  // There is no register code translation for float registers.
+  return true;
+}
+
 }  // namespace helpers
 }  // namespace arm64
 }  // namespace art
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index b7a92b5..20ce110 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -28,6 +28,7 @@
   void VisitShift(HBinaryOperation* shift);
 
   void VisitAnd(HAnd* instruction) OVERRIDE;
+  void VisitCompare(HCompare* instruction) OVERRIDE;
   void VisitMul(HMul* instruction) OVERRIDE;
   void VisitOr(HOr* instruction) OVERRIDE;
   void VisitRem(HRem* instruction) OVERRIDE;
@@ -70,6 +71,14 @@
           inst->ReplaceWith(constant);
           inst->GetBlock()->RemoveInstruction(inst);
         }
+      } else if (inst->IsTypeConversion()) {
+        // Constant folding: replace `TypeConversion(a)' with a constant at
+        // compile time if `a' is a constant.
+        HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
+        if (constant != nullptr) {
+          inst->ReplaceWith(constant);
+          inst->GetBlock()->RemoveInstruction(inst);
+        }
       } else if (inst->IsDivZeroCheck()) {
         // We can safely remove the check if the input is a non-null constant.
         HDivZeroCheck* check = inst->AsDivZeroCheck();
@@ -108,6 +117,26 @@
   }
 }
 
+void InstructionWithAbsorbingInputSimplifier::VisitCompare(HCompare* instruction) {
+  HConstant* input_cst = instruction->GetConstantRight();
+  if (input_cst != nullptr) {
+    HInstruction* input_value = instruction->GetLeastConstantLeft();
+    if (Primitive::IsFloatingPointType(input_value->GetType()) &&
+        ((input_cst->IsFloatConstant() && input_cst->AsFloatConstant()->IsNaN()) ||
+         (input_cst->IsDoubleConstant() && input_cst->AsDoubleConstant()->IsNaN()))) {
+      // Replace code looking like
+      //    CMP{G,L} dst, src, NaN
+      // with
+      //    CONSTANT +1 (gt bias)
+      // or
+      //    CONSTANT -1 (lt bias)
+      instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimInt,
+                                                       (instruction->IsGtBias() ? 1 : -1)));
+      instruction->GetBlock()->RemoveInstruction(instruction);
+    }
+  }
+}
+
 void InstructionWithAbsorbingInputSimplifier::VisitMul(HMul* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   Primitive::Type type = instruction->GetType();
diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h
index 66ff578..2698b2d 100644
--- a/compiler/optimizing/constant_folding.h
+++ b/compiler/optimizing/constant_folding.h
@@ -33,7 +33,7 @@
 class HConstantFolding : public HOptimization {
  public:
   explicit HConstantFolding(HGraph* graph, const char* name = kConstantFoldingPassName)
-      : HOptimization(graph, true, name) {}
+      : HOptimization(graph, name) {}
 
   void Run() OVERRIDE;
 
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index 2362cc1..5de629d 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -17,6 +17,7 @@
 #include "dead_code_elimination.h"
 
 #include "base/bit_vector-inl.h"
+#include "ssa_phi_elimination.h"
 
 namespace art {
 
@@ -130,7 +131,8 @@
       if (!inst->HasSideEffects()
           && !inst->CanThrow()
           && !inst->IsSuspendCheck()
-          && !inst->IsMemoryBarrier()  // If we added an explicit barrier then we should keep it.
+          // If we added an explicit barrier then we should keep it.
+          && !inst->IsMemoryBarrier()
           && !inst->HasUses()) {
         block->RemoveInstruction(inst);
         MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction);
@@ -141,6 +143,7 @@
 
 void HDeadCodeElimination::Run() {
   RemoveDeadBlocks();
+  SsaRedundantPhiElimination(graph_).Run();
   RemoveDeadInstructions();
 }
 
diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h
index 59a57c4..8d6008b 100644
--- a/compiler/optimizing/dead_code_elimination.h
+++ b/compiler/optimizing/dead_code_elimination.h
@@ -32,7 +32,7 @@
   HDeadCodeElimination(HGraph* graph,
                        OptimizingCompilerStats* stats = nullptr,
                        const char* name = kInitialDeadCodeEliminationPassName)
-      : HOptimization(graph, true, name, stats) {}
+      : HOptimization(graph, name, stats) {}
 
   void Run() OVERRIDE;
 
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 44c4101..9679d0a 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -81,7 +81,10 @@
   }
 
   // Ensure `block` ends with a branch instruction.
-  if (!block->EndsWithControlFlowInstruction()) {
+  // This invariant is not enforced on non-SSA graphs. Graph built from DEX with
+  // dead code that falls out of the method will not end with a control-flow
+  // instruction. Such code is removed during the SSA-building DCE phase.
+  if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) {
     AddError(StringPrintf("Block %d does not end with a branch instruction.",
                           block->GetBlockId()));
   }
@@ -253,6 +256,24 @@
   }
 }
 
+void GraphChecker::VisitReturn(HReturn* ret) {
+  VisitInstruction(ret);
+  if (!ret->GetBlock()->GetSingleSuccessor()->IsExitBlock()) {
+    AddError(StringPrintf("%s:%d does not jump to the exit block.",
+                          ret->DebugName(),
+                          ret->GetId()));
+  }
+}
+
+void GraphChecker::VisitReturnVoid(HReturnVoid* ret) {
+  VisitInstruction(ret);
+  if (!ret->GetBlock()->GetSingleSuccessor()->IsExitBlock()) {
+    AddError(StringPrintf("%s:%d does not jump to the exit block.",
+                          ret->DebugName(),
+                          ret->GetId()));
+  }
+}
+
 void GraphChecker::VisitCheckCast(HCheckCast* check) {
   VisitInstruction(check);
   HInstruction* input = check->InputAt(1);
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 9284bb7..7c72e23 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -52,6 +52,10 @@
   void VisitCheckCast(HCheckCast* check) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* check) OVERRIDE;
 
+  // Check that the Return and ReturnVoid jump to the exit block.
+  void VisitReturn(HReturn* ret) OVERRIDE;
+  void VisitReturnVoid(HReturnVoid* ret) OVERRIDE;
+
   // Was the last visit of the graph valid?
   bool IsValid() const {
     return errors_.empty();
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index f5c630b..37c060c 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -16,31 +16,161 @@
 
 #include "graph_visualizer.h"
 
+#include <dlfcn.h>
+
+#include <cctype>
+#include <sstream>
+
 #include "code_generator.h"
 #include "dead_code_elimination.h"
+#include "disassembler.h"
 #include "licm.h"
 #include "nodes.h"
 #include "optimization.h"
+#include "reference_type_propagation.h"
 #include "register_allocator.h"
 #include "ssa_liveness_analysis.h"
+#include "utils/assembler.h"
 
 namespace art {
 
+static bool HasWhitespace(const char* str) {
+  DCHECK(str != nullptr);
+  while (str[0] != 0) {
+    if (isspace(str[0])) {
+      return true;
+    }
+    str++;
+  }
+  return false;
+}
+
+class StringList {
+ public:
+  enum Format {
+    kArrayBrackets,
+    kSetBrackets,
+  };
+
+  // Create an empty list
+  explicit StringList(Format format = kArrayBrackets) : format_(format), is_empty_(true) {}
+
+  // Construct StringList from a linked list. List element class T
+  // must provide methods `GetNext` and `Dump`.
+  template<class T>
+  explicit StringList(T* first_entry, Format format = kArrayBrackets) : StringList(format) {
+    for (T* current = first_entry; current != nullptr; current = current->GetNext()) {
+      current->Dump(NewEntryStream());
+    }
+  }
+
+  std::ostream& NewEntryStream() {
+    if (is_empty_) {
+      is_empty_ = false;
+    } else {
+      sstream_ << ",";
+    }
+    return sstream_;
+  }
+
+ private:
+  Format format_;
+  bool is_empty_;
+  std::ostringstream sstream_;
+
+  friend std::ostream& operator<<(std::ostream& os, const StringList& list);
+};
+
+std::ostream& operator<<(std::ostream& os, const StringList& list) {
+  switch (list.format_) {
+    case StringList::kArrayBrackets: return os << "[" << list.sstream_.str() << "]";
+    case StringList::kSetBrackets:   return os << "{" << list.sstream_.str() << "}";
+    default:
+      LOG(FATAL) << "Invalid StringList format";
+      UNREACHABLE();
+  }
+}
+
+typedef Disassembler* create_disasm_prototype(InstructionSet instruction_set,
+                                              DisassemblerOptions* options);
+class HGraphVisualizerDisassembler {
+ public:
+  HGraphVisualizerDisassembler(InstructionSet instruction_set, const uint8_t* base_address)
+      : instruction_set_(instruction_set), disassembler_(nullptr) {
+    libart_disassembler_handle_ =
+        dlopen(kIsDebugBuild ? "libartd-disassembler.so" : "libart-disassembler.so", RTLD_NOW);
+    if (libart_disassembler_handle_ == nullptr) {
+      LOG(WARNING) << "Failed to dlopen libart-disassembler: " << dlerror();
+      return;
+    }
+    create_disasm_prototype* create_disassembler = reinterpret_cast<create_disasm_prototype*>(
+        dlsym(libart_disassembler_handle_, "create_disassembler"));
+    if (create_disassembler == nullptr) {
+      LOG(WARNING) << "Could not find create_disassembler entry: " << dlerror();
+      return;
+    }
+    // Reading the disassembly from 0x0 is easier, so we print relative
+    // addresses. We will only disassemble the code once everything has
+    // been generated, so we can read data in literal pools.
+    disassembler_ = std::unique_ptr<Disassembler>((*create_disassembler)(
+            instruction_set,
+            new DisassemblerOptions(/* absolute_addresses */ false,
+                                    base_address,
+                                    /* can_read_literals */ true)));
+  }
+
+  ~HGraphVisualizerDisassembler() {
+    // We need to call ~Disassembler() before we close the library.
+    disassembler_.reset();
+    if (libart_disassembler_handle_ != nullptr) {
+      dlclose(libart_disassembler_handle_);
+    }
+  }
+
+  void Disassemble(std::ostream& output, size_t start, size_t end) const {
+    if (disassembler_ == nullptr) {
+      return;
+    }
+
+    const uint8_t* base = disassembler_->GetDisassemblerOptions()->base_address_;
+    if (instruction_set_ == kThumb2) {
+      // ARM and Thumb-2 use the same disassembler. The bottom bit of the
+      // address is used to distinguish between the two.
+      base += 1;
+    }
+    disassembler_->Dump(output, base + start, base + end);
+  }
+
+ private:
+  InstructionSet instruction_set_;
+  std::unique_ptr<Disassembler> disassembler_;
+
+  void* libart_disassembler_handle_;
+};
+
+
 /**
  * HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
  */
-class HGraphVisualizerPrinter : public HGraphVisitor {
+class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
  public:
   HGraphVisualizerPrinter(HGraph* graph,
                           std::ostream& output,
                           const char* pass_name,
                           bool is_after_pass,
-                          const CodeGenerator& codegen)
-      : HGraphVisitor(graph),
+                          const CodeGenerator& codegen,
+                          const DisassemblyInformation* disasm_info = nullptr)
+      : HGraphDelegateVisitor(graph),
         output_(output),
         pass_name_(pass_name),
         is_after_pass_(is_after_pass),
         codegen_(codegen),
+        disasm_info_(disasm_info),
+        disassembler_(disasm_info_ != nullptr
+                      ? new HGraphVisualizerDisassembler(
+                            codegen_.GetInstructionSet(),
+                            codegen_.GetAssembler().CodeBufferBaseAddress())
+                      : nullptr),
         indent_(0) {}
 
   void StartTag(const char* name) {
@@ -112,6 +242,9 @@
       HBasicBlock* predecessor = block->GetPredecessors().Get(i);
       output_ << " \"B" << predecessor->GetBlockId() << "\" ";
     }
+    if (block->IsEntryBlock() && (disasm_info_ != nullptr)) {
+      output_ << " \"" << kDisassemblyBlockFrameEntry << "\" ";
+    }
     output_<< std::endl;
   }
 
@@ -119,82 +252,145 @@
     AddIndent();
     output_ << "successors";
     for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) {
-      HBasicBlock* successor = block->GetSuccessors().Get(i);
-      output_ << " \"B" << successor->GetBlockId() << "\" ";
+      if (!block->IsExceptionalSuccessor(i)) {
+        HBasicBlock* successor = block->GetSuccessors().Get(i);
+        output_ << " \"B" << successor->GetBlockId() << "\" ";
+      }
     }
     output_<< std::endl;
   }
 
-  void DumpLocation(Location location) {
+  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() << "\" ";
+      }
+    }
+    if (block->IsExitBlock() &&
+        (disasm_info_ != nullptr) &&
+        !disasm_info_->GetSlowPathIntervals().empty()) {
+      output_ << " \"" << kDisassemblyBlockSlowPaths << "\" ";
+    }
+    output_<< std::endl;
+  }
+
+  void DumpLocation(std::ostream& stream, const Location& location) {
     if (location.IsRegister()) {
-      codegen_.DumpCoreRegister(output_, location.reg());
+      codegen_.DumpCoreRegister(stream, location.reg());
     } else if (location.IsFpuRegister()) {
-      codegen_.DumpFloatingPointRegister(output_, location.reg());
+      codegen_.DumpFloatingPointRegister(stream, location.reg());
     } else if (location.IsConstant()) {
-      output_ << "constant";
+      stream << "#";
       HConstant* constant = location.GetConstant();
       if (constant->IsIntConstant()) {
-        output_ << " " << constant->AsIntConstant()->GetValue();
+        stream << constant->AsIntConstant()->GetValue();
       } else if (constant->IsLongConstant()) {
-        output_ << " " << constant->AsLongConstant()->GetValue();
+        stream << constant->AsLongConstant()->GetValue();
       }
     } else if (location.IsInvalid()) {
-      output_ << "invalid";
+      stream << "invalid";
     } else if (location.IsStackSlot()) {
-      output_ << location.GetStackIndex() << "(sp)";
+      stream << location.GetStackIndex() << "(sp)";
     } else if (location.IsFpuRegisterPair()) {
-      codegen_.DumpFloatingPointRegister(output_, location.low());
-      output_ << " and ";
-      codegen_.DumpFloatingPointRegister(output_, location.high());
+      codegen_.DumpFloatingPointRegister(stream, location.low());
+      stream << "|";
+      codegen_.DumpFloatingPointRegister(stream, location.high());
     } else if (location.IsRegisterPair()) {
-      codegen_.DumpCoreRegister(output_, location.low());
-      output_ << " and ";
-      codegen_.DumpCoreRegister(output_, location.high());
+      codegen_.DumpCoreRegister(stream, location.low());
+      stream << "|";
+      codegen_.DumpCoreRegister(stream, location.high());
     } else if (location.IsUnallocated()) {
-      output_ << "<U>";
+      stream << "unallocated";
     } else {
       DCHECK(location.IsDoubleStackSlot());
-      output_ << "2x" << location.GetStackIndex() << "(sp)";
+      stream << "2x" << location.GetStackIndex() << "(sp)";
     }
   }
 
+  std::ostream& StartAttributeStream(const char* name = nullptr) {
+    if (name == nullptr) {
+      output_ << " ";
+    } else {
+      DCHECK(!HasWhitespace(name)) << "Checker does not allow spaces in attributes";
+      output_ << " " << name << ":";
+    }
+    return output_;
+  }
+
   void VisitParallelMove(HParallelMove* instruction) OVERRIDE {
-    output_ << " (";
+    StartAttributeStream("liveness") << instruction->GetLifetimePosition();
+    StringList moves;
     for (size_t i = 0, e = instruction->NumMoves(); i < e; ++i) {
       MoveOperands* move = instruction->MoveOperandsAt(i);
-      DumpLocation(move->GetSource());
-      output_ << " -> ";
-      DumpLocation(move->GetDestination());
-      if (i + 1 != e) {
-        output_ << ", ";
-      }
+      std::ostream& str = moves.NewEntryStream();
+      DumpLocation(str, move->GetSource());
+      str << "->";
+      DumpLocation(str, move->GetDestination());
     }
-    output_ << ")";
-    output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
+    StartAttributeStream("moves") <<  moves;
   }
 
   void VisitIntConstant(HIntConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitLongConstant(HLongConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitFloatConstant(HFloatConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitDoubleConstant(HDoubleConstant* instruction) OVERRIDE {
-    output_ << " " << instruction->GetValue();
+    StartAttributeStream() << instruction->GetValue();
   }
 
   void VisitPhi(HPhi* phi) OVERRIDE {
-    output_ << " " << phi->GetRegNumber();
+    StartAttributeStream("reg") << phi->GetRegNumber();
   }
 
   void VisitMemoryBarrier(HMemoryBarrier* barrier) OVERRIDE {
-    output_ << " " << barrier->GetBarrierKind();
+    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;
+  }
+
+  void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
+    StartAttributeStream("must_do_null_check") << std::boolalpha
+        << check_cast->MustDoNullCheck() << std::noboolalpha;
+  }
+
+  void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE {
+    StartAttributeStream("must_do_null_check") << std::boolalpha
+        << instance_of->MustDoNullCheck() << std::noboolalpha;
+  }
+
+  void VisitInvoke(HInvoke* invoke) OVERRIDE {
+    StartAttributeStream("dex_file_index") << invoke->GetDexMethodIndex();
+    StartAttributeStream("method_name") << PrettyMethod(
+        invoke->GetDexMethodIndex(), GetGraph()->GetDexFile(), /* with_signature */ false);
+  }
+
+  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
+    VisitInvoke(invoke);
+    StartAttributeStream("recursive") << std::boolalpha
+                                      << invoke->IsRecursive()
+                                      << std::noboolalpha;
+  }
+
+  void VisitTryBoundary(HTryBoundary* try_boundary) OVERRIDE {
+    StartAttributeStream("kind") << (try_boundary->IsEntry() ? "entry" : "exit");
   }
 
   bool IsPass(const char* name) {
@@ -203,71 +399,104 @@
 
   void PrintInstruction(HInstruction* instruction) {
     output_ << instruction->DebugName();
-    instruction->Accept(this);
     if (instruction->InputCount() > 0) {
-      output_ << " [ ";
-      for (HInputIterator inputs(instruction); !inputs.Done(); inputs.Advance()) {
-        output_ << GetTypeId(inputs.Current()->GetType()) << inputs.Current()->GetId() << " ";
+      StringList inputs;
+      for (HInputIterator it(instruction); !it.Done(); it.Advance()) {
+        inputs.NewEntryStream() << GetTypeId(it.Current()->GetType()) << it.Current()->GetId();
       }
-      output_ << "]";
+      StartAttributeStream() << inputs;
     }
+    instruction->Accept(this);
     if (instruction->HasEnvironment()) {
-      output_ << " (env:";
+      StringList envs;
       for (HEnvironment* environment = instruction->GetEnvironment();
            environment != nullptr;
            environment = environment->GetParent()) {
-        output_ << " [ ";
+        StringList vregs;
         for (size_t i = 0, e = environment->Size(); i < e; ++i) {
           HInstruction* insn = environment->GetInstructionAt(i);
           if (insn != nullptr) {
-            output_ << GetTypeId(insn->GetType()) << insn->GetId() << " ";
+            vregs.NewEntryStream() << GetTypeId(insn->GetType()) << insn->GetId();
           } else {
-            output_ << " _ ";
+            vregs.NewEntryStream() << "_";
           }
         }
-        output_ << "]";
+        envs.NewEntryStream() << vregs;
       }
-      output_ << ")";
+      StartAttributeStream("env") << envs;
     }
     if (IsPass(SsaLivenessAnalysis::kLivenessPassName)
         && is_after_pass_
         && instruction->GetLifetimePosition() != kNoLifetime) {
-      output_ << " (liveness: " << instruction->GetLifetimePosition();
+      StartAttributeStream("liveness") << instruction->GetLifetimePosition();
       if (instruction->HasLiveInterval()) {
-        output_ << " ";
-        const LiveInterval& interval = *instruction->GetLiveInterval();
-        interval.Dump(output_);
+        LiveInterval* interval = instruction->GetLiveInterval();
+        StartAttributeStream("ranges")
+            << StringList(interval->GetFirstRange(), StringList::kSetBrackets);
+        StartAttributeStream("uses") << StringList(interval->GetFirstUse());
+        StartAttributeStream("env_uses") << StringList(interval->GetFirstEnvironmentUse());
+        StartAttributeStream("is_fixed") << interval->IsFixed();
+        StartAttributeStream("is_split") << interval->IsSplit();
+        StartAttributeStream("is_low") << interval->IsLowInterval();
+        StartAttributeStream("is_high") << interval->IsHighInterval();
       }
-      output_ << ")";
     } else if (IsPass(RegisterAllocator::kRegisterAllocatorPassName) && is_after_pass_) {
+      StartAttributeStream("liveness") << instruction->GetLifetimePosition();
       LocationSummary* locations = instruction->GetLocations();
       if (locations != nullptr) {
-        output_ << " ( ";
+        StringList inputs;
         for (size_t i = 0; i < instruction->InputCount(); ++i) {
-          DumpLocation(locations->InAt(i));
-          output_ << " ";
+          DumpLocation(inputs.NewEntryStream(), locations->InAt(i));
         }
-        output_ << ")";
-        if (locations->Out().IsValid()) {
-          output_ << " -> ";
-          DumpLocation(locations->Out());
-        }
+        std::ostream& attr = StartAttributeStream("locations");
+        attr << inputs << "->";
+        DumpLocation(attr, locations->Out());
       }
-      output_ << " (liveness: " << instruction->GetLifetimePosition() << ")";
     } else if (IsPass(LICM::kLoopInvariantCodeMotionPassName)
                || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName)) {
-      output_ << " ( loop_header:";
       HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
       if (info == nullptr) {
-        output_ << "null )";
+        StartAttributeStream("loop") << "none";
       } else {
-        output_ << "B" << info->GetHeader()->GetBlockId() << " )";
+        StartAttributeStream("loop") << "B" << info->GetHeader()->GetBlockId();
+      }
+    } else if (IsPass(ReferenceTypePropagation::kReferenceTypePropagationPassName)
+               && is_after_pass_) {
+      if (instruction->GetType() == Primitive::kPrimNot) {
+        if (instruction->IsLoadClass()) {
+          ReferenceTypeInfo info = instruction->AsLoadClass()->GetLoadedClassRTI();
+          ScopedObjectAccess soa(Thread::Current());
+          if (info.GetTypeHandle().GetReference() != nullptr) {
+            StartAttributeStream("klass") << PrettyClass(info.GetTypeHandle().Get());
+          } else {
+            StartAttributeStream("klass") << "unresolved";
+          }
+        } else {
+          ReferenceTypeInfo info = instruction->GetReferenceTypeInfo();
+          if (info.IsTop()) {
+            StartAttributeStream("klass") << "java.lang.Object";
+          } else {
+            ScopedObjectAccess soa(Thread::Current());
+            StartAttributeStream("klass") << PrettyClass(info.GetTypeHandle().Get());
+          }
+          StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha;
+        }
+      }
+    }
+    if (disasm_info_ != nullptr) {
+      DCHECK(disassembler_ != nullptr);
+      // If the information is available, disassemble the code generated for
+      // this instruction.
+      auto it = disasm_info_->GetInstructionIntervals().find(instruction);
+      if (it != disasm_info_->GetInstructionIntervals().end()
+          && it->second.start != it->second.end) {
+        output_ << std::endl;
+        disassembler_->Disassemble(output_, it->second.start, it->second.end);
       }
     }
   }
 
   void PrintInstructions(const HInstructionList& list) {
-    const char* kEndInstructionMarker = "<|@";
     for (HInstructionIterator it(list); !it.Done(); it.Advance()) {
       HInstruction* instruction = it.Current();
       int bci = 0;
@@ -281,15 +510,87 @@
       output_ << bci << " " << num_uses << " "
               << GetTypeId(instruction->GetType()) << instruction->GetId() << " ";
       PrintInstruction(instruction);
+      output_ << " " << kEndInstructionMarker << std::endl;
+    }
+  }
+
+  void DumpStartOfDisassemblyBlock(const char* block_name,
+                                   int predecessor_index,
+                                   int successor_index) {
+    StartTag("block");
+    PrintProperty("name", block_name);
+    PrintInt("from_bci", -1);
+    PrintInt("to_bci", -1);
+    if (predecessor_index != -1) {
+      PrintProperty("predecessors", "B", predecessor_index);
+    } else {
+      PrintEmptyProperty("predecessors");
+    }
+    if (successor_index != -1) {
+      PrintProperty("successors", "B", successor_index);
+    } else {
+      PrintEmptyProperty("successors");
+    }
+    PrintEmptyProperty("xhandlers");
+    PrintEmptyProperty("flags");
+    StartTag("states");
+    StartTag("locals");
+    PrintInt("size", 0);
+    PrintProperty("method", "None");
+    EndTag("locals");
+    EndTag("states");
+    StartTag("HIR");
+  }
+
+  void DumpEndOfDisassemblyBlock() {
+    EndTag("HIR");
+    EndTag("block");
+  }
+
+  void DumpDisassemblyBlockForFrameEntry() {
+    DumpStartOfDisassemblyBlock(kDisassemblyBlockFrameEntry,
+                                -1,
+                                GetGraph()->GetEntryBlock()->GetBlockId());
+    output_ << "    0 0 disasm " << kDisassemblyBlockFrameEntry << " ";
+    GeneratedCodeInterval frame_entry = disasm_info_->GetFrameEntryInterval();
+    if (frame_entry.start != frame_entry.end) {
+      output_ << std::endl;
+      disassembler_->Disassemble(output_, frame_entry.start, frame_entry.end);
+    }
+    output_ << kEndInstructionMarker << std::endl;
+    DumpEndOfDisassemblyBlock();
+  }
+
+  void DumpDisassemblyBlockForSlowPaths() {
+    if (disasm_info_->GetSlowPathIntervals().empty()) {
+      return;
+    }
+    // If the graph has an exit block we attach the block for the slow paths
+    // after it. Else we just add the block to the graph without linking it to
+    // any other.
+    DumpStartOfDisassemblyBlock(
+        kDisassemblyBlockSlowPaths,
+        GetGraph()->HasExitBlock() ? GetGraph()->GetExitBlock()->GetBlockId() : -1,
+        -1);
+    for (SlowPathCodeInfo info : disasm_info_->GetSlowPathIntervals()) {
+      output_ << "    0 0 disasm " << info.slow_path->GetDescription() << std::endl;
+      disassembler_->Disassemble(output_, info.code_interval.start, info.code_interval.end);
       output_ << kEndInstructionMarker << std::endl;
     }
+    DumpEndOfDisassemblyBlock();
   }
 
   void Run() {
     StartTag("cfg");
     std::string pass_desc = std::string(pass_name_) + (is_after_pass_ ? " (after)" : " (before)");
     PrintProperty("name", pass_desc.c_str());
+    if (disasm_info_ != nullptr) {
+      DumpDisassemblyBlockForFrameEntry();
+    }
     VisitInsertionOrder();
+    if (disasm_info_ != nullptr) {
+      DumpDisassemblyBlockForSlowPaths();
+    }
     EndTag("cfg");
   }
 
@@ -306,8 +607,14 @@
     }
     PrintPredecessors(block);
     PrintSuccessors(block);
-    PrintEmptyProperty("xhandlers");
-    PrintEmptyProperty("flags");
+    PrintExceptionHandlers(block);
+
+    if (block->IsCatchBlock()) {
+      PrintProperty("flags", "catch_block");
+    } else {
+      PrintEmptyProperty("flags");
+    }
+
     if (block->GetDominator() != nullptr) {
       PrintProperty("dominator", "B", block->GetDominator()->GetBlockId());
     }
@@ -336,11 +643,17 @@
     EndTag("block");
   }
 
+  static constexpr const char* const kEndInstructionMarker = "<|@";
+  static constexpr const char* const kDisassemblyBlockFrameEntry = "FrameEntry";
+  static constexpr const char* const kDisassemblyBlockSlowPaths = "SlowPaths";
+
  private:
   std::ostream& output_;
   const char* pass_name_;
   const bool is_after_pass_;
   const CodeGenerator& codegen_;
+  const DisassemblyInformation* disasm_info_;
+  std::unique_ptr<HGraphVisualizerDisassembler> disassembler_;
   size_t indent_;
 
   DISALLOW_COPY_AND_ASSIGN(HGraphVisualizerPrinter);
@@ -369,4 +682,13 @@
   }
 }
 
+void HGraphVisualizer::DumpGraphWithDisassembly() const {
+  DCHECK(output_ != nullptr);
+  if (!graph_->GetBlocks().IsEmpty()) {
+    HGraphVisualizerPrinter printer(
+        graph_, *output_, "disassembly", true, codegen_, codegen_.GetDisassemblyInformation());
+    printer.Run();
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 513bceb..b6b66df 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -19,6 +19,8 @@
 
 #include <ostream>
 
+#include "arch/instruction_set.h"
+#include "base/arena_containers.h"
 #include "base/value_object.h"
 
 namespace art {
@@ -26,11 +28,75 @@
 class CodeGenerator;
 class DexCompilationUnit;
 class HGraph;
+class HInstruction;
+class SlowPathCode;
 
 /**
  * This class outputs the HGraph in the C1visualizer format.
  * Note: Currently only works if the compiler is single threaded.
  */
+struct GeneratedCodeInterval {
+  size_t start;
+  size_t end;
+};
+
+struct SlowPathCodeInfo {
+  const SlowPathCode* slow_path;
+  GeneratedCodeInterval code_interval;
+};
+
+// This information is filled by the code generator. It will be used by the
+// graph visualizer to associate disassembly of the generated code with the
+// instructions and slow paths. We assume that the generated code follows the
+// following structure:
+//   - frame entry
+//   - instructions
+//   - slow paths
+class DisassemblyInformation {
+ public:
+  explicit DisassemblyInformation(ArenaAllocator* allocator)
+      : frame_entry_interval_({0, 0}),
+        instruction_intervals_(std::less<const HInstruction*>(), allocator->Adapter()),
+        slow_path_intervals_(allocator->Adapter()) {}
+
+  void SetFrameEntryInterval(size_t start, size_t end) {
+    frame_entry_interval_ = {start, end};
+  }
+
+  void AddInstructionInterval(HInstruction* instr, size_t start, size_t end) {
+    instruction_intervals_.Put(instr, {start, end});
+  }
+
+  void AddSlowPathInterval(SlowPathCode* slow_path, size_t start, size_t end) {
+    slow_path_intervals_.push_back({slow_path, {start, end}});
+  }
+
+  GeneratedCodeInterval GetFrameEntryInterval() const {
+    return frame_entry_interval_;
+  }
+
+  GeneratedCodeInterval* GetFrameEntryInterval() {
+    return &frame_entry_interval_;
+  }
+
+  const ArenaSafeMap<const HInstruction*, GeneratedCodeInterval>& GetInstructionIntervals() const {
+    return instruction_intervals_;
+  }
+
+  ArenaSafeMap<const HInstruction*, GeneratedCodeInterval>* GetInstructionIntervals() {
+    return &instruction_intervals_;
+  }
+
+  const ArenaVector<SlowPathCodeInfo>& GetSlowPathIntervals() const { return slow_path_intervals_; }
+
+  ArenaVector<SlowPathCodeInfo>* GetSlowPathIntervals() { return &slow_path_intervals_; }
+
+ private:
+  GeneratedCodeInterval frame_entry_interval_;
+  ArenaSafeMap<const HInstruction*, GeneratedCodeInterval> instruction_intervals_;
+  ArenaVector<SlowPathCodeInfo> slow_path_intervals_;
+};
+
 class HGraphVisualizer : public ValueObject {
  public:
   HGraphVisualizer(std::ostream* output,
@@ -39,6 +105,7 @@
 
   void PrintHeader(const char* method_name) const;
   void DumpGraph(const char* pass_name, bool is_after_pass = true) const;
+  void DumpGraphWithDisassembly() const;
 
  private:
   std::ostream* const output_;
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index e74d969..14a503b 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -27,7 +27,7 @@
 class GVNOptimization : public HOptimization {
  public:
   GVNOptimization(HGraph* graph, const SideEffectsAnalysis& side_effects)
-      : HOptimization(graph, true, kGlobalValueNumberingPassName), side_effects_(side_effects) {}
+      : HOptimization(graph, kGlobalValueNumberingPassName), side_effects_(side_effects) {}
 
   void Run() OVERRIDE;
 
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index c3ce7e1..d8a09ff 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -40,23 +40,40 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
 
-  block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
-          MemberOffset(42), false));
-  block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
-          MemberOffset(42), false));
+  block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimNot,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
+  block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimNot,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
   HInstruction* to_remove = block->GetLastInstruction();
-  block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
-          MemberOffset(43), false));
+  block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimNot,
+                                                           MemberOffset(43),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
   HInstruction* different_offset = block->GetLastInstruction();
   // Kill the value.
-  block->AddInstruction(new (&allocator) HInstanceFieldSet(
-      parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
-  block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot,
-          MemberOffset(42), false));
+  block->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
+                                                           parameter,
+                                                           Primitive::kPrimNot,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
+  block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimNot,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
   HInstruction* use_after_kill = block->GetLastInstruction();
   block->AddInstruction(new (&allocator) HExit());
 
@@ -88,9 +105,12 @@
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block);
   entry->AddSuccessor(block);
-  block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimBoolean,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
 
   block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
   HBasicBlock* then = new (&allocator) HBasicBlock(graph);
@@ -105,17 +125,26 @@
   then->AddSuccessor(join);
   else_->AddSuccessor(join);
 
-  then->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  then->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                          Primitive::kPrimBoolean,
+                                                          MemberOffset(42),
+                                                          false,
+                                                          kUnknownFieldIndex,
+                                                          graph->GetDexFile()));
   then->AddInstruction(new (&allocator) HGoto());
-  else_->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  else_->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimBoolean,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
   else_->AddInstruction(new (&allocator) HGoto());
-  join->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  join->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                          Primitive::kPrimBoolean,
+                                                          MemberOffset(42),
+                                                          false,
+                                                          kUnknownFieldIndex,
+                                                          graph->GetDexFile()));
   join->AddInstruction(new (&allocator) HExit());
 
   graph->TryBuildingSsa();
@@ -144,9 +173,12 @@
   HBasicBlock* block = new (&allocator) HBasicBlock(graph);
   graph->AddBlock(block);
   entry->AddSuccessor(block);
-  block->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                           Primitive::kPrimBoolean,
+                                                           MemberOffset(42),
+                                                           false,
+                                                           kUnknownFieldIndex,
+                                                           graph->GetDexFile()));
   block->AddInstruction(new (&allocator) HGoto());
 
   HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
@@ -161,26 +193,40 @@
   loop_header->AddSuccessor(exit);
   loop_body->AddSuccessor(loop_header);
 
-  loop_header->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  loop_header->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                                 Primitive::kPrimBoolean,
+                                                                 MemberOffset(42),
+                                                                 false,
+                                                                 kUnknownFieldIndex,
+                                                                 graph->GetDexFile()));
   HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
   loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
 
   // Kill inside the loop body to prevent field gets inside the loop header
   // and the body to be GVN'ed.
-  loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(
-      parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
+  loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
+                                                               parameter,
+                                                               Primitive::kPrimNot,
+                                                               MemberOffset(42),
+                                                               false,
+                                                               kUnknownFieldIndex,
+                                                               graph->GetDexFile()));
   HInstruction* field_set = loop_body->GetLastInstruction();
-  loop_body->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  loop_body->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                               Primitive::kPrimBoolean,
+                                                               MemberOffset(42),
+                                                               false,
+                                                               kUnknownFieldIndex,
+                                                               graph->GetDexFile()));
   HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
   loop_body->AddInstruction(new (&allocator) HGoto());
 
-  exit->AddInstruction(
-      new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean,
-          MemberOffset(42), false));
+  exit->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
+                                                          Primitive::kPrimBoolean,
+                                                          MemberOffset(42),
+                                                          false,
+                                                          kUnknownFieldIndex,
+                                                          graph->GetDexFile()));
   HInstruction* field_get_in_exit = exit->GetLastInstruction();
   exit->AddInstruction(new (&allocator) HExit());
 
@@ -266,8 +312,13 @@
   // Check that the loops don't have side effects.
   {
     // Make one block with a side effect.
-    entry->AddInstruction(new (&allocator) HInstanceFieldSet(
-        parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false));
+    entry->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
+                                                             parameter,
+                                                             Primitive::kPrimNot,
+                                                             MemberOffset(42),
+                                                             false,
+                                                             kUnknownFieldIndex,
+                                                             graph->GetDexFile()));
 
     SideEffectsAnalysis side_effects(graph);
     side_effects.Run();
@@ -280,8 +331,13 @@
   // Check that the side effects of the outer loop does not affect the inner loop.
   {
     outer_loop_body->InsertInstructionBefore(
-        new (&allocator) HInstanceFieldSet(
-            parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
+        new (&allocator) HInstanceFieldSet(parameter,
+                                           parameter,
+                                           Primitive::kPrimNot,
+                                           MemberOffset(42),
+                                           false,
+                                           kUnknownFieldIndex,
+                                           graph->GetDexFile()),
         outer_loop_body->GetLastInstruction());
 
     SideEffectsAnalysis side_effects(graph);
@@ -297,8 +353,13 @@
   {
     outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
     inner_loop_body->InsertInstructionBefore(
-        new (&allocator) HInstanceFieldSet(
-            parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false),
+        new (&allocator) HInstanceFieldSet(parameter,
+                                           parameter,
+                                           Primitive::kPrimNot,
+                                           MemberOffset(42),
+                                           false,
+                                           kUnknownFieldIndex,
+                                           graph->GetDexFile()),
         inner_loop_body->GetLastInstruction());
 
     SideEffectsAnalysis side_effects(graph);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index eeb1636..3efe7c7 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -28,6 +28,7 @@
 #include "mirror/dex_cache.h"
 #include "nodes.h"
 #include "optimizing_compiler.h"
+#include "reference_type_propagation.h"
 #include "register_allocator.h"
 #include "ssa_phi_elimination.h"
 #include "scoped_thread_state_change.h"
@@ -37,8 +38,8 @@
 
 namespace art {
 
-static constexpr int kMaxInlineCodeUnits = 100;
-static constexpr int kDepthLimit = 5;
+static constexpr int kMaxInlineCodeUnits = 18;
+static constexpr int kDepthLimit = 3;
 
 void HInliner::Run() {
   if (graph_->IsDebuggable()) {
@@ -47,11 +48,18 @@
     return;
   }
   const GrowableArray<HBasicBlock*>& blocks = graph_->GetReversePostOrder();
+  HBasicBlock* next_block = blocks.Get(0);
   for (size_t i = 0; i < blocks.Size(); ++i) {
-    HBasicBlock* block = blocks.Get(i);
+    // Because we are changing the graph when inlining, we need to remember the next block.
+    // This avoids doing the inlining work again on the inlined blocks.
+    if (blocks.Get(i) != next_block) {
+      continue;
+    }
+    HBasicBlock* block = next_block;
+    next_block = (i == blocks.Size() - 1) ? nullptr : blocks.Get(i + 1);
     for (HInstruction* instruction = block->GetFirstInstruction(); instruction != nullptr;) {
       HInstruction* next = instruction->GetNext();
-      HInvokeStaticOrDirect* call = instruction->AsInvokeStaticOrDirect();
+      HInvoke* call = instruction->AsInvoke();
       // As long as the call is not intrinsified, it is worth trying to inline.
       if (call != nullptr && call->GetIntrinsic() == Intrinsics::kNone) {
         // We use the original invoke type to ensure the resolution of the called method
@@ -63,6 +71,13 @@
             bool should_inline = callee_name.find("$inline$") != std::string::npos;
             CHECK(!should_inline) << "Could not inline " << callee_name;
           }
+        } else {
+          if (kIsDebugBuild && IsCompilingWithCoreImage()) {
+            std::string callee_name =
+                PrettyMethod(call->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile());
+            bool must_not_inline = callee_name.find("$noinline$") != std::string::npos;
+            CHECK(!must_not_inline) << "Should not have inlined " << callee_name;
+          }
         }
       }
       instruction = next;
@@ -70,6 +85,93 @@
   }
 }
 
+static bool IsMethodOrDeclaringClassFinal(ArtMethod* method)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return method->IsFinal() || method->GetDeclaringClass()->IsFinal();
+}
+
+/**
+ * Given the `resolved_method` looked up in the dex cache, try to find
+ * the actual runtime target of an interface or virtual call.
+ * Return nullptr if the runtime target cannot be proven.
+ */
+static ArtMethod* FindVirtualOrInterfaceTarget(HInvoke* invoke, ArtMethod* resolved_method)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (IsMethodOrDeclaringClassFinal(resolved_method)) {
+    // No need to lookup further, the resolved method will be the target.
+    return resolved_method;
+  }
+
+  HInstruction* receiver = invoke->InputAt(0);
+  if (receiver->IsNullCheck()) {
+    // Due to multiple levels of inlining within the same pass, it might be that
+    // null check does not have the reference type of the actual receiver.
+    receiver = receiver->InputAt(0);
+  }
+  ReferenceTypeInfo info = receiver->GetReferenceTypeInfo();
+  if (info.IsTop()) {
+    // We have no information on the receiver.
+    return nullptr;
+  } else if (!info.IsExact()) {
+    // We currently only support inlining with known receivers.
+    // TODO: Remove this check, we should be able to inline final methods
+    // on unknown receivers.
+    return nullptr;
+  } else if (info.GetTypeHandle()->IsInterface()) {
+    // Statically knowing that the receiver has an interface type cannot
+    // help us find what is the target method.
+    return nullptr;
+  } else if (!resolved_method->GetDeclaringClass()->IsAssignableFrom(info.GetTypeHandle().Get())) {
+    // The method that we're trying to call is not in the receiver's class or super classes.
+    return nullptr;
+  }
+
+  ClassLinker* cl = Runtime::Current()->GetClassLinker();
+  size_t pointer_size = cl->GetImagePointerSize();
+  if (invoke->IsInvokeInterface()) {
+    resolved_method = info.GetTypeHandle()->FindVirtualMethodForInterface(
+        resolved_method, pointer_size);
+  } else {
+    DCHECK(invoke->IsInvokeVirtual());
+    resolved_method = info.GetTypeHandle()->FindVirtualMethodForVirtual(
+        resolved_method, pointer_size);
+  }
+
+  if (resolved_method == nullptr) {
+    // The information we had on the receiver was not enough to find
+    // the target method. Since we check above the exact type of the receiver,
+    // the only reason this can happen is an IncompatibleClassChangeError.
+    return nullptr;
+  } else if (resolved_method->IsAbstract()) {
+    // The information we had on the receiver was not enough to find
+    // the target method. Since we check above the exact type of the receiver,
+    // the only reason this can happen is an IncompatibleClassChangeError.
+    return nullptr;
+  } else if (IsMethodOrDeclaringClassFinal(resolved_method)) {
+    // A final method has to be the target method.
+    return resolved_method;
+  } else if (info.IsExact()) {
+    // If we found a method and the receiver's concrete type is statically
+    // known, we know for sure the target.
+    return resolved_method;
+  } else {
+    // Even if we did find a method, the receiver type was not enough to
+    // statically find the runtime target.
+    return nullptr;
+  }
+}
+
+static uint32_t FindMethodIndexIn(ArtMethod* method,
+                                  const DexFile& dex_file,
+                                  uint32_t referrer_index)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (method->GetDexFile()->GetLocation().compare(dex_file.GetLocation()) == 0) {
+    return method->GetDexMethodIndex();
+  } else {
+    return method->FindDexMethodIndexInOtherDexFile(dex_file, referrer_index);
+  }
+}
+
 bool HInliner::TryInline(HInvoke* invoke_instruction, uint32_t method_index) const {
   ScopedObjectAccess soa(Thread::Current());
   const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
@@ -86,10 +188,29 @@
     return false;
   }
 
-  bool can_use_dex_cache = true;
+  if (!invoke_instruction->IsInvokeStaticOrDirect()) {
+    resolved_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method);
+    if (resolved_method == nullptr) {
+      VLOG(compiler) << "Interface or virtual call to "
+                     << PrettyMethod(method_index, caller_dex_file)
+                     << " could not be statically determined";
+      return false;
+    }
+    // We have found a method, but we need to find where that method is for the caller's
+    // dex file.
+    method_index = FindMethodIndexIn(resolved_method, caller_dex_file, method_index);
+    if (method_index == DexFile::kDexNoIndex) {
+      VLOG(compiler) << "Interface or virtual call to "
+                     << PrettyMethod(resolved_method)
+                     << " cannot be inlined because unaccessible to caller";
+      return false;
+    }
+  }
+
+  bool same_dex_file = true;
   const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile();
   if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) {
-    can_use_dex_cache = false;
+    same_dex_file = false;
   }
 
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
@@ -136,7 +257,7 @@
     return false;
   }
 
-  if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index, can_use_dex_cache)) {
+  if (!TryBuildAndInline(resolved_method, invoke_instruction, same_dex_file)) {
     return false;
   }
 
@@ -147,11 +268,11 @@
 
 bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
                                  HInvoke* invoke_instruction,
-                                 uint32_t method_index,
-                                 bool can_use_dex_cache) const {
+                                 bool same_dex_file) const {
   ScopedObjectAccess soa(Thread::Current());
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
-  const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
+  const DexFile& callee_dex_file = *resolved_method->GetDexFile();
+  uint32_t method_index = resolved_method->GetDexMethodIndex();
 
   DexCompilationUnit dex_compilation_unit(
     nullptr,
@@ -164,11 +285,38 @@
     resolved_method->GetAccessFlags(),
     nullptr);
 
+  bool requires_ctor_barrier = false;
+
+  if (dex_compilation_unit.IsConstructor()) {
+    // If it's a super invocation and we already generate a barrier there's no need
+    // to generate another one.
+    // We identify super calls by looking at the "this" pointer. If its value is the
+    // same as the local "this" pointer then we must have a super invocation.
+    bool is_super_invocation = invoke_instruction->InputAt(0)->IsParameterValue()
+        && invoke_instruction->InputAt(0)->AsParameterValue()->IsThis();
+    if (is_super_invocation && graph_->ShouldGenerateConstructorBarrier()) {
+      requires_ctor_barrier = false;
+    } else {
+      Thread* self = Thread::Current();
+      requires_ctor_barrier = compiler_driver_->RequiresConstructorBarrier(self,
+          dex_compilation_unit.GetDexFile(),
+          dex_compilation_unit.GetClassDefIndex());
+    }
+  }
+
+  InvokeType invoke_type = invoke_instruction->GetOriginalInvokeType();
+  if (invoke_type == kInterface) {
+    // We have statically resolved the dispatch. To please the class linker
+    // at runtime, we change this call as if it was a virtual call.
+    invoke_type = kVirtual;
+  }
   HGraph* callee_graph = new (graph_->GetArena()) HGraph(
       graph_->GetArena(),
-      caller_dex_file,
+      callee_dex_file,
       method_index,
+      requires_ctor_barrier,
       compiler_driver_->GetInstructionSet(),
+      invoke_type,
       graph_->IsDebuggable(),
       graph_->GetCurrentInstructionId());
 
@@ -181,7 +329,7 @@
                         &inline_stats);
 
   if (!builder.BuildGraph(*code_item)) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be built, so cannot be inlined";
     // There could be multiple reasons why the graph could not be built, including
     // unaccessible methods/fields due to using a different dex cache. We do not mark
@@ -191,14 +339,14 @@
 
   if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph,
                                                   compiler_driver_->GetInstructionSet())) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " cannot be inlined because of the register allocator";
     resolved_method->SetShouldNotInline();
     return false;
   }
 
   if (!callee_graph->TryBuildingSsa()) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be transformed to SSA";
     resolved_method->SetShouldNotInline();
     return false;
@@ -207,11 +355,13 @@
   // Run simple optimizations on the graph.
   HDeadCodeElimination dce(callee_graph, stats_);
   HConstantFolding fold(callee_graph);
+  ReferenceTypePropagation type_propagation(callee_graph, handles_);
   InstructionSimplifier simplify(callee_graph, stats_);
 
   HOptimization* optimizations[] = {
     &dce,
     &fold,
+    &type_propagation,
     &simplify,
   };
 
@@ -225,17 +375,43 @@
                      outer_compilation_unit_,
                      dex_compilation_unit,
                      compiler_driver_,
+                     handles_,
                      stats_,
                      depth_ + 1);
     inliner.Run();
   }
 
+  // TODO: We should abort only if all predecessors throw. However,
+  // HGraph::InlineInto currently does not handle an exit block with
+  // a throw predecessor.
+  HBasicBlock* exit_block = callee_graph->GetExitBlock();
+  if (exit_block == nullptr) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                   << " could not be inlined because it has an infinite loop";
+    resolved_method->SetShouldNotInline();
+    return false;
+  }
+
+  bool has_throw_predecessor = false;
+  for (size_t i = 0, e = exit_block->GetPredecessors().Size(); i < e; ++i) {
+    if (exit_block->GetPredecessors().Get(i)->GetLastInstruction()->IsThrow()) {
+      has_throw_predecessor = true;
+      break;
+    }
+  }
+  if (has_throw_predecessor) {
+    VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                   << " could not be inlined because one branch always throws";
+    resolved_method->SetShouldNotInline();
+    return false;
+  }
+
   HReversePostOrderIterator it(*callee_graph);
   it.Advance();  // Past the entry block, it does not contain instructions that prevent inlining.
   for (; !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     if (block->IsLoopHeader()) {
-      VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+      VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                      << " could not be inlined because it contains a loop";
       resolved_method->SetShouldNotInline();
       return false;
@@ -245,26 +421,25 @@
          !instr_it.Done();
          instr_it.Advance()) {
       HInstruction* current = instr_it.Current();
-      if (current->IsSuspendCheck()) {
-        continue;
-      }
 
-      if (current->CanThrow()) {
-        VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
-                       << " could not be inlined because " << current->DebugName()
-                       << " can throw";
+      if (current->IsInvokeInterface()) {
+        // Disable inlining of interface calls. The cost in case of entering the
+        // resolution conflict is currently too high.
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                       << " could not be inlined because it has an interface call.";
+        resolved_method->SetShouldNotInline();
         return false;
       }
 
-      if (current->NeedsEnvironment()) {
-        VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+      if (!same_dex_file && current->NeedsEnvironment()) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                        << " could not be inlined because " << current->DebugName()
-                       << " needs an environment";
+                       << " needs an environment and is in a different dex file";
         return false;
       }
 
-      if (!can_use_dex_cache && current->NeedsDexCache()) {
-        VLOG(compiler) << "Method " << PrettyMethod(method_index, caller_dex_file)
+      if (!same_dex_file && current->NeedsDexCache()) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                        << " could not be inlined because " << current->DebugName()
                        << " it is in a different dex file and requires access to the dex cache";
         // Do not flag the method as not-inlineable. A caller within the same
@@ -276,10 +451,6 @@
 
   callee_graph->InlineInto(graph_, invoke_instruction);
 
-  if (callee_graph->HasBoundsChecks()) {
-    graph_->SetHasBoundsChecks(true);
-  }
-
   return true;
 }
 
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 4602e77..ffd7569 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -34,13 +34,15 @@
            const DexCompilationUnit& outer_compilation_unit,
            const DexCompilationUnit& caller_compilation_unit,
            CompilerDriver* compiler_driver,
+           StackHandleScopeCollection* handles,
            OptimizingCompilerStats* stats,
            size_t depth = 0)
-      : HOptimization(outer_graph, true, kInlinerPassName, stats),
+      : HOptimization(outer_graph, kInlinerPassName, stats),
         outer_compilation_unit_(outer_compilation_unit),
         caller_compilation_unit_(caller_compilation_unit),
         compiler_driver_(compiler_driver),
-        depth_(depth) {}
+        depth_(depth),
+        handles_(handles) {}
 
   void Run() OVERRIDE;
 
@@ -50,13 +52,13 @@
   bool TryInline(HInvoke* invoke_instruction, uint32_t method_index) const;
   bool TryBuildAndInline(ArtMethod* resolved_method,
                          HInvoke* invoke_instruction,
-                         uint32_t method_index,
-                         bool can_use_dex_cache) const;
+                         bool same_dex_file) const;
 
   const DexCompilationUnit& outer_compilation_unit_;
   const DexCompilationUnit& caller_compilation_unit_;
   CompilerDriver* const compiler_driver_;
   const size_t depth_;
+  StackHandleScopeCollection* const handles_;
 
   DISALLOW_COPY_AND_ASSIGN(HInliner);
 };
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 0ca676a..337cf5b 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -45,6 +45,8 @@
   void VisitEqual(HEqual* equal) OVERRIDE;
   void VisitNotEqual(HNotEqual* equal) OVERRIDE;
   void VisitBooleanNot(HBooleanNot* bool_not) OVERRIDE;
+  void VisitInstanceFieldSet(HInstanceFieldSet* equal) OVERRIDE;
+  void VisitStaticFieldSet(HStaticFieldSet* equal) OVERRIDE;
   void VisitArraySet(HArraySet* equal) OVERRIDE;
   void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
   void VisitNullCheck(HNullCheck* instruction) OVERRIDE;
@@ -52,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;
@@ -63,6 +70,7 @@
   void VisitUShr(HUShr* instruction) OVERRIDE;
   void VisitXor(HXor* instruction) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE;
+  bool IsDominatedByInputNullCheck(HInstruction* instr);
 
   OptimizingCompilerStats* stats_;
   bool simplification_occurred_ = false;
@@ -78,6 +86,8 @@
 }
 
 void InstructionSimplifierVisitor::Run() {
+  // Iterate in reverse post order to open up more simplifications to users
+  // of instructions that got simplified.
   for (HReversePostOrderIterator it(*GetGraph()); !it.Done();) {
     // The simplification of an instruction to another instruction may yield
     // possibilities for other simplifications. So although we perform a reverse
@@ -170,33 +180,119 @@
   }
 }
 
-void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
-  HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass();
-  if (!check_cast->InputAt(0)->CanBeNull()) {
-    check_cast->ClearMustDoNullCheck();
+bool InstructionSimplifierVisitor::IsDominatedByInputNullCheck(HInstruction* instr) {
+  HInstruction* input = instr->InputAt(0);
+  for (HUseIterator<HInstruction*> it(input->GetUses()); !it.Done(); it.Advance()) {
+    HInstruction* use = it.Current()->GetUser();
+    if (use->IsNullCheck() && use->StrictlyDominates(instr)) {
+      return true;
+    }
   }
+  return false;
+}
 
-  if (!load_class->IsResolved()) {
+// Returns whether doing a type test between the class of `object` against `klass` has
+// a statically known outcome. The result of the test is stored in `outcome`.
+static bool TypeCheckHasKnownOutcome(HLoadClass* klass, HInstruction* object, bool* outcome) {
+  if (!klass->IsResolved()) {
     // If the class couldn't be resolve it's not safe to compare against it. It's
     // default type would be Top which might be wider that the actual class type
     // and thus producing wrong results.
-    return;
+    return false;
   }
-  ReferenceTypeInfo obj_rti = check_cast->InputAt(0)->GetReferenceTypeInfo();
-  ReferenceTypeInfo class_rti = load_class->GetLoadedClassRTI();
+
+  ReferenceTypeInfo obj_rti = object->GetReferenceTypeInfo();
+  ReferenceTypeInfo class_rti = klass->GetLoadedClassRTI();
   ScopedObjectAccess soa(Thread::Current());
   if (class_rti.IsSupertypeOf(obj_rti)) {
+    *outcome = true;
+    return true;
+  } else if (obj_rti.IsExact()) {
+    // The test failed at compile time so will also fail at runtime.
+    *outcome = false;
+    return true;
+  } else if (!class_rti.IsInterface()
+             && !obj_rti.IsInterface()
+             && !obj_rti.IsSupertypeOf(class_rti)) {
+    // Different type hierarchy. The test will fail.
+    *outcome = false;
+    return true;
+  }
+  return false;
+}
+
+void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) {
+  HInstruction* object = check_cast->InputAt(0);
+  if (!object->CanBeNull() || IsDominatedByInputNullCheck(check_cast)) {
+    check_cast->ClearMustDoNullCheck();
+  }
+
+  if (object->IsNullConstant()) {
     check_cast->GetBlock()->RemoveInstruction(check_cast);
     if (stats_ != nullptr) {
       stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
     }
+    return;
+  }
+
+  bool outcome;
+  if (TypeCheckHasKnownOutcome(check_cast->InputAt(1)->AsLoadClass(), object, &outcome)) {
+    if (outcome) {
+      check_cast->GetBlock()->RemoveInstruction(check_cast);
+      if (stats_ != nullptr) {
+        stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast);
+      }
+    } else {
+      // Don't do anything for exceptional cases for now. Ideally we should remove
+      // all instructions and blocks this instruction dominates.
+    }
   }
 }
 
 void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) {
-  if (!instruction->InputAt(0)->CanBeNull()) {
+  HInstruction* object = instruction->InputAt(0);
+  bool can_be_null = true;
+  if (!object->CanBeNull() || IsDominatedByInputNullCheck(instruction)) {
+    can_be_null = false;
     instruction->ClearMustDoNullCheck();
   }
+
+  HGraph* graph = GetGraph();
+  if (object->IsNullConstant()) {
+    instruction->ReplaceWith(graph->GetIntConstant(0));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+    RecordSimplification();
+    return;
+  }
+
+  bool outcome;
+  if (TypeCheckHasKnownOutcome(instruction->InputAt(1)->AsLoadClass(), object, &outcome)) {
+    if (outcome && can_be_null) {
+      // Type test will succeed, we just need a null test.
+      HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object);
+      instruction->GetBlock()->InsertInstructionBefore(test, instruction);
+      instruction->ReplaceWith(test);
+    } else {
+      // We've statically determined the result of the instanceof.
+      instruction->ReplaceWith(graph->GetIntConstant(outcome));
+    }
+    RecordSimplification();
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  }
+}
+
+void InstructionSimplifierVisitor::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
+  if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+      && !instruction->GetValue()->CanBeNull()) {
+    instruction->ClearValueCanBeNull();
+  }
+}
+
+void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruction) {
+  if ((instruction->GetValue()->GetType() == Primitive::kPrimNot)
+      && !instruction->GetValue()->CanBeNull()) {
+    instruction->ClearValueCanBeNull();
+  }
 }
 
 void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
@@ -233,8 +329,17 @@
         block->ReplaceAndRemoveInstructionWith(
             equal, new (block->GetGraph()->GetArena()) HBooleanNot(input_value));
         RecordSimplification();
+      } else {
+        // Replace (bool_value == integer_not_zero_nor_one_constant) with false
+        equal->ReplaceWith(GetGraph()->GetIntConstant(0));
+        block->RemoveInstruction(equal);
+        RecordSimplification();
       }
+    } else {
+      VisitCondition(equal);
     }
+  } else {
+    VisitCondition(equal);
   }
 }
 
@@ -256,8 +361,17 @@
         not_equal->ReplaceWith(input_value);
         block->RemoveInstruction(not_equal);
         RecordSimplification();
+      } else {
+        // Replace (bool_value != integer_not_zero_nor_one_constant) with true
+        not_equal->ReplaceWith(GetGraph()->GetIntConstant(1));
+        block->RemoveInstruction(not_equal);
+        RecordSimplification();
       }
+    } else {
+      VisitCondition(not_equal);
     }
+  } else {
+    VisitCondition(not_equal);
   }
 }
 
@@ -296,6 +410,14 @@
       instruction->ClearNeedsTypeCheck();
     }
   }
+
+  if (value->IsNullConstant()) {
+    instruction->ClearNeedsTypeCheck();
+  }
+
+  if (!value->CanBeNull()) {
+    instruction->ClearValueCanBeNull();
+  }
 }
 
 void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
@@ -376,6 +498,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 only supported on x86 and x86_64.
+  // TODO: Implement it for ARM, ARM64 and MIPS64.
+  InstructionSet instruction_set = GetGraph()->GetInstructionSet();
+  if (instruction_set != kX86 && instruction_set != kX86_64) {
+    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();
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index 0244620..faee2dd 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -31,11 +31,14 @@
   InstructionSimplifier(HGraph* graph,
                         OptimizingCompilerStats* stats = nullptr,
                         const char* name = kInstructionSimplifierPassName)
-    : HOptimization(graph, true, name, stats) {}
+    : HOptimization(graph, name, stats) {}
 
   static constexpr const char* kInstructionSimplifierPassName = "instruction_simplifier";
 
   void Run() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InstructionSimplifier);
 };
 
 }  // namespace art
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 9e18f11..8ef13e1 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -327,9 +327,6 @@
 
 // TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
 void IntrinsicsRecognizer::Run() {
-  DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(dex_file_);
-  DCHECK(inliner != nullptr);
-
   for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
     HBasicBlock* block = it.Current();
     for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
@@ -338,6 +335,9 @@
       if (inst->IsInvoke()) {
         HInvoke* invoke = inst->AsInvoke();
         InlineMethod method;
+        DexFileMethodInliner* inliner =
+            driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
+        DCHECK(inliner != nullptr);
         if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
           Intrinsics intrinsic = GetIntrinsic(method);
 
@@ -345,7 +345,7 @@
             if (!CheckInvokeType(intrinsic, invoke)) {
               LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
                            << intrinsic << " for "
-                           << PrettyMethod(invoke->GetDexMethodIndex(), *dex_file_);
+                           << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
             } else {
               invoke->SetIntrinsic(intrinsic);
             }
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index c243ef3..9044982 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -30,16 +30,15 @@
 // Recognize intrinsics from HInvoke nodes.
 class IntrinsicsRecognizer : public HOptimization {
  public:
-  IntrinsicsRecognizer(HGraph* graph, const DexFile* dex_file, CompilerDriver* driver)
-      : HOptimization(graph, true, kIntrinsicsRecognizerPassName),
-        dex_file_(dex_file), driver_(driver) {}
+  IntrinsicsRecognizer(HGraph* graph, CompilerDriver* driver)
+      : HOptimization(graph, kIntrinsicsRecognizerPassName),
+        driver_(driver) {}
 
   void Run() OVERRIDE;
 
   static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
 
  private:
-  const DexFile* dex_file_;
   CompilerDriver* driver_;
 
   DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index db35b8f..b4dbf75 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -101,7 +101,8 @@
     MoveArguments(invoke_, codegen);
 
     if (invoke_->IsInvokeStaticOrDirect()) {
-      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), kArtMethodRegister);
+      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
+                                          Location::RegisterLocation(kArtMethodRegister));
       RecordPcInfo(codegen, invoke_, invoke_->GetDexPc());
     } else {
       UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
@@ -120,6 +121,8 @@
     __ b(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathARM"; }
+
  private:
   // The instruction where this slow path is happening.
   HInvoke* const invoke_;
@@ -507,6 +510,11 @@
   if (is_volatile) {
     __ dmb(ISH);
   }
+
+  if (type == Primitive::kPrimNot) {
+    Register trg = locations->Out().AsRegister<Register>();
+    __ MaybeUnpoisonHeapReference(trg);
+  }
 }
 
 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -646,8 +654,15 @@
       __ strd(value_lo, Address(IP));
     }
   } else {
-    value =  locations->InAt(3).AsRegister<Register>();
-    __ str(value, Address(base, offset));
+    value = locations->InAt(3).AsRegister<Register>();
+    Register source = value;
+    if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+      Register temp = locations->GetTemp(0).AsRegister<Register>();
+      __ Mov(temp, value);
+      __ PoisonHeapReference(temp);
+      source = temp;
+    }
+    __ str(source, Address(base, offset));
   }
 
   if (is_volatile) {
@@ -657,7 +672,8 @@
   if (type == Primitive::kPrimNot) {
     Register temp = locations->GetTemp(0).AsRegister<Register>();
     Register card = locations->GetTemp(1).AsRegister<Register>();
-    codegen->MarkGCCard(temp, card, base, value);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(temp, card, base, value, value_can_be_null);
   }
 }
 
@@ -725,7 +741,8 @@
   if (type == Primitive::kPrimNot) {
     // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
     // object and scan the receiver at the next GC for nothing.
-    codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null);
   }
 
   // Prevent reordering with prior memory operations.
@@ -733,6 +750,11 @@
 
   __ add(tmp_ptr, base, ShifterOperand(offset));
 
+  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    codegen->GetAssembler()->PoisonHeapReference(expected_lo);
+    codegen->GetAssembler()->PoisonHeapReference(value_lo);
+  }
+
   // do {
   //   tmp = [r_ptr] - expected;
   // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
@@ -756,6 +778,11 @@
   __ rsbs(out, tmp_lo, ShifterOperand(1));
   __ it(CC);
   __ mov(out, ShifterOperand(0), CC);
+
+  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    codegen->GetAssembler()->UnpoisonHeapReference(value_lo);
+    codegen->GetAssembler()->UnpoisonHeapReference(expected_lo);
+  }
 }
 
 void IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) {
@@ -1042,5 +1069,9 @@
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
 
+#undef UNIMPLEMENTED_INTRINSIC
+
+#undef __
+
 }  // namespace arm
 }  // namespace art
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 957373f..78ac167 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -110,7 +110,8 @@
     MoveArguments(invoke_, codegen);
 
     if (invoke_->IsInvokeStaticOrDirect()) {
-      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), kArtMethodRegister);
+      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
+                                          LocationFrom(kArtMethodRegister));
       RecordPcInfo(codegen, invoke_, invoke_->GetDexPc());
     } else {
       UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
@@ -129,6 +130,8 @@
     __ B(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathARM64"; }
+
  private:
   // The instruction where this slow path is happening.
   HInvoke* const invoke_;
@@ -680,6 +683,11 @@
   } else {
     codegen->Load(type, trg, mem_op);
   }
+
+  if (type == Primitive::kPrimNot) {
+    DCHECK(trg.IsW());
+    codegen->GetAssembler()->MaybeUnpoisonHeapReference(trg);
+  }
 }
 
 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -778,26 +786,42 @@
   Register base = WRegisterFrom(locations->InAt(1));    // Object pointer.
   Register offset = XRegisterFrom(locations->InAt(2));  // Long offset.
   Register value = RegisterFrom(locations->InAt(3), type);
+  Register source = value;
   bool use_acquire_release = codegen->GetInstructionSetFeatures().PreferAcquireRelease();
 
   MemOperand mem_op(base.X(), offset);
 
-  if (is_volatile || is_ordered) {
-    if (use_acquire_release) {
-      codegen->StoreRelease(type, value, mem_op);
-    } else {
-      __ Dmb(InnerShareable, BarrierAll);
-      codegen->Store(type, value, mem_op);
-      if (is_volatile) {
-        __ Dmb(InnerShareable, BarrierReads);
-      }
+  {
+    // We use a block to end the scratch scope before the write barrier, thus
+    // freeing the temporary registers so they can be used in `MarkGCCard`.
+    UseScratchRegisterScope temps(masm);
+
+    if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+      DCHECK(value.IsW());
+      Register temp = temps.AcquireW();
+      __ Mov(temp.W(), value.W());
+      codegen->GetAssembler()->PoisonHeapReference(temp.W());
+      source = temp;
     }
-  } else {
-    codegen->Store(type, value, mem_op);
+
+    if (is_volatile || is_ordered) {
+      if (use_acquire_release) {
+        codegen->StoreRelease(type, source, mem_op);
+      } else {
+        __ Dmb(InnerShareable, BarrierAll);
+        codegen->Store(type, source, mem_op);
+        if (is_volatile) {
+          __ Dmb(InnerShareable, BarrierReads);
+        }
+      }
+    } else {
+      codegen->Store(type, source, mem_op);
+    }
   }
 
   if (type == Primitive::kPrimNot) {
-    codegen->MarkGCCard(base, value);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(base, value, value_can_be_null);
   }
 }
 
@@ -856,7 +880,8 @@
   // This needs to be before the temp registers, as MarkGCCard also uses VIXL temps.
   if (type == Primitive::kPrimNot) {
     // Mark card for object assuming new value is stored.
-    codegen->MarkGCCard(base, value);
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
+    codegen->MarkGCCard(base, value, value_can_be_null);
   }
 
   UseScratchRegisterScope temps(masm);
@@ -867,6 +892,11 @@
 
   __ Add(tmp_ptr, base.X(), Operand(offset));
 
+  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    codegen->GetAssembler()->PoisonHeapReference(expected);
+    codegen->GetAssembler()->PoisonHeapReference(value);
+  }
+
   // do {
   //   tmp_value = [tmp_ptr] - expected;
   // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
@@ -892,6 +922,11 @@
   }
   __ Bind(&exit_loop);
   __ Cset(out, eq);
+
+  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    codegen->GetAssembler()->UnpoisonHeapReference(value);
+    codegen->GetAssembler()->UnpoisonHeapReference(expected);
+  }
 }
 
 void IntrinsicLocationsBuilderARM64::VisitUnsafeCASInt(HInvoke* invoke) {
@@ -1168,5 +1203,9 @@
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
 
+#undef UNIMPLEMENTED_INTRINSIC
+
+#undef __
+
 }  // namespace arm64
 }  // namespace art
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 989dd0d..0d6ca09 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -138,7 +138,8 @@
     MoveArguments(invoke_, codegen);
 
     if (invoke_->IsInvokeStaticOrDirect()) {
-      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), EAX);
+      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
+                                          Location::RegisterLocation(EAX));
       RecordPcInfo(codegen, invoke_, invoke_->GetDexPc());
     } else {
       UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
@@ -157,6 +158,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathX86"; }
+
  private:
   // The instruction where this slow path is happening.
   HInvoke* const invoke_;
@@ -732,7 +735,8 @@
   MoveArguments(invoke, codegen);
 
   DCHECK(invoke->IsInvokeStaticOrDirect());
-  codegen->GenerateStaticOrDirectCall(invoke->AsInvokeStaticOrDirect(), EAX);
+  codegen->GenerateStaticOrDirectCall(invoke->AsInvokeStaticOrDirect(),
+                                      Location::RegisterLocation(EAX));
   codegen->RecordPcInfo(invoke, invoke->GetDexPc());
 
   // Copy the result back to the expected output.
@@ -1331,9 +1335,14 @@
 
   switch (type) {
     case Primitive::kPrimInt:
-    case Primitive::kPrimNot:
-      __ movl(output.AsRegister<Register>(), Address(base, offset, ScaleFactor::TIMES_1, 0));
+    case Primitive::kPrimNot: {
+      Register output_reg = output.AsRegister<Register>();
+      __ movl(output_reg, Address(base, offset, ScaleFactor::TIMES_1, 0));
+      if (type == Primitive::kPrimNot) {
+        __ MaybeUnpoisonHeapReference(output_reg);
+      }
       break;
+    }
 
     case Primitive::kPrimLong: {
         Register output_lo = output.AsRegisterPairLow<Register>();
@@ -1432,7 +1441,7 @@
   locations->SetInAt(3, Location::RequiresRegister());
   if (type == Primitive::kPrimNot) {
     // Need temp registers for card-marking.
-    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     // Ensure the value is in a byte register.
     locations->AddTemp(Location::RegisterLocation(ECX));
   } else if (type == Primitive::kPrimLong && is_volatile) {
@@ -1494,6 +1503,11 @@
       __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
       __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
     }
+  } else if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    Register temp = locations->GetTemp(0).AsRegister<Register>();
+    __ movl(temp, value_loc.AsRegister<Register>());
+    __ PoisonHeapReference(temp);
+    __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), temp);
   } else {
     __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<Register>());
   }
@@ -1503,10 +1517,12 @@
   }
 
   if (type == Primitive::kPrimNot) {
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
                         locations->GetTemp(1).AsRegister<Register>(),
                         base,
-                        value_loc.AsRegister<Register>());
+                        value_loc.AsRegister<Register>(),
+                        value_can_be_null);
   }
 }
 
@@ -1598,14 +1614,22 @@
     __ LockCmpxchg8b(Address(base, offset, TIMES_1, 0));
   } else {
     // Integer or object.
-    DCHECK_EQ(locations->InAt(3).AsRegister<Register>(), EAX);
+    Register expected = locations->InAt(3).AsRegister<Register>();
+    DCHECK_EQ(expected, EAX);
     Register value = locations->InAt(4).AsRegister<Register>();
     if (type == Primitive::kPrimNot) {
       // Mark card for object assuming new value is stored.
+      bool value_can_be_null = true;  // TODO: Worth finding out this information?
       codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
                           locations->GetTemp(1).AsRegister<Register>(),
                           base,
-                          value);
+                          value,
+                          value_can_be_null);
+
+      if (kPoisonHeapReferences) {
+        __ PoisonHeapReference(expected);
+        __ PoisonHeapReference(value);
+      }
     }
 
     __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
@@ -1617,6 +1641,13 @@
   // Convert ZF into the boolean result.
   __ setb(kZero, out.AsRegister<Register>());
   __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
+
+  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    Register value = locations->InAt(4).AsRegister<Register>();
+    __ UnpoisonHeapReference(value);
+    // Do not unpoison the reference contained in register `expected`,
+    // as it is the same as register `out`.
+  }
 }
 
 void IntrinsicCodeGeneratorX86::VisitUnsafeCASInt(HInvoke* invoke) {
@@ -1726,5 +1757,9 @@
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 
+#undef UNIMPLEMENTED_INTRINSIC
+
+#undef __
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index c245cb6..ea342e9 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -129,7 +129,8 @@
     MoveArguments(invoke_, codegen);
 
     if (invoke_->IsInvokeStaticOrDirect()) {
-      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), CpuRegister(RDI));
+      codegen->GenerateStaticOrDirectCall(
+          invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(RDI));
       RecordPcInfo(codegen, invoke_, invoke_->GetDexPc());
     } else {
       UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
@@ -148,6 +149,8 @@
     __ jmp(GetExitLabel());
   }
 
+  const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathX86_64"; }
+
  private:
   // The instruction where this slow path is happening.
   HInvoke* const invoke_;
@@ -609,7 +612,8 @@
   MoveArguments(invoke, codegen);
 
   DCHECK(invoke->IsInvokeStaticOrDirect());
-  codegen->GenerateStaticOrDirectCall(invoke->AsInvokeStaticOrDirect(), CpuRegister(RDI));
+  codegen->GenerateStaticOrDirectCall(
+      invoke->AsInvokeStaticOrDirect(), Location::RegisterLocation(RDI));
   codegen->RecordPcInfo(invoke, invoke->GetDexPc());
 
   // Copy the result back to the expected output.
@@ -1247,6 +1251,9 @@
     case Primitive::kPrimInt:
     case Primitive::kPrimNot:
       __ movl(trg, Address(base, offset, ScaleFactor::TIMES_1, 0));
+      if (type == Primitive::kPrimNot) {
+        __ MaybeUnpoisonHeapReference(trg);
+      }
       break;
 
     case Primitive::kPrimLong:
@@ -1321,7 +1328,7 @@
   locations->SetInAt(3, Location::RequiresRegister());
   if (type == Primitive::kPrimNot) {
     // Need temp registers for card-marking.
-    locations->AddTemp(Location::RequiresRegister());
+    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
     locations->AddTemp(Location::RequiresRegister());
   }
 }
@@ -1365,6 +1372,11 @@
 
   if (type == Primitive::kPrimLong) {
     __ movq(Address(base, offset, ScaleFactor::TIMES_1, 0), value);
+  } else if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    CpuRegister temp = locations->GetTemp(0).AsRegister<CpuRegister>();
+    __ movl(temp, value);
+    __ PoisonHeapReference(temp);
+    __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), temp);
   } else {
     __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value);
   }
@@ -1374,10 +1386,12 @@
   }
 
   if (type == Primitive::kPrimNot) {
+    bool value_can_be_null = true;  // TODO: Worth finding out this information?
     codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
                         locations->GetTemp(1).AsRegister<CpuRegister>(),
                         base,
-                        value);
+                        value,
+                        value_can_be_null);
   }
 }
 
@@ -1459,10 +1473,17 @@
     // Integer or object.
     if (type == Primitive::kPrimNot) {
       // Mark card for object assuming new value is stored.
+      bool value_can_be_null = true;  // TODO: Worth finding out this information?
       codegen->MarkGCCard(locations->GetTemp(0).AsRegister<CpuRegister>(),
                           locations->GetTemp(1).AsRegister<CpuRegister>(),
                           base,
-                          value);
+                          value,
+                          value_can_be_null);
+
+      if (kPoisonHeapReferences) {
+        __ PoisonHeapReference(expected);
+        __ PoisonHeapReference(value);
+      }
     }
 
     __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
@@ -1474,6 +1495,11 @@
   // Convert ZF into the boolean result.
   __ setcc(kZero, out);
   __ movzxb(out, out);
+
+  if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
+    __ UnpoisonHeapReference(value);
+    __ UnpoisonHeapReference(expected);
+  }
 }
 
 void IntrinsicCodeGeneratorX86_64::VisitUnsafeCASInt(HInvoke* invoke) {
@@ -1590,5 +1616,9 @@
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 
+#undef UNIMPLEMENTED_INTRINSIC
+
+#undef __
+
 }  // namespace x86_64
 }  // namespace art
diff --git a/compiler/optimizing/licm.h b/compiler/optimizing/licm.h
index cb6170e..0b5a0f1 100644
--- a/compiler/optimizing/licm.h
+++ b/compiler/optimizing/licm.h
@@ -27,7 +27,7 @@
 class LICM : public HOptimization {
  public:
   LICM(HGraph* graph, const SideEffectsAnalysis& side_effects)
-      : HOptimization(graph, true, kLoopInvariantCodeMotionPassName), side_effects_(side_effects) {}
+      : HOptimization(graph, kLoopInvariantCodeMotionPassName), side_effects_(side_effects) {}
 
   void Run() OVERRIDE;
 
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 42aba04..d14dfc1 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -51,16 +51,17 @@
 }
 
 Location Location::RegisterOrInt32LongConstant(HInstruction* instruction) {
-  if (!instruction->IsConstant() || !instruction->AsConstant()->IsLongConstant()) {
+  if (instruction->IsIntConstant() || instruction->IsNullConstant()) {
+    return Location::ConstantLocation(instruction->AsConstant());
+  } else if (instruction->IsLongConstant()) {
+    // Does the long constant fit in a 32 bit int?
+    int64_t value = instruction->AsLongConstant()->GetValue();
+    return IsInt<32>(value)
+        ? Location::ConstantLocation(instruction->AsConstant())
+        : Location::RequiresRegister();
+  } else {
     return Location::RequiresRegister();
   }
-
-  // Does the long constant fit in a 32 bit int?
-  int64_t value = instruction->AsConstant()->AsLongConstant()->GetValue();
-
-  return IsInt<32>(value)
-      ? Location::ConstantLocation(instruction->AsConstant())
-      : Location::RequiresRegister();
 }
 
 Location Location::ByteRegisterOrConstant(int reg, HInstruction* instruction) {
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index 09bbb33..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);
   }
 
@@ -481,7 +481,6 @@
                   bool intrinsified = false);
 
   void SetInAt(uint32_t at, Location location) {
-    DCHECK(inputs_.Get(at).IsUnallocated() || inputs_.Get(at).IsInvalid());
     inputs_.Put(at, location);
   }
 
@@ -525,6 +524,8 @@
     return temps_.Size();
   }
 
+  bool HasTemps() const { return !temps_.IsEmpty(); }
+
   Location Out() const { return output_; }
 
   bool CanCall() const { return call_kind_ != kNoCall; }
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 88490d0..588ab70 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -16,6 +16,7 @@
 
 #include "nodes.h"
 
+#include "code_generator.h"
 #include "ssa_builder.h"
 #include "base/bit_vector-inl.h"
 #include "base/bit_utils.h"
@@ -188,15 +189,20 @@
   ssa_builder.BuildSsa();
 }
 
-void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
-  // Insert a new node between `block` and `successor` to split the
-  // critical edge.
+HBasicBlock* HGraph::SplitEdge(HBasicBlock* block, HBasicBlock* successor) {
   HBasicBlock* new_block = new (arena_) HBasicBlock(this, successor->GetDexPc());
   AddBlock(new_block);
-  new_block->AddInstruction(new (arena_) HGoto());
   // Use `InsertBetween` to ensure the predecessor index and successor index of
   // `block` and `successor` are preserved.
   new_block->InsertBetween(block, successor);
+  return new_block;
+}
+
+void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
+  // Insert a new node between `block` and `successor` to split the
+  // critical edge.
+  HBasicBlock* new_block = SplitEdge(block, successor);
+  new_block->AddInstruction(new (arena_) HGoto());
   if (successor->IsLoopHeader()) {
     // If we split at a back edge boundary, make the new block the back edge.
     HLoopInformation* info = successor->GetLoopInformation();
@@ -313,6 +319,23 @@
   return cached_null_constant_;
 }
 
+HCurrentMethod* HGraph::GetCurrentMethod() {
+  // For simplicity, don't bother reviving the cached current method if it is
+  // not null and not in a block. Otherwise, we need to clear the instruction
+  // id and/or any invariants the graph is assuming when adding new instructions.
+  if ((cached_current_method_ == nullptr) || (cached_current_method_->GetBlock() == nullptr)) {
+    cached_current_method_ = new (arena_) HCurrentMethod(
+        Is64BitInstructionSet(instruction_set_) ? Primitive::kPrimLong : Primitive::kPrimInt);
+    if (entry_block_->GetFirstInstruction() == nullptr) {
+      entry_block_->AddInstruction(cached_current_method_);
+    } else {
+      entry_block_->InsertInstructionBefore(
+          cached_current_method_, entry_block_->GetFirstInstruction());
+    }
+  }
+  return cached_current_method_;
+}
+
 HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) {
   switch (type) {
     case Primitive::Type::kPrimBoolean:
@@ -814,6 +837,84 @@
   }
 }
 
+HConstant* HTypeConversion::TryStaticEvaluation() const {
+  HGraph* graph = GetBlock()->GetGraph();
+  if (GetInput()->IsIntConstant()) {
+    int32_t value = GetInput()->AsIntConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimLong:
+        return graph->GetLongConstant(static_cast<int64_t>(value));
+      case Primitive::kPrimFloat:
+        return graph->GetFloatConstant(static_cast<float>(value));
+      case Primitive::kPrimDouble:
+        return graph->GetDoubleConstant(static_cast<double>(value));
+      default:
+        return nullptr;
+    }
+  } else if (GetInput()->IsLongConstant()) {
+    int64_t value = GetInput()->AsLongConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimInt:
+        return graph->GetIntConstant(static_cast<int32_t>(value));
+      case Primitive::kPrimFloat:
+        return graph->GetFloatConstant(static_cast<float>(value));
+      case Primitive::kPrimDouble:
+        return graph->GetDoubleConstant(static_cast<double>(value));
+      default:
+        return nullptr;
+    }
+  } else if (GetInput()->IsFloatConstant()) {
+    float value = GetInput()->AsFloatConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimInt:
+        if (std::isnan(value))
+          return graph->GetIntConstant(0);
+        if (value >= kPrimIntMax)
+          return graph->GetIntConstant(kPrimIntMax);
+        if (value <= kPrimIntMin)
+          return graph->GetIntConstant(kPrimIntMin);
+        return graph->GetIntConstant(static_cast<int32_t>(value));
+      case Primitive::kPrimLong:
+        if (std::isnan(value))
+          return graph->GetLongConstant(0);
+        if (value >= kPrimLongMax)
+          return graph->GetLongConstant(kPrimLongMax);
+        if (value <= kPrimLongMin)
+          return graph->GetLongConstant(kPrimLongMin);
+        return graph->GetLongConstant(static_cast<int64_t>(value));
+      case Primitive::kPrimDouble:
+        return graph->GetDoubleConstant(static_cast<double>(value));
+      default:
+        return nullptr;
+    }
+  } else if (GetInput()->IsDoubleConstant()) {
+    double value = GetInput()->AsDoubleConstant()->GetValue();
+    switch (GetResultType()) {
+      case Primitive::kPrimInt:
+        if (std::isnan(value))
+          return graph->GetIntConstant(0);
+        if (value >= kPrimIntMax)
+          return graph->GetIntConstant(kPrimIntMax);
+        if (value <= kPrimLongMin)
+          return graph->GetIntConstant(kPrimIntMin);
+        return graph->GetIntConstant(static_cast<int32_t>(value));
+      case Primitive::kPrimLong:
+        if (std::isnan(value))
+          return graph->GetLongConstant(0);
+        if (value >= kPrimLongMax)
+          return graph->GetLongConstant(kPrimLongMax);
+        if (value <= kPrimLongMin)
+          return graph->GetLongConstant(kPrimLongMin);
+        return graph->GetLongConstant(static_cast<int64_t>(value));
+      case Primitive::kPrimFloat:
+        return graph->GetFloatConstant(static_cast<float>(value));
+      default:
+        return nullptr;
+    }
+  }
+  return nullptr;
+}
+
 HConstant* HUnaryOperation::TryStaticEvaluation() const {
   if (GetInput()->IsIntConstant()) {
     int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
@@ -839,6 +940,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));
@@ -923,6 +1027,36 @@
   }
 }
 
+HBasicBlock* HBasicBlock::SplitBefore(HInstruction* cursor) {
+  DCHECK(!graph_->IsInSsaForm()) << "Support for SSA form not implemented";
+  DCHECK_EQ(cursor->GetBlock(), this);
+
+  HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(), GetDexPc());
+  new_block->instructions_.first_instruction_ = cursor;
+  new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
+  instructions_.last_instruction_ = cursor->previous_;
+  if (cursor->previous_ == nullptr) {
+    instructions_.first_instruction_ = nullptr;
+  } else {
+    cursor->previous_->next_ = nullptr;
+    cursor->previous_ = nullptr;
+  }
+
+  new_block->instructions_.SetBlockOfInstructions(new_block);
+  AddInstruction(new (GetGraph()->GetArena()) HGoto());
+
+  for (size_t i = 0, e = GetSuccessors().Size(); i < e; ++i) {
+    HBasicBlock* successor = GetSuccessors().Get(i);
+    new_block->successors_.Add(successor);
+    successor->predecessors_.Put(successor->GetPredecessorIndexOf(this), new_block);
+  }
+  successors_.Reset();
+  AddSuccessor(new_block);
+
+  GetGraph()->AddBlock(new_block);
+  return new_block;
+}
+
 HBasicBlock* HBasicBlock::SplitAfter(HInstruction* cursor) {
   DCHECK(!cursor->IsControlFlow());
   DCHECK_NE(instructions_.last_instruction_, cursor);
@@ -952,15 +1086,24 @@
   return new_block;
 }
 
+bool HBasicBlock::IsExceptionalSuccessor(size_t idx) const {
+  return !GetInstructions().IsEmpty()
+      && GetLastInstruction()->IsTryBoundary()
+      && GetLastInstruction()->AsTryBoundary()->IsExceptionalSuccessor(idx);
+}
+
+static bool HasOnlyOneInstruction(const HBasicBlock& block) {
+  return block.GetPhis().IsEmpty()
+      && !block.GetInstructions().IsEmpty()
+      && block.GetFirstInstruction() == block.GetLastInstruction();
+}
+
 bool HBasicBlock::IsSingleGoto() const {
-  HLoopInformation* loop_info = GetLoopInformation();
-  // TODO: Remove the null check b/19084197.
-  return GetFirstInstruction() != nullptr
-         && GetPhis().IsEmpty()
-         && GetFirstInstruction() == GetLastInstruction()
-         && GetLastInstruction()->IsGoto()
-         // Back edges generate the suspend check.
-         && (loop_info == nullptr || !loop_info->IsBackEdge(*this));
+  return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsGoto();
+}
+
+bool HBasicBlock::IsSingleTryBoundary() const {
+  return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsTryBoundary();
 }
 
 bool HBasicBlock::EndsWithControlFlowInstruction() const {
@@ -1217,11 +1360,39 @@
     block->RemovePhi(it.Current()->AsPhi());
   }
 
+  if (block->IsExitBlock()) {
+    exit_block_ = nullptr;
+  }
+
   reverse_post_order_.Delete(block);
   blocks_.Put(block->GetBlockId(), nullptr);
 }
 
 void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
+  DCHECK(HasExitBlock()) << "Unimplemented scenario";
+  // Update the environments in this graph to have the invoke's environment
+  // as parent.
+  {
+    HReversePostOrderIterator it(*this);
+    it.Advance();  // Skip the entry block, we do not need to update the entry's suspend check.
+    for (; !it.Done(); it.Advance()) {
+      HBasicBlock* block = it.Current();
+      for (HInstructionIterator instr_it(block->GetInstructions());
+           !instr_it.Done();
+           instr_it.Advance()) {
+        HInstruction* current = instr_it.Current();
+        if (current->NeedsEnvironment()) {
+          current->GetEnvironment()->SetAndCopyParentChain(
+              outer_graph->GetArena(), invoke->GetEnvironment());
+        }
+      }
+    }
+  }
+  outer_graph->UpdateMaximumNumberOfOutVRegs(GetMaximumNumberOfOutVRegs());
+  if (HasBoundsChecks()) {
+    outer_graph->SetHasBoundsChecks(true);
+  }
+
   if (GetBlocks().Size() == 3) {
     // Simple case of an entry block, a body block, and an exit block.
     // Put the body block's instruction into `invoke`'s block.
@@ -1382,6 +1553,8 @@
         DCHECK(parameter_index != last_input_index);
       }
       current->ReplaceWith(invoke->InputAt(parameter_index++));
+    } else if (current->IsCurrentMethod()) {
+      current->ReplaceWith(outer_graph->GetCurrentMethod());
     } else {
       DCHECK(current->IsGoto() || current->IsSuspendCheck());
       entry_block_->RemoveInstruction(current);
@@ -1477,4 +1650,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 f8149d1..59255d1 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -35,9 +35,11 @@
 
 class GraphChecker;
 class HBasicBlock;
+class HCurrentMethod;
 class HDoubleConstant;
 class HEnvironment;
 class HFloatConstant;
+class HGraphBuilder;
 class HGraphVisitor;
 class HInstruction;
 class HIntConstant;
@@ -60,6 +62,10 @@
 static constexpr uint32_t kMaxIntShiftValue = 0x1f;
 static constexpr uint64_t kMaxLongShiftValue = 0x3f;
 
+static constexpr uint32_t kUnknownFieldIndex = static_cast<uint32_t>(-1);
+
+static constexpr InvokeType kInvalidInvokeType = static_cast<InvokeType>(-1);
+
 enum IfCondition {
   kCondEQ,
   kCondNE,
@@ -120,7 +126,9 @@
   HGraph(ArenaAllocator* arena,
          const DexFile& dex_file,
          uint32_t method_idx,
+         bool should_generate_constructor_barrier,
          InstructionSet instruction_set,
+         InvokeType invoke_type = kInvalidInvokeType,
          bool debuggable = false,
          int start_instruction_id = 0)
       : arena_(arena),
@@ -138,19 +146,26 @@
         current_instruction_id_(start_instruction_id),
         dex_file_(dex_file),
         method_idx_(method_idx),
+        invoke_type_(invoke_type),
+        in_ssa_form_(false),
+        should_generate_constructor_barrier_(should_generate_constructor_barrier),
         instruction_set_(instruction_set),
         cached_null_constant_(nullptr),
         cached_int_constants_(std::less<int32_t>(), arena->Adapter()),
         cached_float_constants_(std::less<int32_t>(), arena->Adapter()),
         cached_long_constants_(std::less<int64_t>(), arena->Adapter()),
-        cached_double_constants_(std::less<int64_t>(), arena->Adapter()) {}
+        cached_double_constants_(std::less<int64_t>(), arena->Adapter()),
+        cached_current_method_(nullptr) {}
 
   ArenaAllocator* GetArena() const { return arena_; }
   const GrowableArray<HBasicBlock*>& GetBlocks() const { return blocks_; }
   HBasicBlock* GetBlock(size_t id) const { return blocks_.Get(id); }
 
+  bool IsInSsaForm() const { return in_ssa_form_; }
+
   HBasicBlock* GetEntryBlock() const { return entry_block_; }
   HBasicBlock* GetExitBlock() const { return exit_block_; }
+  bool HasExitBlock() const { return exit_block_ != nullptr; }
 
   void SetEntryBlock(HBasicBlock* block) { entry_block_ = block; }
   void SetExitBlock(HBasicBlock* block) { exit_block_ = block; }
@@ -167,6 +182,7 @@
     // users remaining when being visited.
     if (!AnalyzeNaturalLoops()) return false;
     TransformToSsa();
+    in_ssa_form_ = true;
     return true;
   }
 
@@ -192,6 +208,12 @@
   // Removes `block` from the graph.
   void DeleteDeadBlock(HBasicBlock* block);
 
+  // Splits the edge between `block` and `successor` while preserving the
+  // indices in the predecessor/successor lists. If there are multiple edges
+  // between the blocks, the lowest indices are used.
+  // Returns the new block which is empty and has the same dex pc as `successor`.
+  HBasicBlock* SplitEdge(HBasicBlock* block, HBasicBlock* successor);
+
   void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
   void SimplifyLoop(HBasicBlock* header);
 
@@ -216,11 +238,16 @@
     maximum_number_of_out_vregs_ = new_value;
   }
 
+  void UpdateMaximumNumberOfOutVRegs(uint16_t other_value) {
+    maximum_number_of_out_vregs_ = std::max(maximum_number_of_out_vregs_, other_value);
+  }
+
   void UpdateTemporariesVRegSlots(size_t slots) {
     temporaries_vreg_slots_ = std::max(slots, temporaries_vreg_slots_);
   }
 
   size_t GetTemporariesVRegSlots() const {
+    DCHECK(!in_ssa_form_);
     return temporaries_vreg_slots_;
   }
 
@@ -229,6 +256,7 @@
   }
 
   uint16_t GetNumberOfVRegs() const {
+    DCHECK(!in_ssa_form_);
     return number_of_vregs_;
   }
 
@@ -237,6 +265,7 @@
   }
 
   uint16_t GetNumberOfLocalVRegs() const {
+    DCHECK(!in_ssa_form_);
     return number_of_vregs_ - number_of_in_vregs_;
   }
 
@@ -256,6 +285,10 @@
     has_bounds_checks_ = value;
   }
 
+  bool ShouldGenerateConstructorBarrier() const {
+    return should_generate_constructor_barrier_;
+  }
+
   bool IsDebuggable() const { return debuggable_; }
 
   // Returns a constant of the given type and value. If it does not exist
@@ -276,6 +309,8 @@
     return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_);
   }
 
+  HCurrentMethod* GetCurrentMethod();
+
   HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
 
   const DexFile& GetDexFile() const {
@@ -286,6 +321,14 @@
     return method_idx_;
   }
 
+  InvokeType GetInvokeType() const {
+    return invoke_type_;
+  }
+
+  InstructionSet GetInstructionSet() const {
+    return instruction_set_;
+  }
+
  private:
   void VisitBlockForDominatorTree(HBasicBlock* block,
                                   HBasicBlock* predecessor,
@@ -308,6 +351,7 @@
     }
 
     // If not found or previously deleted, create and cache a new instruction.
+    // Don't bother reviving a previously deleted instruction, for simplicity.
     if (constant == nullptr || constant->GetBlock() == nullptr) {
       constant = new (arena_) InstructionType(value);
       cache->Overwrite(value, constant);
@@ -368,6 +412,16 @@
   // The method index in the dex file.
   const uint32_t method_idx_;
 
+  // If inlined, this encodes how the callee is being invoked.
+  const InvokeType invoke_type_;
+
+  // Whether the graph has been transformed to SSA form. Only used
+  // in debug mode to ensure we are not using properties only valid
+  // for non-SSA form (like the number of temporaries).
+  bool in_ssa_form_;
+
+  const bool should_generate_constructor_barrier_;
+
   const InstructionSet instruction_set_;
 
   // Cached constants.
@@ -377,6 +431,8 @@
   ArenaSafeMap<int64_t, HLongConstant*> cached_long_constants_;
   ArenaSafeMap<int64_t, HDoubleConstant*> cached_double_constants_;
 
+  HCurrentMethod* cached_current_method_;
+
   friend class SsaBuilder;           // For caching constants.
   friend class SsaLivenessAnalysis;  // For the linear order.
   ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
@@ -521,6 +577,15 @@
   }
 
   bool IsSingleGoto() const;
+  bool IsSingleTryBoundary() const;
+
+  // Returns true if this block emits nothing but a jump.
+  bool IsSingleJump() const {
+    HLoopInformation* loop_info = GetLoopInformation();
+    return (IsSingleGoto() || IsSingleTryBoundary())
+           // Back edges generate a suspend check.
+           && (loop_info == nullptr || !loop_info->IsBackEdge(*this));
+  }
 
   void AddBackEdge(HBasicBlock* back_edge) {
     if (loop_information_ == nullptr) {
@@ -629,7 +694,7 @@
     successors_.Put(1, temp);
   }
 
-  size_t GetPredecessorIndexOf(HBasicBlock* predecessor) {
+  size_t GetPredecessorIndexOf(HBasicBlock* predecessor) const {
     for (size_t i = 0, e = predecessors_.Size(); i < e; ++i) {
       if (predecessors_.Get(i) == predecessor) {
         return i;
@@ -638,7 +703,7 @@
     return -1;
   }
 
-  size_t GetSuccessorIndexOf(HBasicBlock* successor) {
+  size_t GetSuccessorIndexOf(HBasicBlock* successor) const {
     for (size_t i = 0, e = successors_.Size(); i < e; ++i) {
       if (successors_.Get(i) == successor) {
         return i;
@@ -647,6 +712,33 @@
     return -1;
   }
 
+  HBasicBlock* GetSinglePredecessor() const {
+    DCHECK_EQ(GetPredecessors().Size(), 1u);
+    return GetPredecessors().Get(0);
+  }
+
+  HBasicBlock* GetSingleSuccessor() const {
+    DCHECK_EQ(GetSuccessors().Size(), 1u);
+    return GetSuccessors().Get(0);
+  }
+
+  // Returns whether the first occurrence of `predecessor` in the list of
+  // predecessors is at index `idx`.
+  bool IsFirstIndexOfPredecessor(HBasicBlock* predecessor, size_t idx) const {
+    DCHECK_EQ(GetPredecessors().Get(idx), predecessor);
+    return GetPredecessorIndexOf(predecessor) == idx;
+  }
+
+  // Returns whether successor at index `idx` is an exception handler.
+  bool IsExceptionalSuccessor(size_t idx) const;
+
+  // 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
+  // graph, create a Goto at the end of the former block and will create an edge
+  // between the blocks. It will not, however, update the reverse post order or
+  // loop information.
+  HBasicBlock* SplitBefore(HInstruction* cursor);
+
   // Split the block into two blocks just after `cursor`. Returns the newly
   // created block. Note that this method just updates raw block information,
   // like predecessors, successors, dominators, and instruction list. It does not
@@ -802,7 +894,7 @@
   DISALLOW_COPY_AND_ASSIGN(HLoopInformationOutwardIterator);
 };
 
-#define FOR_EACH_CONCRETE_INSTRUCTION(M)                                \
+#define FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M)                         \
   M(Add, BinaryOperation)                                               \
   M(And, BinaryOperation)                                               \
   M(ArrayGet, Instruction)                                              \
@@ -815,6 +907,7 @@
   M(ClinitCheck, Instruction)                                           \
   M(Compare, BinaryOperation)                                           \
   M(Condition, BinaryOperation)                                         \
+  M(CurrentMethod, Instruction)                                         \
   M(Deoptimize, Instruction)                                            \
   M(Div, BinaryOperation)                                               \
   M(DivZeroCheck, Instruction)                                          \
@@ -867,10 +960,29 @@
   M(SuspendCheck, Instruction)                                          \
   M(Temporary, Instruction)                                             \
   M(Throw, Instruction)                                                 \
+  M(TryBoundary, Instruction)                                           \
   M(TypeConversion, Instruction)                                        \
   M(UShr, BinaryOperation)                                              \
   M(Xor, BinaryOperation)                                               \
 
+#define FOR_EACH_CONCRETE_INSTRUCTION_ARM(M)
+
+#define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M)
+
+#define FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M)
+
+#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)
+
+#define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M)
+
+#define FOR_EACH_CONCRETE_INSTRUCTION(M)                                \
+  FOR_EACH_CONCRETE_INSTRUCTION_COMMON(M)                               \
+  FOR_EACH_CONCRETE_INSTRUCTION_ARM(M)                                  \
+  FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M)                                \
+  FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M)                               \
+  FOR_EACH_CONCRETE_INSTRUCTION_X86(M)                                  \
+  FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M)
+
 #define FOR_EACH_INSTRUCTION(M)                                         \
   FOR_EACH_CONCRETE_INSTRUCTION(M)                                      \
   M(Constant, Instruction)                                              \
@@ -1117,13 +1229,17 @@
                size_t number_of_vregs,
                const DexFile& dex_file,
                uint32_t method_idx,
-               uint32_t dex_pc)
+               uint32_t dex_pc,
+               InvokeType invoke_type,
+               HInstruction* holder)
      : vregs_(arena, number_of_vregs),
        locations_(arena, number_of_vregs),
        parent_(nullptr),
        dex_file_(dex_file),
        method_idx_(method_idx),
-       dex_pc_(dex_pc) {
+       dex_pc_(dex_pc),
+       invoke_type_(invoke_type),
+       holder_(holder) {
     vregs_.SetSize(number_of_vregs);
     for (size_t i = 0; i < number_of_vregs; i++) {
       vregs_.Put(i, HUserRecord<HEnvironment*>());
@@ -1135,16 +1251,25 @@
     }
   }
 
+  HEnvironment(ArenaAllocator* arena, const HEnvironment& to_copy, HInstruction* holder)
+      : HEnvironment(arena,
+                     to_copy.Size(),
+                     to_copy.GetDexFile(),
+                     to_copy.GetMethodIdx(),
+                     to_copy.GetDexPc(),
+                     to_copy.GetInvokeType(),
+                     holder) {}
+
   void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
-    parent_ = new (allocator) HEnvironment(allocator,
-                                           parent->Size(),
-                                           parent->GetDexFile(),
-                                           parent->GetMethodIdx(),
-                                           parent->GetDexPc());
-    if (parent->GetParent() != nullptr) {
-      parent_->SetAndCopyParentChain(allocator, parent->GetParent());
+    if (parent_ != nullptr) {
+      parent_->SetAndCopyParentChain(allocator, parent);
+    } else {
+      parent_ = new (allocator) HEnvironment(allocator, *parent, holder_);
+      parent_->CopyFrom(parent);
+      if (parent->GetParent() != nullptr) {
+        parent_->SetAndCopyParentChain(allocator, parent->GetParent());
+      }
     }
-    parent_->CopyFrom(parent);
   }
 
   void CopyFrom(const GrowableArray<HInstruction*>& locals);
@@ -1185,10 +1310,18 @@
     return method_idx_;
   }
 
+  InvokeType GetInvokeType() const {
+    return invoke_type_;
+  }
+
   const DexFile& GetDexFile() const {
     return dex_file_;
   }
 
+  HInstruction* GetHolder() const {
+    return holder_;
+  }
+
  private:
   // Record instructions' use entries of this environment for constant-time removal.
   // It should only be called by HInstruction when a new environment use is added.
@@ -1204,6 +1337,11 @@
   const DexFile& dex_file_;
   const uint32_t method_idx_;
   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.
+  HInstruction* const holder_;
 
   friend class HInstruction;
 
@@ -1232,6 +1370,9 @@
 
   bool IsExact() const { return is_exact_; }
   bool IsTop() const { return is_top_; }
+  bool IsInterface() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return !IsTop() && GetTypeHandle()->IsInterface();
+  }
 
   Handle<mirror::Class> GetTypeHandle() const { return type_handle_; }
 
@@ -1411,18 +1552,18 @@
   HEnvironment* GetEnvironment() const { return environment_; }
   // Set the `environment_` field. Raw because this method does not
   // update the uses lists.
-  void SetRawEnvironment(HEnvironment* environment) { environment_ = environment; }
+  void SetRawEnvironment(HEnvironment* environment) {
+    DCHECK(environment_ == nullptr);
+    DCHECK_EQ(environment->GetHolder(), this);
+    environment_ = environment;
+  }
 
   // Set the environment of this instruction, copying it from `environment`. While
   // copying, the uses lists are being updated.
   void CopyEnvironmentFrom(HEnvironment* environment) {
+    DCHECK(environment_ == nullptr);
     ArenaAllocator* allocator = GetBlock()->GetGraph()->GetArena();
-    environment_ = new (allocator) HEnvironment(
-        allocator,
-        environment->Size(),
-        environment->GetDexFile(),
-        environment->GetMethodIdx(),
-        environment->GetDexPc());
+    environment_ = new (allocator) HEnvironment(allocator, *environment, this);
     environment_->CopyFrom(environment);
     if (environment->GetParent() != nullptr) {
       environment_->SetAndCopyParentChain(allocator, environment->GetParent());
@@ -1431,17 +1572,13 @@
 
   void CopyEnvironmentFromWithLoopPhiAdjustment(HEnvironment* environment,
                                                 HBasicBlock* block) {
+    DCHECK(environment_ == nullptr);
     ArenaAllocator* allocator = GetBlock()->GetGraph()->GetArena();
-    environment_ = new (allocator) HEnvironment(
-        allocator,
-        environment->Size(),
-        environment->GetDexFile(),
-        environment->GetMethodIdx(),
-        environment->GetDexPc());
+    environment_ = new (allocator) HEnvironment(allocator, *environment, this);
+    environment_->CopyFromWithLoopPhiAdjustment(environment, block);
     if (environment->GetParent() != nullptr) {
       environment_->SetAndCopyParentChain(allocator, environment->GetParent());
     }
-    environment_->CopyFromWithLoopPhiAdjustment(environment, block);
   }
 
   // Returns the number of entries in the environment. Typically, that is the
@@ -1526,6 +1663,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;
@@ -1772,7 +1917,7 @@
   bool IsControlFlow() const OVERRIDE { return true; }
 
   HBasicBlock* GetSuccessor() const {
-    return GetBlock()->GetSuccessors().Get(0);
+    return GetBlock()->GetSingleSuccessor();
   }
 
   DECLARE_INSTRUCTION(Goto);
@@ -1806,6 +1951,61 @@
   DISALLOW_COPY_AND_ASSIGN(HIf);
 };
 
+
+// Abstract instruction which marks the beginning and/or end of a try block and
+// links it to the respective exception handlers. Behaves the same as a Goto in
+// non-exceptional control flow.
+// Normal-flow successor is stored at index zero, exception handlers under
+// higher indices in no particular order.
+class HTryBoundary : public HTemplateInstruction<0> {
+ public:
+  enum BoundaryKind {
+    kEntry,
+    kExit,
+  };
+
+  explicit HTryBoundary(BoundaryKind kind)
+      : HTemplateInstruction(SideEffects::None()), kind_(kind) {}
+
+  bool IsControlFlow() const OVERRIDE { return true; }
+
+  // Returns the block's non-exceptional successor (index zero).
+  HBasicBlock* GetNormalFlowSuccessor() const { return GetBlock()->GetSuccessors().Get(0); }
+
+  // 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;
+  }
+
+  // If not present already, adds `handler` to its block's list of exception
+  // handlers.
+  void AddExceptionHandler(HBasicBlock* handler) {
+    if (!HasExceptionHandler(handler)) {
+      GetBlock()->AddSuccessor(handler);
+    }
+  }
+
+  bool IsEntry() const { return kind_ == BoundaryKind::kEntry; }
+
+  DECLARE_INSTRUCTION(TryBoundary);
+
+ private:
+  const BoundaryKind kind_;
+
+  DISALLOW_COPY_AND_ASSIGN(HTryBoundary);
+};
+
+
 // Deoptimize to interpreter, upon checking a condition.
 class HDeoptimize : public HTemplateInstruction<1> {
  public:
@@ -1827,6 +2027,19 @@
   DISALLOW_COPY_AND_ASSIGN(HDeoptimize);
 };
 
+// Represents the ArtMethod that was passed as a first argument to
+// the method. It is used by instructions that depend on it, like
+// instructions that work with the dex cache.
+class HCurrentMethod : public HExpression<0> {
+ public:
+  explicit HCurrentMethod(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
+
+  DECLARE_INSTRUCTION(CurrentMethod);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HCurrentMethod);
+};
+
 class HUnaryOperation : public HExpression<1> {
  public:
   HUnaryOperation(Primitive::Type result_type, HInstruction* input)
@@ -1934,11 +2147,20 @@
   DISALLOW_COPY_AND_ASSIGN(HBinaryOperation);
 };
 
+// The comparison bias applies for floating point operations and indicates how NaN
+// comparisons are treated:
+enum 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_(kNoBias) {}
 
   bool NeedsMaterialization() const { return needs_materialization_; }
   void ClearNeedsMaterialization() { needs_materialization_ = false; }
@@ -1951,11 +2173,24 @@
 
   virtual IfCondition GetCondition() const = 0;
 
+  virtual IfCondition GetOppositeCondition() const = 0;
+
+  bool IsGtBias() { return bias_ == kGtBias; }
+
+  void SetBias(ComparisonBias bias) { bias_ = bias; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return bias_ == other->AsCondition()->bias_;
+  }
+
  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);
 };
 
@@ -1980,6 +2215,10 @@
     return kCondEQ;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondNE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HEqual);
 };
@@ -2004,6 +2243,10 @@
     return kCondNE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondEQ;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HNotEqual);
 };
@@ -2026,6 +2269,10 @@
     return kCondLT;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondGE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HLessThan);
 };
@@ -2048,6 +2295,10 @@
     return kCondLE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondGT;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual);
 };
@@ -2070,6 +2321,10 @@
     return kCondGT;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondLE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HGreaterThan);
 };
@@ -2092,6 +2347,10 @@
     return kCondGE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondLT;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual);
 };
@@ -2101,18 +2360,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());
@@ -2137,6 +2388,8 @@
     return bias_ == other->AsCompare()->bias_;
   }
 
+  ComparisonBias GetBias() const { return bias_; }
+
   bool IsGtBias() { return bias_ == kGtBias; }
 
   uint32_t GetDexPc() const { return dex_pc_; }
@@ -2144,7 +2397,7 @@
   DECLARE_INSTRUCTION(Compare);
 
  private:
-  const Bias bias_;
+  const ComparisonBias bias_;
   const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HCompare);
@@ -2228,15 +2481,16 @@
   size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
 
   bool IsMinusOne() const OVERRIDE {
-    return bit_cast<uint32_t, float>(AsFloatConstant()->GetValue()) ==
-        bit_cast<uint32_t, float>((-1.0f));
+    return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>((-1.0f));
   }
   bool IsZero() const OVERRIDE {
-    return AsFloatConstant()->GetValue() == 0.0f;
+    return value_ == 0.0f;
   }
   bool IsOne() const OVERRIDE {
-    return bit_cast<uint32_t, float>(AsFloatConstant()->GetValue()) ==
-        bit_cast<uint32_t, float>(1.0f);
+    return bit_cast<uint32_t, float>(value_) == bit_cast<uint32_t, float>(1.0f);
+  }
+  bool IsNaN() const {
+    return std::isnan(value_);
   }
 
   DECLARE_INSTRUCTION(FloatConstant);
@@ -2266,15 +2520,16 @@
   size_t ComputeHashCode() const OVERRIDE { return static_cast<size_t>(GetValue()); }
 
   bool IsMinusOne() const OVERRIDE {
-    return bit_cast<uint64_t, double>(AsDoubleConstant()->GetValue()) ==
-        bit_cast<uint64_t, double>((-1.0));
+    return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>((-1.0));
   }
   bool IsZero() const OVERRIDE {
-    return AsDoubleConstant()->GetValue() == 0.0;
+    return value_ == 0.0;
   }
   bool IsOne() const OVERRIDE {
-    return bit_cast<uint64_t, double>(AsDoubleConstant()->GetValue()) ==
-        bit_cast<uint64_t, double>(1.0);
+    return bit_cast<uint64_t, double>(value_) == bit_cast<uint64_t, double>(1.0);
+  }
+  bool IsNaN() const {
+    return std::isnan(value_);
   }
 
   DECLARE_INSTRUCTION(DoubleConstant);
@@ -2396,6 +2651,9 @@
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   uint32_t GetDexMethodIndex() const { return dex_method_index_; }
+  const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
+
+  InvokeType GetOriginalInvokeType() const { return original_invoke_type_; }
 
   Intrinsics GetIntrinsic() const {
     return intrinsic_;
@@ -2405,6 +2663,12 @@
     intrinsic_ = intrinsic;
   }
 
+  bool IsFromInlinedInvoke() const {
+    return GetEnvironment()->GetParent() != nullptr;
+  }
+
+  bool CanThrow() const OVERRIDE { return true; }
+
   DECLARE_INSTRUCTION(Invoke);
 
  protected:
@@ -2413,13 +2677,15 @@
           uint32_t number_of_other_inputs,
           Primitive::Type return_type,
           uint32_t dex_pc,
-          uint32_t dex_method_index)
+          uint32_t dex_method_index,
+          InvokeType original_invoke_type)
     : HInstruction(SideEffects::All()),
       number_of_arguments_(number_of_arguments),
       inputs_(arena, number_of_arguments),
       return_type_(return_type),
       dex_pc_(dex_pc),
       dex_method_index_(dex_method_index),
+      original_invoke_type_(original_invoke_type),
       intrinsic_(Intrinsics::kNone) {
     uint32_t number_of_inputs = number_of_arguments + number_of_other_inputs;
     inputs_.SetSize(number_of_inputs);
@@ -2435,6 +2701,7 @@
   const Primitive::Type return_type_;
   const uint32_t dex_pc_;
   const uint32_t dex_method_index_;
+  const InvokeType original_invoke_type_;
   Intrinsics intrinsic_;
 
  private:
@@ -2463,11 +2730,13 @@
                         ClinitCheckRequirement clinit_check_requirement)
       : HInvoke(arena,
                 number_of_arguments,
-                clinit_check_requirement == ClinitCheckRequirement::kExplicit ? 1u : 0u,
+                // 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,
                 return_type,
                 dex_pc,
-                dex_method_index),
-        original_invoke_type_(original_invoke_type),
+                dex_method_index,
+                original_invoke_type),
         invoke_type_(invoke_type),
         is_recursive_(is_recursive),
         clinit_check_requirement_(clinit_check_requirement),
@@ -2480,12 +2749,12 @@
     return false;
   }
 
-  InvokeType GetOriginalInvokeType() const { return original_invoke_type_; }
   InvokeType GetInvokeType() const { return invoke_type_; }
   bool IsRecursive() const { return is_recursive_; }
   bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); }
   bool IsStringInit() const { return string_init_offset_ != 0; }
   int32_t GetStringInitOffset() const { return string_init_offset_; }
+  uint32_t GetCurrentMethodInputIndex() const { return GetNumberOfArguments(); }
 
   // Is this instruction a call to a static method?
   bool IsStatic() const {
@@ -2538,7 +2807,6 @@
   }
 
  private:
-  const InvokeType original_invoke_type_;
   const InvokeType invoke_type_;
   const bool is_recursive_;
   ClinitCheckRequirement clinit_check_requirement_;
@@ -2557,7 +2825,7 @@
                  uint32_t dex_pc,
                  uint32_t dex_method_index,
                  uint32_t vtable_index)
-      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index),
+      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kVirtual),
         vtable_index_(vtable_index) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -2583,7 +2851,7 @@
                    uint32_t dex_pc,
                    uint32_t dex_method_index,
                    uint32_t imt_index)
-      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index),
+      : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kInterface),
         imt_index_(imt_index) {}
 
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -2602,16 +2870,24 @@
   DISALLOW_COPY_AND_ASSIGN(HInvokeInterface);
 };
 
-class HNewInstance : public HExpression<0> {
+class HNewInstance : public HExpression<1> {
  public:
-  HNewInstance(uint32_t dex_pc, uint16_t type_index, QuickEntrypointEnum entrypoint)
+  HNewInstance(HCurrentMethod* current_method,
+               uint32_t dex_pc,
+               uint16_t type_index,
+               const DexFile& dex_file,
+               QuickEntrypointEnum entrypoint)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         dex_pc_(dex_pc),
         type_index_(type_index),
-        entrypoint_(entrypoint) {}
+        dex_file_(dex_file),
+        entrypoint_(entrypoint) {
+    SetRawInputAt(0, current_method);
+  }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
+  const DexFile& GetDexFile() const { return dex_file_; }
 
   // Calls runtime so needs an environment.
   bool NeedsEnvironment() const OVERRIDE { return true; }
@@ -2630,6 +2906,7 @@
  private:
   const uint32_t dex_pc_;
   const uint16_t type_index_;
+  const DexFile& dex_file_;
   const QuickEntrypointEnum entrypoint_;
 
   DISALLOW_COPY_AND_ASSIGN(HNewInstance);
@@ -2649,21 +2926,26 @@
   DISALLOW_COPY_AND_ASSIGN(HNeg);
 };
 
-class HNewArray : public HExpression<1> {
+class HNewArray : public HExpression<2> {
  public:
   HNewArray(HInstruction* length,
+            HCurrentMethod* current_method,
             uint32_t dex_pc,
             uint16_t type_index,
+            const DexFile& dex_file,
             QuickEntrypointEnum entrypoint)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         dex_pc_(dex_pc),
         type_index_(type_index),
+        dex_file_(dex_file),
         entrypoint_(entrypoint) {
     SetRawInputAt(0, length);
+    SetRawInputAt(1, current_method);
   }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
+  const DexFile& GetDexFile() const { return dex_file_; }
 
   // Calls runtime so needs an environment.
   bool NeedsEnvironment() const OVERRIDE { return true; }
@@ -2680,6 +2962,7 @@
  private:
   const uint32_t dex_pc_;
   const uint16_t type_index_;
+  const DexFile& dex_file_;
   const QuickEntrypointEnum entrypoint_;
 
   DISALLOW_COPY_AND_ASSIGN(HNewArray);
@@ -2931,6 +3214,8 @@
 
   bool CanBeNull() const OVERRIDE { return !is_this_; }
 
+  bool IsThis() const { return is_this_; }
+
   DECLARE_INSTRUCTION(ParameterValue);
 
  private:
@@ -3011,6 +3296,10 @@
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
 
+  // Try to statically evaluate the conversion and return a HConstant
+  // containing the result.  If the input cannot be converted, return nullptr.
+  HConstant* TryStaticEvaluation() const;
+
   DECLARE_INSTRUCTION(TypeConversion);
 
  private:
@@ -3128,17 +3417,29 @@
 
 class FieldInfo : public ValueObject {
  public:
-  FieldInfo(MemberOffset field_offset, Primitive::Type field_type, bool is_volatile)
-      : field_offset_(field_offset), field_type_(field_type), is_volatile_(is_volatile) {}
+  FieldInfo(MemberOffset field_offset,
+            Primitive::Type field_type,
+            bool is_volatile,
+            uint32_t index,
+            const DexFile& dex_file)
+      : field_offset_(field_offset),
+        field_type_(field_type),
+        is_volatile_(is_volatile),
+        index_(index),
+        dex_file_(dex_file) {}
 
   MemberOffset GetFieldOffset() const { return field_offset_; }
   Primitive::Type GetFieldType() const { return field_type_; }
+  uint32_t GetFieldIndex() const { return index_; }
+  const DexFile& GetDexFile() const { return dex_file_; }
   bool IsVolatile() const { return is_volatile_; }
 
  private:
   const MemberOffset field_offset_;
   const Primitive::Type field_type_;
   const bool is_volatile_;
+  uint32_t index_;
+  const DexFile& dex_file_;
 };
 
 class HInstanceFieldGet : public HExpression<1> {
@@ -3146,9 +3447,11 @@
   HInstanceFieldGet(HInstruction* value,
                     Primitive::Type field_type,
                     MemberOffset field_offset,
-                    bool is_volatile)
+                    bool is_volatile,
+                    uint32_t field_idx,
+                    const DexFile& dex_file)
       : HExpression(field_type, SideEffects::DependsOnSomething()),
-        field_info_(field_offset, field_type, is_volatile) {
+        field_info_(field_offset, field_type, is_volatile, field_idx, dex_file) {
     SetRawInputAt(0, value);
   }
 
@@ -3186,9 +3489,12 @@
                     HInstruction* value,
                     Primitive::Type field_type,
                     MemberOffset field_offset,
-                    bool is_volatile)
+                    bool is_volatile,
+                    uint32_t field_idx,
+                    const DexFile& dex_file)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
-        field_info_(field_offset, field_type, is_volatile) {
+        field_info_(field_offset, field_type, is_volatile, field_idx, dex_file),
+        value_can_be_null_(true) {
     SetRawInputAt(0, object);
     SetRawInputAt(1, value);
   }
@@ -3202,11 +3508,14 @@
   Primitive::Type GetFieldType() const { return field_info_.GetFieldType(); }
   bool IsVolatile() const { return field_info_.IsVolatile(); }
   HInstruction* GetValue() const { return InputAt(1); }
+  bool GetValueCanBeNull() const { return value_can_be_null_; }
+  void ClearValueCanBeNull() { value_can_be_null_ = false; }
 
   DECLARE_INSTRUCTION(InstanceFieldSet);
 
  private:
   const FieldInfo field_info_;
+  bool value_can_be_null_;
 
   DISALLOW_COPY_AND_ASSIGN(HInstanceFieldSet);
 };
@@ -3255,7 +3564,8 @@
       : HTemplateInstruction(SideEffects::ChangesSomething()),
         dex_pc_(dex_pc),
         expected_component_type_(expected_component_type),
-        needs_type_check_(value->GetType() == Primitive::kPrimNot) {
+        needs_type_check_(value->GetType() == Primitive::kPrimNot),
+        value_can_be_null_(true) {
     SetRawInputAt(0, array);
     SetRawInputAt(1, index);
     SetRawInputAt(2, value);
@@ -3267,6 +3577,9 @@
     return needs_type_check_;
   }
 
+  // Can throw ArrayStoreException.
+  bool CanThrow() const OVERRIDE { return needs_type_check_; }
+
   bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
     UNUSED(obj);
     // TODO: Same as for ArrayGet.
@@ -3277,6 +3590,11 @@
     needs_type_check_ = false;
   }
 
+  void ClearValueCanBeNull() {
+    value_can_be_null_ = false;
+  }
+
+  bool GetValueCanBeNull() const { return value_can_be_null_; }
   bool NeedsTypeCheck() const { return needs_type_check_; }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
@@ -3302,6 +3620,7 @@
   const uint32_t dex_pc_;
   const Primitive::Type expected_component_type_;
   bool needs_type_check_;
+  bool value_can_be_null_;
 
   DISALLOW_COPY_AND_ASSIGN(HArraySet);
 };
@@ -3414,17 +3733,22 @@
 /**
  * Instruction to load a Class object.
  */
-class HLoadClass : public HExpression<0> {
+class HLoadClass : public HExpression<1> {
  public:
-  HLoadClass(uint16_t type_index,
+  HLoadClass(HCurrentMethod* current_method,
+             uint16_t type_index,
+             const DexFile& dex_file,
              bool is_referrers_class,
              uint32_t dex_pc)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         type_index_(type_index),
+        dex_file_(dex_file),
         is_referrers_class_(is_referrers_class),
         dex_pc_(dex_pc),
         generate_clinit_check_(false),
-        loaded_class_rti_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {}
+        loaded_class_rti_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {
+    SetRawInputAt(0, current_method);
+  }
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
@@ -3449,8 +3773,8 @@
     return generate_clinit_check_;
   }
 
-  void SetMustGenerateClinitCheck() {
-    generate_clinit_check_ = true;
+  void SetMustGenerateClinitCheck(bool generate_clinit_check) {
+    generate_clinit_check_ = generate_clinit_check;
   }
 
   bool CanCallRuntime() const {
@@ -3460,7 +3784,7 @@
   bool CanThrow() const OVERRIDE {
     // May call runtime and and therefore can throw.
     // TODO: finer grain decision.
-    return !is_referrers_class_;
+    return CanCallRuntime();
   }
 
   ReferenceTypeInfo GetLoadedClassRTI() {
@@ -3477,12 +3801,15 @@
     return loaded_class_rti_.IsExact();
   }
 
+  const DexFile& GetDexFile() { return dex_file_; }
+
   bool NeedsDexCache() const OVERRIDE { return !is_referrers_class_; }
 
   DECLARE_INSTRUCTION(LoadClass);
 
  private:
   const uint16_t type_index_;
+  const DexFile& dex_file_;
   const bool is_referrers_class_;
   const uint32_t dex_pc_;
   // Whether this instruction must generate the initialization check.
@@ -3494,12 +3821,14 @@
   DISALLOW_COPY_AND_ASSIGN(HLoadClass);
 };
 
-class HLoadString : public HExpression<0> {
+class HLoadString : public HExpression<1> {
  public:
-  HLoadString(uint32_t string_index, uint32_t dex_pc)
+  HLoadString(HCurrentMethod* current_method, uint32_t string_index, uint32_t dex_pc)
       : HExpression(Primitive::kPrimNot, SideEffects::None()),
         string_index_(string_index),
-        dex_pc_(dex_pc) {}
+        dex_pc_(dex_pc) {
+    SetRawInputAt(0, current_method);
+  }
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
@@ -3564,9 +3893,11 @@
   HStaticFieldGet(HInstruction* cls,
                   Primitive::Type field_type,
                   MemberOffset field_offset,
-                  bool is_volatile)
+                  bool is_volatile,
+                  uint32_t field_idx,
+                  const DexFile& dex_file)
       : HExpression(field_type, SideEffects::DependsOnSomething()),
-        field_info_(field_offset, field_type, is_volatile) {
+        field_info_(field_offset, field_type, is_volatile, field_idx, dex_file) {
     SetRawInputAt(0, cls);
   }
 
@@ -3601,9 +3932,12 @@
                   HInstruction* value,
                   Primitive::Type field_type,
                   MemberOffset field_offset,
-                  bool is_volatile)
+                  bool is_volatile,
+                  uint32_t field_idx,
+                  const DexFile& dex_file)
       : HTemplateInstruction(SideEffects::ChangesSomething()),
-        field_info_(field_offset, field_type, is_volatile) {
+        field_info_(field_offset, field_type, is_volatile, field_idx, dex_file),
+        value_can_be_null_(true) {
     SetRawInputAt(0, cls);
     SetRawInputAt(1, value);
   }
@@ -3614,11 +3948,14 @@
   bool IsVolatile() const { return field_info_.IsVolatile(); }
 
   HInstruction* GetValue() const { return InputAt(1); }
+  bool GetValueCanBeNull() const { return value_can_be_null_; }
+  void ClearValueCanBeNull() { value_can_be_null_ = false; }
 
   DECLARE_INSTRUCTION(StaticFieldSet);
 
  private:
   const FieldInfo field_info_;
+  bool value_can_be_null_;
 
   DISALLOW_COPY_AND_ASSIGN(HStaticFieldSet);
 };
@@ -3794,13 +4131,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_; }
 
@@ -3923,7 +4266,9 @@
       }
       for (size_t i = 0, e = moves_.Size(); i < e; ++i) {
         DCHECK(!destination.OverlapsWith(moves_.Get(i).GetDestination()))
-            << "Overlapped destination for two moves in a parallel move.";
+            << "Overlapped destination for two moves in a parallel move: "
+            << moves_.Get(i).GetSource() << " ==> " << moves_.Get(i).GetDestination() << " and "
+            << source << " ==> " << destination;
       }
     }
     moves_.Add(MoveOperands(source, destination, type, instruction));
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index 2736453..fef77aa 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -51,7 +51,7 @@
   exit_block->AddInstruction(new (&allocator) HExit());
 
   HEnvironment* environment = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, null_check);
   null_check->SetRawEnvironment(environment);
   environment->SetRawEnvAt(0, parameter);
   parameter->AddEnvUseAt(null_check->GetEnvironment(), 0);
@@ -132,7 +132,7 @@
   ASSERT_TRUE(parameter1->GetUses().HasOnlyOneUse());
 
   HEnvironment* environment = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, with_environment);
   GrowableArray<HInstruction*> array(&allocator, 1);
   array.Add(parameter1);
 
@@ -143,13 +143,13 @@
   ASSERT_TRUE(parameter1->GetEnvUses().HasOnlyOneUse());
 
   HEnvironment* parent1 = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, nullptr);
   parent1->CopyFrom(array);
 
   ASSERT_EQ(parameter1->GetEnvUses().SizeSlow(), 2u);
 
   HEnvironment* parent2 = new (&allocator) HEnvironment(
-      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0);
+      &allocator, 1, graph->GetDexFile(), graph->GetMethodIdx(), 0, kStatic, nullptr);
   parent2->CopyFrom(array);
   parent1->SetAndCopyParentChain(&allocator, parent2);
 
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index c46a219..3d76949 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -16,9 +16,6 @@
 
 #include "optimization.h"
 
-#include "base/dumpable.h"
-#include "graph_checker.h"
-
 namespace art {
 
 void HOptimization::MaybeRecordStat(MethodCompilationStat compilation_stat, size_t count) const {
@@ -27,24 +24,4 @@
   }
 }
 
-void HOptimization::Check() {
-  if (kIsDebugBuild) {
-    if (is_in_ssa_form_) {
-      SSAChecker checker(graph_->GetArena(), graph_);
-      checker.Run();
-      if (!checker.IsValid()) {
-        LOG(FATAL) << "Error after " << GetPassName() << ": "
-                   << Dumpable<SSAChecker>(checker);
-      }
-    } else {
-      GraphChecker checker(graph_->GetArena(), graph_);
-      checker.Run();
-      if (!checker.IsValid()) {
-        LOG(FATAL) << "Error after " << GetPassName() << ": "
-                   << Dumpable<GraphChecker>(checker);
-      }
-    }
-  }
-}
-
 }  // namespace art
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index ccf8de9..bc56546 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_
 #define ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_
 
+#include "base/arena_object.h"
 #include "nodes.h"
 #include "optimizing_compiler_stats.h"
 
@@ -25,15 +26,13 @@
 /**
  * Abstraction to implement an optimization pass.
  */
-class HOptimization : public ValueObject {
+class HOptimization : public ArenaObject<kArenaAllocMisc> {
  public:
   HOptimization(HGraph* graph,
-                bool is_in_ssa_form,
                 const char* pass_name,
                 OptimizingCompilerStats* stats = nullptr)
       : graph_(graph),
         stats_(stats),
-        is_in_ssa_form_(is_in_ssa_form),
         pass_name_(pass_name) {}
 
   virtual ~HOptimization() {}
@@ -44,9 +43,6 @@
   // Peform the analysis itself.
   virtual void Run() = 0;
 
-  // Verify the graph; abort if it is not valid.
-  void Check();
-
  protected:
   void MaybeRecordStat(MethodCompilationStat compilation_stat, size_t count = 1) const;
 
@@ -55,8 +51,6 @@
   OptimizingCompilerStats* const stats_;
 
  private:
-  // Does the analyzed graph use the SSA form?
-  const bool is_in_ssa_form_;
   // Optimization pass name.
   const char* pass_name_;
 
diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc
index b0d1433..fe3bb1a 100644
--- a/compiler/optimizing/optimizing_cfi_test.cc
+++ b/compiler/optimizing/optimizing_cfi_test.cc
@@ -71,6 +71,8 @@
         }
       }
     }
+    GrowableArray<HBasicBlock*> blocks(&allocator, 0);
+    code_gen->block_order_ = &blocks;
     code_gen->ComputeSpillMask();
     code_gen->SetFrameSize(frame_size);
     code_gen->GenerateFrameEntry();
diff --git a/compiler/optimizing/optimizing_cfi_test_expected.inc b/compiler/optimizing/optimizing_cfi_test_expected.inc
index 9ccc011..2c2c55f 100644
--- a/compiler/optimizing/optimizing_cfi_test_expected.inc
+++ b/compiler/optimizing/optimizing_cfi_test_expected.inc
@@ -32,20 +32,20 @@
 // 0x00000012: .cfi_def_cfa_offset: 64
 
 static constexpr uint8_t expected_asm_kArm64[] = {
-    0xE0, 0x0F, 0x1C, 0xF8, 0xF3, 0xD3, 0x02, 0xA9, 0xFE, 0x1F, 0x00, 0xF9,
-    0xE8, 0xA7, 0x01, 0x6D, 0xE8, 0xA7, 0x41, 0x6D, 0xF3, 0xD3, 0x42, 0xA9,
+    0xE0, 0x0F, 0x1C, 0xF8, 0xF4, 0xD7, 0x02, 0xA9, 0xFE, 0x1F, 0x00, 0xF9,
+    0xE8, 0xA7, 0x01, 0x6D, 0xE8, 0xA7, 0x41, 0x6D, 0xF4, 0xD7, 0x42, 0xA9,
     0xFE, 0x1F, 0x40, 0xF9, 0xFF, 0x03, 0x01, 0x91, 0xC0, 0x03, 0x5F, 0xD6,
 };
 static constexpr uint8_t expected_cfi_kArm64[] = {
-    0x44, 0x0E, 0x40, 0x44, 0x93, 0x06, 0x94, 0x04, 0x44, 0x9E, 0x02, 0x44,
+    0x44, 0x0E, 0x40, 0x44, 0x94, 0x06, 0x95, 0x04, 0x44, 0x9E, 0x02, 0x44,
     0x05, 0x48, 0x0A, 0x05, 0x49, 0x08, 0x0A, 0x44, 0x06, 0x48, 0x06, 0x49,
-    0x44, 0xD3, 0xD4, 0x44, 0xDE, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E, 0x40,
+    0x44, 0xD4, 0xD5, 0x44, 0xDE, 0x44, 0x0E, 0x00, 0x44, 0x0B, 0x0E, 0x40,
 };
 // 0x00000000: str x0, [sp, #-64]!
 // 0x00000004: .cfi_def_cfa_offset: 64
-// 0x00000004: stp x19, x20, [sp, #40]
-// 0x00000008: .cfi_offset: r19 at cfa-24
-// 0x00000008: .cfi_offset: r20 at cfa-16
+// 0x00000004: stp x20, x21, [sp, #40]
+// 0x00000008: .cfi_offset: r20 at cfa-24
+// 0x00000008: .cfi_offset: r21 at cfa-16
 // 0x00000008: str lr, [sp, #56]
 // 0x0000000c: .cfi_offset: r30 at cfa-8
 // 0x0000000c: stp d8, d9, [sp, #24]
@@ -55,9 +55,9 @@
 // 0x00000010: ldp d8, d9, [sp, #24]
 // 0x00000014: .cfi_restore_extended: r72
 // 0x00000014: .cfi_restore_extended: r73
-// 0x00000014: ldp x19, x20, [sp, #40]
-// 0x00000018: .cfi_restore: r19
+// 0x00000014: ldp x20, x21, [sp, #40]
 // 0x00000018: .cfi_restore: r20
+// 0x00000018: .cfi_restore: r21
 // 0x00000018: ldr lr, [sp, #56]
 // 0x0000001c: .cfi_restore: r30
 // 0x0000001c: add sp, sp, #0x40 (64)
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index f1293b7..1e51530 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -38,6 +38,7 @@
 #include "driver/compiler_options.h"
 #include "driver/dex_compilation_unit.h"
 #include "elf_writer_quick.h"
+#include "graph_checker.h"
 #include "graph_visualizer.h"
 #include "gvn.h"
 #include "inliner.h"
@@ -86,35 +87,47 @@
  */
 static const char* kStringFilter = "";
 
-class PassInfo;
+class PassScope;
 
-class PassInfoPrinter : public ValueObject {
+class PassObserver : public ValueObject {
  public:
-  PassInfoPrinter(HGraph* graph,
-                  const char* method_name,
-                  const CodeGenerator& codegen,
-                  std::ostream* visualizer_output,
-                  CompilerDriver* compiler_driver)
-      : method_name_(method_name),
+  PassObserver(HGraph* graph,
+               const char* method_name,
+               CodeGenerator* codegen,
+               std::ostream* visualizer_output,
+               CompilerDriver* compiler_driver)
+      : graph_(graph),
+        method_name_(method_name),
         timing_logger_enabled_(compiler_driver->GetDumpPasses()),
         timing_logger_(method_name, true, true),
+        disasm_info_(graph->GetArena()),
         visualizer_enabled_(!compiler_driver->GetDumpCfgFileName().empty()),
-        visualizer_(visualizer_output, graph, codegen) {
+        visualizer_(visualizer_output, graph, *codegen),
+        graph_in_bad_state_(false) {
     if (strstr(method_name, kStringFilter) == nullptr) {
       timing_logger_enabled_ = visualizer_enabled_ = false;
     }
     if (visualizer_enabled_) {
       visualizer_.PrintHeader(method_name_);
+      codegen->SetDisassemblyInformation(&disasm_info_);
     }
   }
 
-  ~PassInfoPrinter() {
+  ~PassObserver() {
     if (timing_logger_enabled_) {
       LOG(INFO) << "TIMINGS " << method_name_;
       LOG(INFO) << Dumpable<TimingLogger>(timing_logger_);
     }
   }
 
+  void DumpDisassembly() const {
+    if (visualizer_enabled_) {
+      visualizer_.DumpGraphWithDisassembly();
+    }
+  }
+
+  void SetGraphInBadState() { graph_in_bad_state_ = true; }
+
  private:
   void StartPass(const char* pass_name) {
     // Dump graph first, then start timer.
@@ -134,36 +147,62 @@
     if (visualizer_enabled_) {
       visualizer_.DumpGraph(pass_name, /* is_after_pass */ true);
     }
+
+    // Validate the HGraph if running in debug mode.
+    if (kIsDebugBuild) {
+      if (!graph_in_bad_state_) {
+        if (graph_->IsInSsaForm()) {
+          SSAChecker checker(graph_->GetArena(), graph_);
+          checker.Run();
+          if (!checker.IsValid()) {
+            LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<SSAChecker>(checker);
+          }
+        } else {
+          GraphChecker checker(graph_->GetArena(), graph_);
+          checker.Run();
+          if (!checker.IsValid()) {
+            LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<GraphChecker>(checker);
+          }
+        }
+      }
+    }
   }
 
+  HGraph* const graph_;
   const char* method_name_;
 
   bool timing_logger_enabled_;
   TimingLogger timing_logger_;
 
+  DisassemblyInformation disasm_info_;
+
   bool visualizer_enabled_;
   HGraphVisualizer visualizer_;
 
-  friend PassInfo;
+  // Flag to be set by the compiler if the pass failed and the graph is not
+  // expected to validate.
+  bool graph_in_bad_state_;
 
-  DISALLOW_COPY_AND_ASSIGN(PassInfoPrinter);
+  friend PassScope;
+
+  DISALLOW_COPY_AND_ASSIGN(PassObserver);
 };
 
-class PassInfo : public ValueObject {
+class PassScope : public ValueObject {
  public:
-  PassInfo(const char *pass_name, PassInfoPrinter* pass_info_printer)
+  PassScope(const char *pass_name, PassObserver* pass_observer)
       : pass_name_(pass_name),
-        pass_info_printer_(pass_info_printer) {
-    pass_info_printer_->StartPass(pass_name_);
+        pass_observer_(pass_observer) {
+    pass_observer_->StartPass(pass_name_);
   }
 
-  ~PassInfo() {
-    pass_info_printer_->EndPass(pass_name_);
+  ~PassScope() {
+    pass_observer_->EndPass(pass_name_);
   }
 
  private:
   const char* const pass_name_;
-  PassInfoPrinter* const pass_info_printer_;
+  PassObserver* const pass_observer_;
 };
 
 class OptimizingCompiler FINAL : public Compiler {
@@ -223,14 +262,14 @@
   CompiledMethod* CompileOptimized(HGraph* graph,
                                    CodeGenerator* codegen,
                                    CompilerDriver* driver,
-                                   const DexFile& dex_file,
                                    const DexCompilationUnit& dex_compilation_unit,
-                                   PassInfoPrinter* pass_info) const;
+                                   PassObserver* pass_observer) const;
 
   // Just compile without doing optimizations.
   CompiledMethod* CompileBaseline(CodeGenerator* codegen,
                                   CompilerDriver* driver,
-                                  const DexCompilationUnit& dex_compilation_unit) const;
+                                  const DexCompilationUnit& dex_compilation_unit,
+                                  PassObserver* pass_observer) const;
 
   std::unique_ptr<OptimizingCompilerStats> compilation_stats_;
 
@@ -303,69 +342,77 @@
 
 static void RunOptimizations(HOptimization* optimizations[],
                              size_t length,
-                             PassInfoPrinter* pass_info_printer) {
+                             PassObserver* pass_observer) {
   for (size_t i = 0; i < length; ++i) {
-    HOptimization* optimization = optimizations[i];
-    {
-      PassInfo pass_info(optimization->GetPassName(), pass_info_printer);
-      optimization->Run();
-    }
-    optimization->Check();
+    PassScope scope(optimizations[i]->GetPassName(), pass_observer);
+    optimizations[i]->Run();
   }
 }
 
 static void RunOptimizations(HGraph* graph,
                              CompilerDriver* driver,
                              OptimizingCompilerStats* stats,
-                             const DexFile& dex_file,
                              const DexCompilationUnit& dex_compilation_unit,
-                             PassInfoPrinter* pass_info_printer,
+                             PassObserver* pass_observer,
                              StackHandleScopeCollection* handles) {
-  HDeadCodeElimination dce1(graph, stats,
-                            HDeadCodeElimination::kInitialDeadCodeEliminationPassName);
-  HDeadCodeElimination dce2(graph, stats,
-                            HDeadCodeElimination::kFinalDeadCodeEliminationPassName);
-  HConstantFolding fold1(graph);
-  InstructionSimplifier simplify1(graph, stats);
-  HBooleanSimplifier boolean_simplify(graph);
+  ArenaAllocator* arena = graph->GetArena();
+  HDeadCodeElimination* dce1 = new (arena) HDeadCodeElimination(
+      graph, stats, HDeadCodeElimination::kInitialDeadCodeEliminationPassName);
+  HDeadCodeElimination* dce2 = new (arena) HDeadCodeElimination(
+      graph, stats, HDeadCodeElimination::kFinalDeadCodeEliminationPassName);
+  HConstantFolding* fold1 = new (arena) HConstantFolding(graph);
+  InstructionSimplifier* simplify1 = new (arena) InstructionSimplifier(graph, stats);
+  HBooleanSimplifier* boolean_simplify = new (arena) HBooleanSimplifier(graph);
 
-  HInliner inliner(graph, dex_compilation_unit, dex_compilation_unit, driver, stats);
+  HInliner* inliner = new (arena) HInliner(
+      graph, dex_compilation_unit, dex_compilation_unit, driver, handles, stats);
 
-  HConstantFolding fold2(graph, "constant_folding_after_inlining");
-  SideEffectsAnalysis side_effects(graph);
-  GVNOptimization gvn(graph, side_effects);
-  LICM licm(graph, side_effects);
-  BoundsCheckElimination bce(graph);
-  ReferenceTypePropagation type_propagation(graph, dex_file, dex_compilation_unit, handles);
-  InstructionSimplifier simplify2(graph, stats, "instruction_simplifier_after_types");
-  InstructionSimplifier simplify3(graph, stats, "instruction_simplifier_before_codegen");
+  HConstantFolding* fold2 = new (arena) HConstantFolding(graph, "constant_folding_after_inlining");
+  SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
+  GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects);
+  LICM* licm = new (arena) LICM(graph, *side_effects);
+  BoundsCheckElimination* bce = new (arena) BoundsCheckElimination(graph);
+  ReferenceTypePropagation* type_propagation =
+      new (arena) ReferenceTypePropagation(graph, handles);
+  InstructionSimplifier* simplify2 = new (arena) InstructionSimplifier(
+      graph, stats, "instruction_simplifier_after_types");
+  InstructionSimplifier* simplify3 = new (arena) InstructionSimplifier(
+      graph, stats, "instruction_simplifier_after_bce");
+  ReferenceTypePropagation* type_propagation2 =
+      new (arena) ReferenceTypePropagation(graph, handles);
+  InstructionSimplifier* simplify4 = new (arena) InstructionSimplifier(
+      graph, stats, "instruction_simplifier_before_codegen");
 
-  IntrinsicsRecognizer intrinsics(graph, dex_compilation_unit.GetDexFile(), driver);
+  IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, driver);
 
   HOptimization* optimizations[] = {
-    &intrinsics,
-    &fold1,
-    &simplify1,
-    &dce1,
-    &inliner,
+    intrinsics,
+    fold1,
+    simplify1,
+    type_propagation,
+    dce1,
+    simplify2,
+    inliner,
+    // Run another type propagation phase: inlining will open up more opprotunities
+    // to remove checkast/instanceof and null checks.
+    type_propagation2,
     // BooleanSimplifier depends on the InstructionSimplifier removing redundant
     // suspend checks to recognize empty blocks.
-    &boolean_simplify,
-    &fold2,
-    &side_effects,
-    &gvn,
-    &licm,
-    &bce,
-    &type_propagation,
-    &simplify2,
-    &dce2,
+    boolean_simplify,
+    fold2,
+    side_effects,
+    gvn,
+    licm,
+    bce,
+    simplify3,
+    dce2,
     // The codegen has a few assumptions that only the instruction simplifier can
     // satisfy. For example, the code generator does not expect to see a
     // HTypeConversion from a type to the same type.
-    &simplify3,
+    simplify4,
   };
 
-  RunOptimizations(optimizations, arraysize(optimizations), pass_info_printer);
+  RunOptimizations(optimizations, arraysize(optimizations), pass_observer);
 }
 
 // The stack map we generate must be 4-byte aligned on ARM. Since existing
@@ -381,15 +428,15 @@
 
 static void AllocateRegisters(HGraph* graph,
                               CodeGenerator* codegen,
-                              PassInfoPrinter* pass_info_printer) {
+                              PassObserver* pass_observer) {
   PrepareForRegisterAllocation(graph).Run();
   SsaLivenessAnalysis liveness(graph, codegen);
   {
-    PassInfo pass_info(SsaLivenessAnalysis::kLivenessPassName, pass_info_printer);
+    PassScope scope(SsaLivenessAnalysis::kLivenessPassName, pass_observer);
     liveness.Analyze();
   }
   {
-    PassInfo pass_info(RegisterAllocator::kRegisterAllocatorPassName, pass_info_printer);
+    PassScope scope(RegisterAllocator::kRegisterAllocatorPassName, pass_observer);
     RegisterAllocator(graph->GetArena(), codegen, liveness).AllocateRegisters();
   }
 }
@@ -397,14 +444,13 @@
 CompiledMethod* OptimizingCompiler::CompileOptimized(HGraph* graph,
                                                      CodeGenerator* codegen,
                                                      CompilerDriver* compiler_driver,
-                                                     const DexFile& dex_file,
                                                      const DexCompilationUnit& dex_compilation_unit,
-                                                     PassInfoPrinter* pass_info_printer) const {
+                                                     PassObserver* pass_observer) const {
   StackHandleScopeCollection handles(Thread::Current());
   RunOptimizations(graph, compiler_driver, compilation_stats_.get(),
-                   dex_file, dex_compilation_unit, pass_info_printer, &handles);
+                   dex_compilation_unit, pass_observer, &handles);
 
-  AllocateRegisters(graph, codegen, pass_info_printer);
+  AllocateRegisters(graph, codegen, pass_observer);
 
   CodeVectorAllocator allocator;
   codegen->CompileOptimized(&allocator);
@@ -419,7 +465,7 @@
 
   MaybeRecordStat(MethodCompilationStat::kCompiledOptimized);
 
-  return CompiledMethod::SwapAllocCompiledMethod(
+  CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod(
       compiler_driver,
       codegen->GetInstructionSet(),
       ArrayRef<const uint8_t>(allocator.GetMemory()),
@@ -435,12 +481,15 @@
       ArrayRef<const uint8_t>(),  // native_gc_map.
       ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
       ArrayRef<const LinkerPatch>());
+  pass_observer->DumpDisassembly();
+  return compiled_method;
 }
 
 CompiledMethod* OptimizingCompiler::CompileBaseline(
     CodeGenerator* codegen,
     CompilerDriver* compiler_driver,
-    const DexCompilationUnit& dex_compilation_unit) const {
+    const DexCompilationUnit& dex_compilation_unit,
+    PassObserver* pass_observer) const {
   CodeVectorAllocator allocator;
   codegen->CompileBaseline(&allocator);
 
@@ -456,7 +505,7 @@
   codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
 
   MaybeRecordStat(MethodCompilationStat::kCompiledBaseline);
-  return CompiledMethod::SwapAllocCompiledMethod(
+  CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod(
       compiler_driver,
       codegen->GetInstructionSet(),
       ArrayRef<const uint8_t>(allocator.GetMemory()),
@@ -472,6 +521,8 @@
       AlignVectorSize(gc_map),
       ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
       ArrayRef<const LinkerPatch>());
+  pass_observer->DumpDisassembly();
+  return compiled_method;
 }
 
 CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item,
@@ -492,16 +543,6 @@
     instruction_set = kThumb2;
   }
 
-  // `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 should_use_baseline = !run_optimizations_;
-  bool can_optimize = CanOptimize(*code_item);
-  if (!can_optimize && !should_use_baseline) {
-    // We know we will not compile this method. Bail out before doing any work.
-    return nullptr;
-  }
-
   // Do not attempt to compile on architectures we do not support.
   if (!IsInstructionSetSupported(instruction_set)) {
     MaybeRecordStat(MethodCompilationStat::kNotCompiledUnsupportedIsa);
@@ -528,10 +569,14 @@
     class_def_idx, method_idx, access_flags,
     compiler_driver->GetVerifiedMethod(&dex_file, method_idx));
 
+  bool requires_barrier = dex_compilation_unit.IsConstructor()
+      && compiler_driver->RequiresConstructorBarrier(Thread::Current(),
+                                                     dex_compilation_unit.GetDexFile(),
+                                                     dex_compilation_unit.GetClassDefIndex());
   ArenaAllocator arena(Runtime::Current()->GetArenaPool());
   HGraph* graph = new (&arena) HGraph(
-      &arena, dex_file, method_idx, compiler_driver->GetInstructionSet(),
-      compiler_driver->GetCompilerOptions().GetDebuggable());
+      &arena, dex_file, method_idx, requires_barrier, compiler_driver->GetInstructionSet(),
+      kInvalidInvokeType, compiler_driver->GetCompilerOptions().GetDebuggable());
 
   // For testing purposes, we put a special marker on method names that should be compiled
   // with this compiler. This makes sure we're not regressing.
@@ -551,11 +596,11 @@
   codegen->GetAssembler()->cfi().SetEnabled(
       compiler_driver->GetCompilerOptions().GetGenerateDebugInfo());
 
-  PassInfoPrinter pass_info_printer(graph,
-                                    method_name.c_str(),
-                                    *codegen.get(),
-                                    visualizer_output_.get(),
-                                    compiler_driver);
+  PassObserver pass_observer(graph,
+                             method_name.c_str(),
+                             codegen.get(),
+                             visualizer_output_.get(),
+                             compiler_driver);
 
   HGraphBuilder builder(graph,
                         &dex_compilation_unit,
@@ -567,21 +612,27 @@
   VLOG(compiler) << "Building " << method_name;
 
   {
-    PassInfo pass_info(HGraphBuilder::kBuilderPassName, &pass_info_printer);
+    PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
     if (!builder.BuildGraph(*code_item)) {
       DCHECK(!(IsCompilingWithCoreImage() && shouldCompile))
           << "Could not build graph in optimizing compiler";
+      pass_observer.SetGraphInBadState();
       return nullptr;
     }
   }
 
+  bool can_optimize = CanOptimize(*code_item);
   bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set);
 
+  // `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) {
     VLOG(compiler) << "Optimizing " << method_name;
 
     {
-      PassInfo pass_info(SsaBuilder::kSsaBuilderPassName, &pass_info_printer);
+      PassScope scope(SsaBuilder::kSsaBuilderPassName, &pass_observer);
       if (!graph->TryBuildingSsa()) {
         // We could not transform the graph to SSA, bailout.
         LOG(INFO) << "Skipping compilation of " << method_name << ": it contains a non natural loop";
@@ -593,13 +644,12 @@
     return CompileOptimized(graph,
                             codegen.get(),
                             compiler_driver,
-                            dex_file,
                             dex_compilation_unit,
-                            &pass_info_printer);
+                            &pass_observer);
   } else if (shouldOptimize && can_allocate_registers) {
     LOG(FATAL) << "Could not allocate registers in optimizing compiler";
     UNREACHABLE();
-  } else if (should_use_baseline) {
+  } else if (can_use_baseline) {
     VLOG(compiler) << "Compile baseline " << method_name;
 
     if (!run_optimizations_) {
@@ -610,7 +660,10 @@
       MaybeRecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator);
     }
 
-    return CompileBaseline(codegen.get(), compiler_driver, dex_compilation_unit);
+    return CompileBaseline(codegen.get(),
+                           compiler_driver,
+                           dex_compilation_unit,
+                           &pass_observer);
   } else {
     return nullptr;
   }
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 6d340e2..53d052b 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -19,6 +19,7 @@
 
 #include <sstream>
 #include <string>
+#include <type_traits>
 
 #include "atomic.h"
 
@@ -39,7 +40,6 @@
   kNotCompiledLargeMethodNoBranches,
   kNotCompiledMalformedOpcode,
   kNotCompiledNoCodegen,
-  kNotCompiledNonSequentialRegPair,
   kNotCompiledPathological,
   kNotCompiledSpaceFilter,
   kNotCompiledUnhandledInstruction,
@@ -85,14 +85,15 @@
 
       for (int i = 0; i < kLastStat; i++) {
         if (compile_stats_[i] != 0) {
-          LOG(INFO) << PrintMethodCompilationStat(i) << ": " << compile_stats_[i];
+          LOG(INFO) << PrintMethodCompilationStat(static_cast<MethodCompilationStat>(i)) << ": "
+              << compile_stats_[i];
         }
       }
     }
   }
 
  private:
-  std::string PrintMethodCompilationStat(int stat) const {
+  std::string PrintMethodCompilationStat(MethodCompilationStat stat) const {
     switch (stat) {
       case kAttemptCompilation : return "kAttemptCompilation";
       case kCompiledBaseline : return "kCompiledBaseline";
@@ -108,7 +109,6 @@
       case kNotCompiledLargeMethodNoBranches : return "kNotCompiledLargeMethodNoBranches";
       case kNotCompiledMalformedOpcode : return "kNotCompiledMalformedOpcode";
       case kNotCompiledNoCodegen : return "kNotCompiledNoCodegen";
-      case kNotCompiledNonSequentialRegPair : return "kNotCompiledNonSequentialRegPair";
       case kNotCompiledPathological : return "kNotCompiledPathological";
       case kNotCompiledSpaceFilter : return "kNotCompiledSpaceFilter";
       case kNotCompiledUnhandledInstruction : return "kNotCompiledUnhandledInstruction";
@@ -122,9 +122,12 @@
       case kRemovedCheckedCast: return "kRemovedCheckedCast";
       case kRemovedDeadInstruction: return "kRemovedDeadInstruction";
       case kRemovedNullCheck: return "kRemovedNullCheck";
-      default: LOG(FATAL) << "invalid stat";
+
+      case kLastStat: break;  // Invalid to print out.
     }
-    return "";
+    LOG(FATAL) << "invalid stat "
+        << static_cast<std::underlying_type<MethodCompilationStat>::type>(stat);
+    UNREACHABLE();
   }
 
   AtomicInteger compile_stats_[kLastStat];
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 3ef96fa..86c22ed 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -74,8 +74,8 @@
 
 inline HGraph* CreateGraph(ArenaAllocator* allocator) {
   return new (allocator) HGraph(
-      allocator, *reinterpret_cast<DexFile*>(allocator->Alloc(sizeof(DexFile))), -1, kRuntimeISA,
-      false);
+      allocator, *reinterpret_cast<DexFile*>(allocator->Alloc(sizeof(DexFile))), -1, false,
+      kRuntimeISA);
 }
 
 // Create a control-flow graph from Dex instructions.
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 78d1185..ca928ae 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -53,7 +53,7 @@
   if (check->GetPrevious() == cls) {
     // Pass the initialization duty to the `HLoadClass` instruction,
     // and remove the instruction from the graph.
-    cls->SetMustGenerateClinitCheck();
+    cls->SetMustGenerateClinitCheck(true);
     check->GetBlock()->RemoveInstruction(check);
   }
 }
@@ -82,8 +82,9 @@
 void PrepareForRegisterAllocation::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
   if (invoke->IsStaticWithExplicitClinitCheck()) {
     size_t last_input_index = invoke->InputCount() - 1;
-    HInstruction* last_input = invoke->InputAt(last_input_index);
-    DCHECK(last_input->IsLoadClass()) << last_input->DebugName();
+    HLoadClass* last_input = invoke->InputAt(last_input_index)->AsLoadClass();
+    DCHECK(last_input != nullptr)
+        << "Last input is not HLoadClass. It is " << last_input->DebugName();
 
     // Remove a load class instruction as last input of a static
     // invoke, which has been added (along with a clinit check,
@@ -93,10 +94,20 @@
     // stage (i.e., after inlining has been performed).
     invoke->RemoveLoadClassAsLastInput();
 
-    // If the load class instruction is no longer used, remove it from
-    // the graph.
-    if (!last_input->HasUses()) {
-      last_input->GetBlock()->RemoveInstruction(last_input);
+    // The static call will initialize the class so there's no need for a clinit check if
+    // it's the first user.
+    // There is one special case where we still need the clinit check, when inlining. Because
+    // currently the callee is responsible for reporting parameters to the GC, the code
+    // that walks the stack during `artQuickResolutionTrampoline` cannot be interrupted for GC.
+    // Therefore we cannot allocate any object in that code, including loading a new class.
+    if (last_input == invoke->GetPrevious() && !invoke->IsFromInlinedInvoke()) {
+      last_input->SetMustGenerateClinitCheck(false);
+
+      // If the load class instruction is no longer used, remove it from
+      // the graph.
+      if (!last_input->HasUses()) {
+        last_input->GetBlock()->RemoveInstruction(last_input);
+      }
     }
   }
 }
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 40ec46c..68316c2 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -23,6 +23,30 @@
 
 namespace art {
 
+class RTPVisitor : public HGraphDelegateVisitor {
+ public:
+  RTPVisitor(HGraph* graph, StackHandleScopeCollection* handles)
+    : HGraphDelegateVisitor(graph),
+      handles_(handles) {}
+
+  void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
+  void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
+  void VisitNewArray(HNewArray* instr) OVERRIDE;
+  void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
+  void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass, bool is_exact);
+  void VisitInstanceFieldGet(HInstanceFieldGet* instr) OVERRIDE;
+  void VisitStaticFieldGet(HStaticFieldGet* instr) OVERRIDE;
+  void VisitInvoke(HInvoke* instr) OVERRIDE;
+  void VisitArrayGet(HArrayGet* instr) OVERRIDE;
+  void UpdateReferenceTypeInfo(HInstruction* instr,
+                               uint16_t type_idx,
+                               const DexFile& dex_file,
+                               bool is_exact);
+
+ private:
+  StackHandleScopeCollection* handles_;
+};
+
 void ReferenceTypePropagation::Run() {
   // To properly propagate type info we need to visit in the dominator-based order.
   // Reverse post order guarantees a node's dominators are visited first.
@@ -35,16 +59,13 @@
 
 void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
   // TODO: handle other instructions that give type info
-  // (NewArray/Call/Field accesses/array accesses)
+  // (array accesses)
 
+  RTPVisitor visitor(graph_, handles_);
   // Initialize exact types first for faster convergence.
   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* instr = it.Current();
-    if (instr->IsNewInstance()) {
-      VisitNewInstance(instr->AsNewInstance());
-    } else if (instr->IsLoadClass()) {
-      VisitLoadClass(instr->AsLoadClass());
-    }
+    instr->Accept(&visitor);
   }
 
   // Handle Phis.
@@ -175,20 +196,66 @@
   }
 }
 
-void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) {
-  ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = dex_compilation_unit_.GetClassLinker()->FindDexCache(dex_file_);
-  // Get type from dex cache assuming it was populated by the verifier.
-  mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
-  if (resolved_class != nullptr) {
-    MutableHandle<mirror::Class> handle = handles_->NewHandle(resolved_class);
-    instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, true));
+void RTPVisitor::SetClassAsTypeInfo(HInstruction* instr,
+                                    mirror::Class* klass,
+                                    bool is_exact) {
+  if (klass != nullptr) {
+    ScopedObjectAccess soa(Thread::Current());
+    MutableHandle<mirror::Class> handle = handles_->NewHandle(klass);
+    is_exact = is_exact || klass->IsFinal();
+    instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, is_exact));
   }
 }
 
-void ReferenceTypePropagation::VisitLoadClass(HLoadClass* instr) {
+void RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
+                                         uint16_t type_idx,
+                                         const DexFile& dex_file,
+                                         bool is_exact) {
+  DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
+
   ScopedObjectAccess soa(Thread::Current());
-  mirror::DexCache* dex_cache = dex_compilation_unit_.GetClassLinker()->FindDexCache(dex_file_);
+  mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
+  // Get type from dex cache assuming it was populated by the verifier.
+  SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx), is_exact);
+}
+
+void RTPVisitor::VisitNewInstance(HNewInstance* instr) {
+  UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
+}
+
+void RTPVisitor::VisitNewArray(HNewArray* instr) {
+  UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile(), /* is_exact */ true);
+}
+
+void RTPVisitor::UpdateFieldAccessTypeInfo(HInstruction* instr,
+                                           const FieldInfo& info) {
+  // The field index is unknown only during tests.
+  if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) {
+    return;
+  }
+
+  ScopedObjectAccess soa(Thread::Current());
+  ClassLinker* cl = Runtime::Current()->GetClassLinker();
+  mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile());
+  ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache);
+  if (field != nullptr) {
+    mirror::Class* klass = field->GetType<false>();
+    SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+  }
+}
+
+void RTPVisitor::VisitInstanceFieldGet(HInstanceFieldGet* instr) {
+  UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
+}
+
+void RTPVisitor::VisitStaticFieldGet(HStaticFieldGet* instr) {
+  UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo());
+}
+
+void RTPVisitor::VisitLoadClass(HLoadClass* instr) {
+  ScopedObjectAccess soa(Thread::Current());
+  mirror::DexCache* dex_cache =
+      Runtime::Current()->GetClassLinker()->FindDexCache(instr->GetDexFile());
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class = dex_cache->GetResolvedType(instr->GetTypeIndex());
   if (resolved_class != nullptr) {
@@ -263,6 +330,35 @@
   return !previous_rti.IsEqual(instr->GetReferenceTypeInfo());
 }
 
+void RTPVisitor::VisitInvoke(HInvoke* instr) {
+  if (instr->GetType() != Primitive::kPrimNot) {
+    return;
+  }
+
+  ScopedObjectAccess soa(Thread::Current());
+  ClassLinker* cl = Runtime::Current()->GetClassLinker();
+  mirror::DexCache* dex_cache = cl->FindDexCache(instr->GetDexFile());
+  ArtMethod* method = dex_cache->GetResolvedMethod(
+      instr->GetDexMethodIndex(), cl->GetImagePointerSize());
+  if (method != nullptr) {
+    mirror::Class* klass = method->GetReturnType(false);
+    SetClassAsTypeInfo(instr, klass, /* is_exact */ false);
+  }
+}
+
+void RTPVisitor::VisitArrayGet(HArrayGet* instr) {
+  if (instr->GetType() != Primitive::kPrimNot) {
+    return;
+  }
+
+  HInstruction* parent = instr->InputAt(0);
+  ScopedObjectAccess soa(Thread::Current());
+  Handle<mirror::Class> handle = parent->GetReferenceTypeInfo().GetTypeHandle();
+  if (handle.GetReference() != nullptr && handle->IsObjectArrayClass()) {
+    SetClassAsTypeInfo(instr, handle->GetComponentType(), /* is_exact */ false);
+  }
+}
+
 void ReferenceTypePropagation::UpdateBoundType(HBoundType* instr) {
   ReferenceTypeInfo new_rti = instr->InputAt(0)->GetReferenceTypeInfo();
   // Be sure that we don't go over the bounded type.
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 733e18e..17cfed4 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -30,13 +30,8 @@
  */
 class ReferenceTypePropagation : public HOptimization {
  public:
-  ReferenceTypePropagation(HGraph* graph,
-                           const DexFile& dex_file,
-                           const DexCompilationUnit& dex_compilation_unit,
-                           StackHandleScopeCollection* handles)
-    : HOptimization(graph, true, kReferenceTypePropagationPassName),
-      dex_file_(dex_file),
-      dex_compilation_unit_(dex_compilation_unit),
+  ReferenceTypePropagation(HGraph* graph, StackHandleScopeCollection* handles)
+    : HOptimization(graph, kReferenceTypePropagationPassName),
       handles_(handles),
       worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
@@ -45,17 +40,12 @@
   static constexpr const char* kReferenceTypePropagationPassName = "reference_type_propagation";
 
  private:
-  void VisitNewInstance(HNewInstance* new_instance);
-  void VisitLoadClass(HLoadClass* load_class);
   void VisitPhi(HPhi* phi);
   void VisitBasicBlock(HBasicBlock* block);
-
   void UpdateBoundType(HBoundType* bound_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdatePhi(HPhi* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   void BoundTypeForIfNotNull(HBasicBlock* block);
   void BoundTypeForIfInstanceOf(HBasicBlock* block);
-
   void ProcessWorklist();
   void AddToWorklist(HInstruction* instr);
   void AddDependentInstructionsToWorklist(HInstruction* instr);
@@ -66,8 +56,6 @@
   ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, const ReferenceTypeInfo& b)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  const DexFile& dex_file_;
-  const DexCompilationUnit& dex_compilation_unit_;
   StackHandleScopeCollection* handles_;
 
   GrowableArray<HInstruction*> worklist_;
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 8656ad5..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()) {
@@ -485,8 +487,9 @@
       LiveInterval* current = it.CurrentInterval();
       HInstruction* defined_by = current->GetParent()->GetDefinedBy();
       if (current->GetParent()->HasSpillSlot()
-           // Parameters have their own stack slot.
-           && !(defined_by != nullptr && defined_by->IsParameterValue())) {
+           // Parameters and current method have their own stack slot.
+           && !(defined_by != nullptr && (defined_by->IsParameterValue()
+                                          || defined_by->IsCurrentMethod()))) {
         BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers
             + current->GetParent()->GetSpillSlot() / kVRegSize
             - number_of_out_slots);
@@ -506,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)) {
@@ -714,13 +722,15 @@
   if (defined_by != nullptr && !current->IsSplit()) {
     LocationSummary* locations = defined_by->GetLocations();
     if (!locations->OutputCanOverlapWithInputs() && locations->Out().IsUnallocated()) {
-      for (HInputIterator it(defined_by); !it.Done(); it.Advance()) {
+      for (size_t i = 0, e = defined_by->InputCount(); i < e; ++i) {
         // Take the last interval of the input. It is the location of that interval
         // that will be used at `defined_by`.
-        LiveInterval* interval = it.Current()->GetLiveInterval()->GetLastSibling();
+        LiveInterval* interval = defined_by->InputAt(i)->GetLiveInterval()->GetLastSibling();
         // Note that interval may have not been processed yet.
         // TODO: Handle non-split intervals last in the work list.
-        if (interval->HasRegister() && interval->SameRegisterKind(*current)) {
+        if (locations->InAt(i).IsValid()
+            && interval->HasRegister()
+            && interval->SameRegisterKind(*current)) {
           // The input must be live until the end of `defined_by`, to comply to
           // the linear scan algorithm. So we use `defined_by`'s end lifetime
           // position to check whether the input is dead or is inactive after
@@ -778,7 +788,7 @@
     } else if (current->IsLowInterval()) {
       reg = FindAvailableRegisterPair(free_until, current->GetStart());
     } else {
-      reg = FindAvailableRegister(free_until);
+      reg = FindAvailableRegister(free_until, current);
     }
   }
 
@@ -802,9 +812,9 @@
   current->SetRegister(reg);
   if (!current->IsDeadAt(free_until[reg])) {
     // If the register is only available for a subset of live ranges
-    // covered by `current`, split `current` at the position where
+    // covered by `current`, split `current` before the position where
     // the register is not available anymore.
-    LiveInterval* split = Split(current, free_until[reg]);
+    LiveInterval* split = SplitBetween(current, current->GetStart(), free_until[reg]);
     DCHECK(split != nullptr);
     AddSorted(unhandled_, split);
   }
@@ -842,14 +852,52 @@
   return reg;
 }
 
-int RegisterAllocator::FindAvailableRegister(size_t* next_use) const {
+bool RegisterAllocator::IsCallerSaveRegister(int reg) const {
+  return processing_core_registers_
+      ? !codegen_->IsCoreCalleeSaveRegister(reg)
+      : !codegen_->IsFloatingPointCalleeSaveRegister(reg);
+}
+
+int RegisterAllocator::FindAvailableRegister(size_t* next_use, LiveInterval* current) const {
+  // We special case intervals that do not span a safepoint to try to find a caller-save
+  // register if one is available. We iterate from 0 to the number of registers,
+  // so if there are caller-save registers available at the end, we continue the iteration.
+  bool prefers_caller_save = !current->HasWillCallSafepoint();
   int reg = kNoRegister;
-  // Pick the register that is used the last.
   for (size_t i = 0; i < number_of_registers_; ++i) {
-    if (IsBlocked(i)) continue;
-    if (reg == kNoRegister || next_use[i] > next_use[reg]) {
+    if (IsBlocked(i)) {
+      // Register cannot be used. Continue.
+      continue;
+    }
+
+    // Best case: we found a register fully available.
+    if (next_use[i] == kMaxLifetimePosition) {
+      if (prefers_caller_save && !IsCallerSaveRegister(i)) {
+        // We can get shorter encodings on some platforms by using
+        // small register numbers. So only update the candidate if the previous
+        // one was not available for the whole method.
+        if (reg == kNoRegister || next_use[reg] != kMaxLifetimePosition) {
+          reg = i;
+        }
+        // Continue the iteration in the hope of finding a caller save register.
+        continue;
+      } else {
+        reg = i;
+        // We know the register is good enough. Return it.
+        break;
+      }
+    }
+
+    // If we had no register before, take this one as a reference.
+    if (reg == kNoRegister) {
       reg = i;
-      if (next_use[i] == kMaxLifetimePosition) break;
+      continue;
+    }
+
+    // Pick the register that is used the last.
+    if (next_use[i] > next_use[reg]) {
+      reg = i;
+      continue;
     }
   }
   return reg;
@@ -974,7 +1022,7 @@
       || (first_use >= next_use[GetHighForLowRegister(reg)]);
   } else {
     DCHECK(!current->IsHighInterval());
-    reg = FindAvailableRegister(next_use);
+    reg = FindAvailableRegister(next_use, current);
     should_spill = (first_use >= next_use[reg]);
   }
 
@@ -1211,6 +1259,11 @@
     return;
   }
 
+  if (defined_by->IsCurrentMethod()) {
+    parent->SetSpillSlot(0);
+    return;
+  }
+
   if (defined_by->IsConstant()) {
     // Constants don't need a spill slot.
     return;
@@ -1484,7 +1537,10 @@
 
 void RegisterAllocator::ConnectSiblings(LiveInterval* interval) {
   LiveInterval* current = interval;
-  if (current->HasSpillSlot() && current->HasRegister()) {
+  if (current->HasSpillSlot()
+      && current->HasRegister()
+      // Currently, we spill unconditionnally the current method in the code generators.
+      && !interval->GetDefinedBy()->IsCurrentMethod()) {
     // We spill eagerly, so move must be at definition.
     InsertMoveAfter(interval->GetDefinedBy(),
                     interval->ToLocation(),
@@ -1539,7 +1595,7 @@
       while (env_use != nullptr && env_use->GetPosition() <= range->GetEnd()) {
         DCHECK(current->CoversSlow(env_use->GetPosition())
                || (env_use->GetPosition() == range->GetEnd()));
-        HEnvironment* environment = env_use->GetUser()->GetEnvironment();
+        HEnvironment* environment = env_use->GetEnvironment();
         environment->SetLocationAt(env_use->GetInputIndex(), source);
         env_use = env_use->GetNext();
       }
@@ -1680,6 +1736,9 @@
       } else if (current->HasSpillSlot()) {
         current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize());
       }
+    } else if (instruction->IsCurrentMethod()) {
+      // The current method is always at offset 0.
+      DCHECK(!current->HasSpillSlot() || (current->GetSpillSlot() == 0));
     } else if (current->HasSpillSlot()) {
       // Adjust the stack slot, now that we know the number of them for each type.
       // The way this implementation lays out the stack is the following:
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index 97bd777..c29fe75 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -141,7 +141,8 @@
   void DumpInterval(std::ostream& stream, LiveInterval* interval) const;
   void DumpAllIntervals(std::ostream& stream) const;
   int FindAvailableRegisterPair(size_t* next_use, size_t starting_at) const;
-  int FindAvailableRegister(size_t* next_use) const;
+  int FindAvailableRegister(size_t* next_use, LiveInterval* current) const;
+  bool IsCallerSaveRegister(int reg) const;
 
   // Try splitting an active non-pair or unaligned pair interval at the given `position`.
   // Returns whether it was successful at finding such an interval.
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index b72ffb8..b7da362 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -426,6 +426,13 @@
   // Add an artifical range to cover the temps that will be put in the unhandled list.
   LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
   unhandled->AddLoopRange(0, 60);
+
+  // Populate the instructions in the liveness object, to please the register allocator.
+  for (size_t i = 0; i < 60; ++i) {
+    liveness.instructions_from_lifetime_position_.Add(
+        graph->GetEntryBlock()->GetFirstInstruction());
+  }
+
   // For SSA value intervals, only an interval resulted from a split may intersect
   // with inactive intervals.
   unhandled = register_allocator.Split(unhandled, 5);
@@ -474,8 +481,12 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
 
-  HInstruction* test = new (allocator) HInstanceFieldGet(
-      parameter, Primitive::kPrimBoolean, MemberOffset(22), false);
+  HInstruction* test = new (allocator) HInstanceFieldGet(parameter,
+                                                         Primitive::kPrimBoolean,
+                                                         MemberOffset(22),
+                                                         false,
+                                                         kUnknownFieldIndex,
+                                                         graph->GetDexFile());
   block->AddInstruction(test);
   block->AddInstruction(new (allocator) HIf(test));
   HBasicBlock* then = new (allocator) HBasicBlock(graph);
@@ -494,10 +505,18 @@
 
   *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
   join->AddPhi(*phi);
-  *input1 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
-                                              MemberOffset(42), false);
-  *input2 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
-                                              MemberOffset(42), false);
+  *input1 = new (allocator) HInstanceFieldGet(parameter,
+                                              Primitive::kPrimInt,
+                                              MemberOffset(42),
+                                              false,
+                                              kUnknownFieldIndex,
+                                              graph->GetDexFile());
+*input2 = new (allocator) HInstanceFieldGet(parameter,
+                                            Primitive::kPrimInt,
+                                            MemberOffset(42),
+                                            false,
+                                            kUnknownFieldIndex,
+                                            graph->GetDexFile());
   then->AddInstruction(*input1);
   else_->AddInstruction(*input2);
   join->AddInstruction(new (allocator) HExit());
@@ -604,8 +623,12 @@
   graph->AddBlock(block);
   entry->AddSuccessor(block);
 
-  *field = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt,
-                                             MemberOffset(42), false);
+  *field = new (allocator) HInstanceFieldGet(parameter,
+                                             Primitive::kPrimInt,
+                                             MemberOffset(42),
+                                             false,
+                                             kUnknownFieldIndex,
+                                             graph->GetDexFile());
   block->AddInstruction(*field);
   *ret = new (allocator) HReturn(*field);
   block->AddInstruction(*ret);
diff --git a/compiler/optimizing/side_effects_analysis.h b/compiler/optimizing/side_effects_analysis.h
index 415d10c..7d300ad 100644
--- a/compiler/optimizing/side_effects_analysis.h
+++ b/compiler/optimizing/side_effects_analysis.h
@@ -25,7 +25,7 @@
 class SideEffectsAnalysis : public HOptimization {
  public:
   explicit SideEffectsAnalysis(HGraph* graph)
-      : HOptimization(graph, true, kSideEffectsAnalysisPassName),
+      : HOptimization(graph, kSideEffectsAnalysisPassName),
         graph_(graph),
         block_effects_(graph->GetArena(), graph->GetBlocks().Size(), SideEffects::None()),
         loop_effects_(graph->GetArena(), graph->GetBlocks().Size(), SideEffects::None()) {}
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 3814e8f..c37b199 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -516,7 +516,7 @@
     // typed and the value in a dex register will not be used for both floating point and
     // non-floating point operations. So the only reason an instruction would want a floating
     // point equivalent is for an unused phi that will be removed by the dead phi elimination phase.
-    DCHECK(user->IsPhi());
+    DCHECK(user->IsPhi()) << "is actually " << user->DebugName() << " (" << user->GetId() << ")";
     return value;
   }
 }
@@ -559,7 +559,9 @@
       current_locals_->Size(),
       GetGraph()->GetDexFile(),
       GetGraph()->GetMethodIdx(),
-      instruction->GetDexPc());
+      instruction->GetDexPc(),
+      GetGraph()->GetInvokeType(),
+      instruction);
   environment->CopyFrom(*current_locals_);
   instruction->SetRawEnvironment(environment);
 }
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 250eb04..701dbb0 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -242,7 +242,7 @@
         HInstruction* input = current->InputAt(i);
         // Some instructions 'inline' their inputs, that is they do not need
         // to be materialized.
-        if (input->HasSsaIndex()) {
+        if (input->HasSsaIndex() && current->GetLocations()->InAt(i).IsValid()) {
           live_in->SetBit(input->GetSsaIndex());
           input->GetLiveInterval()->AddUse(current, /* environment */ nullptr, i);
         }
@@ -341,6 +341,7 @@
     // starts at. If one location is a register we return it as a hint. This
     // will avoid a move between the two blocks.
     HBasicBlock* block = liveness.GetBlockFromPosition(GetStart() / 2);
+    size_t next_register_use = FirstRegisterUse();
     for (size_t i = 0; i < block->GetPredecessors().Size(); ++i) {
       size_t position = block->GetPredecessors().Get(i)->GetLifetimeEnd() - 1;
       // We know positions above GetStart() do not have a location yet.
@@ -348,7 +349,9 @@
         LiveInterval* existing = GetParent()->GetSiblingAt(position);
         if (existing != nullptr
             && existing->HasRegister()
-            && (free_until[existing->GetRegister()] > GetStart())) {
+            // It's worth using that register if it is available until
+            // the next use.
+            && (free_until[existing->GetRegister()] >= next_register_use)) {
           return existing->GetRegister();
         }
       }
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 82c5454..220ee6a 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -76,7 +76,7 @@
   }
 
   void Dump(std::ostream& stream) const {
-    stream << "[" << start_ << ", " << end_ << ")";
+    stream << "[" << start_ << "," << end_ << ")";
   }
 
   LiveRange* Dup(ArenaAllocator* allocator) const {
@@ -117,6 +117,7 @@
         || user->IsPhi()
         || (GetPosition() == user->GetLifetimePosition() + 1)
         || (GetPosition() == user->GetLifetimePosition()));
+    DCHECK(environment == nullptr || user == nullptr);
     DCHECK(next_ == nullptr || next->GetPosition() >= GetPosition());
   }
 
@@ -128,6 +129,7 @@
   void SetNext(UsePosition* next) { next_ = next; }
 
   HInstruction* GetUser() const { return user_; }
+  HEnvironment* GetEnvironment() const { return environment_; }
 
   bool GetIsEnvironment() const { return environment_ != nullptr; }
   bool IsSynthesized() const { return user_ == nullptr; }
@@ -280,7 +282,7 @@
       }
       DCHECK(first_use_->GetPosition() + 1 == position);
       UsePosition* new_use = new (allocator_) UsePosition(
-          instruction, environment, input_index, position, cursor->GetNext());
+          instruction, nullptr /* environment */, input_index, position, cursor->GetNext());
       cursor->SetNext(new_use);
       if (first_range_->GetEnd() == first_use_->GetPosition()) {
         first_range_->end_ = position;
@@ -290,10 +292,10 @@
 
     if (is_environment) {
       first_env_use_ = new (allocator_) UsePosition(
-          instruction, environment, input_index, position, first_env_use_);
+          nullptr /* instruction */, environment, input_index, position, first_env_use_);
     } else {
       first_use_ = new (allocator_) UsePosition(
-          instruction, environment, input_index, position, first_use_);
+          instruction, nullptr /* environment */, input_index, position, first_use_);
     }
 
     if (is_environment && !keep_alive) {
@@ -392,7 +394,7 @@
       first_range_->start_ = from;
     } else {
       // Instruction without uses.
-      DCHECK(!defined_by_->HasNonEnvironmentUses());
+      DCHECK(first_use_ == nullptr);
       DCHECK(from == defined_by_->GetLifetimePosition());
       first_range_ = last_range_ = range_search_start_ =
           new (allocator_) LiveRange(from, from + 2, nullptr);
@@ -542,6 +544,15 @@
     return defined_by_;
   }
 
+  bool HasWillCallSafepoint() const {
+    for (SafepointPosition* safepoint = first_safepoint_;
+         safepoint != nullptr;
+         safepoint = safepoint->GetNext()) {
+      if (safepoint->GetLocations()->WillCall()) return true;
+    }
+    return false;
+  }
+
   SafepointPosition* FindSafepointJustBefore(size_t position) const {
     for (SafepointPosition* safepoint = first_safepoint_, *previous = nullptr;
          safepoint != nullptr;
@@ -1208,6 +1219,7 @@
   size_t number_of_ssa_values_;
 
   ART_FRIEND_TEST(RegisterAllocatorTest, SpillInactive);
+  ART_FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
 
   DISALLOW_COPY_AND_ASSIGN(SsaLivenessAnalysis);
 };
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index c4b63ab..67351f2 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -29,7 +29,7 @@
 class SsaDeadPhiElimination : public HOptimization {
  public:
   explicit SsaDeadPhiElimination(HGraph* graph)
-      : HOptimization(graph, true, kSsaDeadPhiEliminationPassName),
+      : HOptimization(graph, kSsaDeadPhiEliminationPassName),
         worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
   void Run() OVERRIDE;
@@ -56,7 +56,7 @@
 class SsaRedundantPhiElimination : public HOptimization {
  public:
   explicit SsaRedundantPhiElimination(HGraph* graph)
-      : HOptimization(graph, true, kSsaRedundantPhiEliminationPassName),
+      : HOptimization(graph, kSsaRedundantPhiEliminationPassName),
         worklist_(graph->GetArena(), kDefaultWorklistSize) {}
 
   void Run() OVERRIDE;
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 8344fc3..65610d5 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include "stack_map_stream.h"
 
 namespace art {
@@ -50,8 +49,8 @@
   }
 
   dex_pc_max_ = std::max(dex_pc_max_, dex_pc);
-  native_pc_offset_max_ = std::max(native_pc_offset_max_, native_pc_offset);
   register_mask_max_ = std::max(register_mask_max_, register_mask);
+  current_dex_register_ = 0;
 }
 
 void StackMapStream::EndStackMapEntry() {
@@ -60,11 +59,7 @@
   current_entry_ = StackMapEntry();
 }
 
-void StackMapStream::AddDexRegisterEntry(uint16_t dex_register,
-                                         DexRegisterLocation::Kind kind,
-                                         int32_t value) {
-  DCHECK_LT(dex_register, current_entry_.num_dex_registers);
-
+void StackMapStream::AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value) {
   if (kind != DexRegisterLocation::Kind::kNone) {
     // Ensure we only use non-compressed location kind at this stage.
     DCHECK(DexRegisterLocation::IsShortLocationKind(kind))
@@ -87,18 +82,57 @@
       location_catalog_entries_indices_.Insert(std::make_pair(location, index));
     }
 
-    current_entry_.live_dex_registers_mask->SetBit(dex_register);
-    current_entry_.dex_register_map_hash +=
-      (1 << (dex_register % (sizeof(current_entry_.dex_register_map_hash) * kBitsPerByte)));
-    current_entry_.dex_register_map_hash += static_cast<uint32_t>(value);
-    current_entry_.dex_register_map_hash += static_cast<uint32_t>(kind);
+    if (in_inline_frame_) {
+      // TODO: Support sharing DexRegisterMap across InlineInfo.
+      DCHECK_LT(current_dex_register_, current_inline_info_.num_dex_registers);
+      current_inline_info_.live_dex_registers_mask->SetBit(current_dex_register_);
+    } else {
+      DCHECK_LT(current_dex_register_, current_entry_.num_dex_registers);
+      current_entry_.live_dex_registers_mask->SetBit(current_dex_register_);
+      current_entry_.dex_register_map_hash += (1 <<
+          (current_dex_register_ % (sizeof(current_entry_.dex_register_map_hash) * kBitsPerByte)));
+      current_entry_.dex_register_map_hash += static_cast<uint32_t>(value);
+      current_entry_.dex_register_map_hash += static_cast<uint32_t>(kind);
+    }
   }
+  current_dex_register_++;
 }
 
-void StackMapStream::AddInlineInfoEntry(uint32_t method_index) {
-  InlineInfoEntry entry;
-  entry.method_index = method_index;
-  inline_infos_.Add(entry);
+void StackMapStream::BeginInlineInfoEntry(uint32_t method_index,
+                                          uint32_t dex_pc,
+                                          InvokeType invoke_type,
+                                          uint32_t num_dex_registers) {
+  DCHECK(!in_inline_frame_);
+  in_inline_frame_ = true;
+  current_inline_info_.method_index = method_index;
+  current_inline_info_.dex_pc = dex_pc;
+  current_inline_info_.invoke_type = invoke_type;
+  current_inline_info_.num_dex_registers = num_dex_registers;
+  current_inline_info_.dex_register_locations_start_index = dex_register_locations_.Size();
+  if (num_dex_registers != 0) {
+    current_inline_info_.live_dex_registers_mask =
+        new (allocator_) ArenaBitVector(allocator_, num_dex_registers, true);
+  } else {
+    current_inline_info_.live_dex_registers_mask = nullptr;
+  }
+  current_dex_register_ = 0;
+}
+
+void StackMapStream::EndInlineInfoEntry() {
+  DCHECK(in_inline_frame_);
+  DCHECK_EQ(current_dex_register_, current_inline_info_.num_dex_registers)
+      << "Inline information contains less registers than expected";
+  in_inline_frame_ = false;
+  inline_infos_.Add(current_inline_info_);
+  current_inline_info_ = InlineInfoEntry();
+}
+
+uint32_t StackMapStream::ComputeMaxNativePcOffset() const {
+  uint32_t max_native_pc_offset = 0u;
+  for (size_t i = 0, size = stack_maps_.Size(); i != size; ++i) {
+    max_native_pc_offset = std::max(max_native_pc_offset, stack_maps_.Get(i).native_pc_offset);
+  }
+  return max_native_pc_offset;
 }
 
 size_t StackMapStream::PrepareForFillIn() {
@@ -106,25 +140,29 @@
   stack_mask_size_ = RoundUp(stack_mask_number_of_bits, kBitsPerByte) / kBitsPerByte;
   inline_info_size_ = ComputeInlineInfoSize();
   dex_register_maps_size_ = ComputeDexRegisterMapsSize();
-  stack_maps_size_ = stack_maps_.Size()
-      * StackMap::ComputeStackMapSize(stack_mask_size_,
-                                      inline_info_size_,
-                                      dex_register_maps_size_,
-                                      dex_pc_max_,
-                                      native_pc_offset_max_,
-                                      register_mask_max_);
+  uint32_t max_native_pc_offset = ComputeMaxNativePcOffset();
+  stack_map_encoding_ = StackMapEncoding::CreateFromSizes(stack_mask_size_,
+                                                          inline_info_size_,
+                                                          dex_register_maps_size_,
+                                                          dex_pc_max_,
+                                                          max_native_pc_offset,
+                                                          register_mask_max_);
+  stack_maps_size_ = stack_maps_.Size() * stack_map_encoding_.ComputeStackMapSize();
   dex_register_location_catalog_size_ = ComputeDexRegisterLocationCatalogSize();
 
   // Note: use RoundUp to word-size here if you want CodeInfo objects to be word aligned.
   needed_size_ = CodeInfo::kFixedSize
-      + dex_register_location_catalog_size_
       + stack_maps_size_
+      + dex_register_location_catalog_size_
       + dex_register_maps_size_
       + inline_info_size_;
 
-  dex_register_location_catalog_start_ = CodeInfo::kFixedSize;
-  stack_maps_start_ = dex_register_location_catalog_start_ + dex_register_location_catalog_size_;
-  dex_register_maps_start_ = stack_maps_start_ + stack_maps_size_;
+  stack_maps_start_ = CodeInfo::kFixedSize;
+  // TODO: Move the catalog at the end. It is currently too expensive at runtime
+  // to compute its size (note that we do not encode that size in the CodeInfo).
+  dex_register_location_catalog_start_ = stack_maps_start_ + stack_maps_size_;
+  dex_register_maps_start_ =
+      dex_register_location_catalog_start_ + dex_register_location_catalog_size_;
   inline_infos_start_ = dex_register_maps_start_ + dex_register_maps_size_;
 
   return needed_size_;
@@ -142,17 +180,18 @@
   return size;
 }
 
-size_t StackMapStream::ComputeDexRegisterMapSize(const StackMapEntry& entry) const {
+size_t StackMapStream::ComputeDexRegisterMapSize(uint32_t num_dex_registers,
+                                                 const BitVector& live_dex_registers_mask) const {
   // Size of the map in bytes.
   size_t size = DexRegisterMap::kFixedSize;
   // Add the live bit mask for the Dex register liveness.
-  size += DexRegisterMap::GetLiveBitMaskSize(entry.num_dex_registers);
+  size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers);
   // Compute the size of the set of live Dex register entries.
   size_t number_of_live_dex_registers = 0;
   for (size_t dex_register_number = 0;
-       dex_register_number < entry.num_dex_registers;
+       dex_register_number < num_dex_registers;
        ++dex_register_number) {
-    if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
+    if (live_dex_registers_mask.IsBitSet(dex_register_number)) {
       ++number_of_live_dex_registers;
     }
   }
@@ -167,11 +206,18 @@
 
 size_t StackMapStream::ComputeDexRegisterMapsSize() const {
   size_t size = 0;
+  size_t inline_info_index = 0;
   for (size_t i = 0; i < stack_maps_.Size(); ++i) {
     StackMapEntry entry = stack_maps_.Get(i);
     if (entry.same_dex_register_map_as_ == kNoSameDexMapFound) {
+      size += ComputeDexRegisterMapSize(entry.num_dex_registers, *entry.live_dex_registers_mask);
+    } else {
       // Entries with the same dex map will have the same offset.
-      size += ComputeDexRegisterMapSize(entry);
+    }
+    for (size_t j = 0; j < entry.inlining_depth; ++j) {
+      InlineInfoEntry inline_entry = inline_infos_.Get(inline_info_index++);
+      size += ComputeDexRegisterMapSize(inline_entry.num_dex_registers,
+                                        *inline_entry.live_dex_registers_mask);
     }
   }
   return size;
@@ -197,14 +243,9 @@
   MemoryRegion inline_infos_region = region.Subregion(
       inline_infos_start_, inline_info_size_);
 
-  code_info.SetEncoding(inline_info_size_,
-                        dex_register_maps_size_,
-                        dex_pc_max_,
-                        native_pc_offset_max_,
-                        register_mask_max_);
+  code_info.SetEncoding(stack_map_encoding_);
   code_info.SetNumberOfStackMaps(stack_maps_.Size());
-  code_info.SetStackMaskSize(stack_mask_size_);
-  DCHECK_EQ(code_info.GetStackMapsSize(), stack_maps_size_);
+  DCHECK_EQ(code_info.GetStackMapsSize(code_info.ExtractEncoding()), stack_maps_size_);
 
   // Set the Dex register location catalog.
   code_info.SetNumberOfDexRegisterLocationCatalogEntries(location_catalog_entries_.Size());
@@ -225,56 +266,42 @@
   uintptr_t next_dex_register_map_offset = 0;
   uintptr_t next_inline_info_offset = 0;
   for (size_t i = 0, e = stack_maps_.Size(); i < e; ++i) {
-    StackMap stack_map = code_info.GetStackMapAt(i);
+    StackMap stack_map = code_info.GetStackMapAt(i, stack_map_encoding_);
     StackMapEntry entry = stack_maps_.Get(i);
 
-    stack_map.SetDexPc(code_info, entry.dex_pc);
-    stack_map.SetNativePcOffset(code_info, entry.native_pc_offset);
-    stack_map.SetRegisterMask(code_info, entry.register_mask);
+    stack_map.SetDexPc(stack_map_encoding_, entry.dex_pc);
+    stack_map.SetNativePcOffset(stack_map_encoding_, entry.native_pc_offset);
+    stack_map.SetRegisterMask(stack_map_encoding_, entry.register_mask);
     if (entry.sp_mask != nullptr) {
-      stack_map.SetStackMask(code_info, *entry.sp_mask);
+      stack_map.SetStackMask(stack_map_encoding_, *entry.sp_mask);
     }
 
     if (entry.num_dex_registers == 0) {
       // No dex map available.
-      stack_map.SetDexRegisterMapOffset(code_info, StackMap::kNoDexRegisterMap);
+      stack_map.SetDexRegisterMapOffset(stack_map_encoding_, StackMap::kNoDexRegisterMap);
     } else {
       // Search for an entry with the same dex map.
       if (entry.same_dex_register_map_as_ != kNoSameDexMapFound) {
         // If we have a hit reuse the offset.
-        stack_map.SetDexRegisterMapOffset(code_info,
-            code_info.GetStackMapAt(entry.same_dex_register_map_as_)
-                     .GetDexRegisterMapOffset(code_info));
+        stack_map.SetDexRegisterMapOffset(
+            stack_map_encoding_,
+            code_info.GetStackMapAt(entry.same_dex_register_map_as_, stack_map_encoding_)
+                     .GetDexRegisterMapOffset(stack_map_encoding_));
       } else {
         // New dex registers maps should be added to the stack map.
-        MemoryRegion register_region =
-            dex_register_locations_region.Subregion(
-                next_dex_register_map_offset,
-                ComputeDexRegisterMapSize(entry));
+        MemoryRegion register_region = dex_register_locations_region.Subregion(
+            next_dex_register_map_offset,
+            ComputeDexRegisterMapSize(entry.num_dex_registers, *entry.live_dex_registers_mask));
         next_dex_register_map_offset += register_region.size();
         DexRegisterMap dex_register_map(register_region);
         stack_map.SetDexRegisterMapOffset(
-          code_info, register_region.start() - dex_register_locations_region.start());
+            stack_map_encoding_, register_region.start() - dex_register_locations_region.start());
 
-        // Set the live bit mask.
-        dex_register_map.SetLiveBitMask(entry.num_dex_registers, *entry.live_dex_registers_mask);
-
-        // Set the dex register location mapping data.
-        for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
-             dex_register_number < entry.num_dex_registers;
-             ++dex_register_number) {
-          if (entry.live_dex_registers_mask->IsBitSet(dex_register_number)) {
-            size_t location_catalog_entry_index =
-                dex_register_locations_.Get(entry.dex_register_locations_start_index
-                                            + index_in_dex_register_locations);
-            dex_register_map.SetLocationCatalogEntryIndex(
-                index_in_dex_register_locations,
-                location_catalog_entry_index,
-                entry.num_dex_registers,
-                location_catalog_entries_.Size());
-            ++index_in_dex_register_locations;
-          }
-        }
+        // Set the dex register location.
+        FillInDexRegisterMap(dex_register_map,
+                             entry.num_dex_registers,
+                             *entry.live_dex_registers_mask,
+                             entry.dex_register_locations_start_index);
       }
     }
 
@@ -288,21 +315,64 @@
 
       // Currently relative to the dex register map.
       stack_map.SetInlineDescriptorOffset(
-          code_info, inline_region.start() - dex_register_locations_region.start());
+          stack_map_encoding_, inline_region.start() - dex_register_locations_region.start());
 
       inline_info.SetDepth(entry.inlining_depth);
-      for (size_t j = 0; j < entry.inlining_depth; ++j) {
-        InlineInfoEntry inline_entry = inline_infos_.Get(j + entry.inline_infos_start_index);
-        inline_info.SetMethodReferenceIndexAtDepth(j, inline_entry.method_index);
+      for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
+        InlineInfoEntry inline_entry = inline_infos_.Get(depth + entry.inline_infos_start_index);
+        inline_info.SetMethodIndexAtDepth(depth, inline_entry.method_index);
+        inline_info.SetDexPcAtDepth(depth, inline_entry.dex_pc);
+        inline_info.SetInvokeTypeAtDepth(depth, inline_entry.invoke_type);
+        if (inline_entry.num_dex_registers == 0) {
+          // No dex map available.
+          inline_info.SetDexRegisterMapOffsetAtDepth(depth, StackMap::kNoDexRegisterMap);
+          DCHECK(inline_entry.live_dex_registers_mask == nullptr);
+        } else {
+          MemoryRegion register_region = dex_register_locations_region.Subregion(
+              next_dex_register_map_offset,
+              ComputeDexRegisterMapSize(inline_entry.num_dex_registers,
+                                        *inline_entry.live_dex_registers_mask));
+          next_dex_register_map_offset += register_region.size();
+          DexRegisterMap dex_register_map(register_region);
+          inline_info.SetDexRegisterMapOffsetAtDepth(
+            depth, register_region.start() - dex_register_locations_region.start());
+
+          FillInDexRegisterMap(dex_register_map,
+                               inline_entry.num_dex_registers,
+                               *inline_entry.live_dex_registers_mask,
+                               inline_entry.dex_register_locations_start_index);
+        }
       }
     } else {
       if (inline_info_size_ != 0) {
-        stack_map.SetInlineDescriptorOffset(code_info, StackMap::kNoInlineInfo);
+        stack_map.SetInlineDescriptorOffset(stack_map_encoding_, StackMap::kNoInlineInfo);
       }
     }
   }
 }
 
+void StackMapStream::FillInDexRegisterMap(DexRegisterMap dex_register_map,
+                                          uint32_t num_dex_registers,
+                                          const BitVector& live_dex_registers_mask,
+                                          uint32_t start_index_in_dex_register_locations) const {
+  dex_register_map.SetLiveBitMask(num_dex_registers, live_dex_registers_mask);
+  // Set the dex register location mapping data.
+  for (size_t dex_register_number = 0, index_in_dex_register_locations = 0;
+       dex_register_number < num_dex_registers;
+       ++dex_register_number) {
+    if (live_dex_registers_mask.IsBitSet(dex_register_number)) {
+      size_t location_catalog_entry_index = dex_register_locations_.Get(
+          start_index_in_dex_register_locations + index_in_dex_register_locations);
+      dex_register_map.SetLocationCatalogEntryIndex(
+          index_in_dex_register_locations,
+          location_catalog_entry_index,
+          num_dex_registers,
+          location_catalog_entries_.Size());
+      ++index_in_dex_register_locations;
+    }
+  }
+}
+
 size_t StackMapStream::FindEntryWithTheSameDexMap() {
   size_t current_entry_index = stack_maps_.Size();
   auto entries_it = dex_map_hash_to_stack_map_indices_.find(current_entry_.dex_register_map_hash);
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index 0c626be..550ed70 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -67,11 +67,11 @@
         inline_infos_(allocator, 2),
         stack_mask_max_(-1),
         dex_pc_max_(0),
-        native_pc_offset_max_(0),
         register_mask_max_(0),
         number_of_stack_maps_with_inline_info_(0),
         dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter()),
         current_entry_(),
+        current_inline_info_(),
         stack_mask_size_(0),
         inline_info_size_(0),
         dex_register_maps_size_(0),
@@ -81,7 +81,9 @@
         stack_maps_start_(0),
         dex_register_maps_start_(0),
         inline_infos_start_(0),
-        needed_size_(0) {}
+        needed_size_(0),
+        current_dex_register_(0),
+        in_inline_frame_(false) {}
 
   // See runtime/stack_map.h to know what these fields contain.
   struct StackMapEntry {
@@ -99,7 +101,12 @@
   };
 
   struct InlineInfoEntry {
+    uint32_t dex_pc;
     uint32_t method_index;
+    InvokeType invoke_type;
+    uint32_t num_dex_registers;
+    BitVector* live_dex_registers_mask;
+    size_t dex_register_locations_start_index;
   };
 
   void BeginStackMapEntry(uint32_t dex_pc,
@@ -110,11 +117,29 @@
                           uint8_t inlining_depth);
   void EndStackMapEntry();
 
-  void AddDexRegisterEntry(uint16_t dex_register,
-                           DexRegisterLocation::Kind kind,
-                           int32_t value);
+  void AddDexRegisterEntry(DexRegisterLocation::Kind kind, int32_t value);
 
-  void AddInlineInfoEntry(uint32_t method_index);
+  void BeginInlineInfoEntry(uint32_t method_index,
+                            uint32_t dex_pc,
+                            InvokeType invoke_type,
+                            uint32_t num_dex_registers);
+  void EndInlineInfoEntry();
+
+  size_t GetNumberOfStackMaps() const {
+    return stack_maps_.Size();
+  }
+
+  const StackMapEntry& GetStackMap(size_t i) const {
+    DCHECK_LT(i, stack_maps_.Size());
+    return stack_maps_.GetRawStorage()[i];
+  }
+
+  void SetStackMapNativePcOffset(size_t i, uint32_t native_pc_offset) {
+    DCHECK_LT(i, stack_maps_.Size());
+    stack_maps_.GetRawStorage()[i].native_pc_offset = native_pc_offset;
+  }
+
+  uint32_t ComputeMaxNativePcOffset() const;
 
   // Prepares the stream to fill in a memory region. Must be called before FillIn.
   // Returns the size (in bytes) needed to store this stream.
@@ -123,7 +148,8 @@
 
  private:
   size_t ComputeDexRegisterLocationCatalogSize() const;
-  size_t ComputeDexRegisterMapSize(const StackMapEntry& entry) const;
+  size_t ComputeDexRegisterMapSize(uint32_t num_dex_registers,
+                                   const BitVector& live_dex_registers_mask) const;
   size_t ComputeDexRegisterMapsSize() const;
   size_t ComputeInlineInfoSize() const;
 
@@ -131,6 +157,10 @@
   // or kNoSameDexMapFound if no such entry exists.
   size_t FindEntryWithTheSameDexMap();
   bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const;
+  void FillInDexRegisterMap(DexRegisterMap dex_register_map,
+                            uint32_t num_dex_registers,
+                            const BitVector& live_dex_registers_mask,
+                            uint32_t start_index_in_dex_register_locations) const;
 
   ArenaAllocator* allocator_;
   GrowableArray<StackMapEntry> stack_maps_;
@@ -148,13 +178,14 @@
   GrowableArray<InlineInfoEntry> inline_infos_;
   int stack_mask_max_;
   uint32_t dex_pc_max_;
-  uint32_t native_pc_offset_max_;
   uint32_t register_mask_max_;
   size_t number_of_stack_maps_with_inline_info_;
 
   ArenaSafeMap<uint32_t, GrowableArray<uint32_t>> dex_map_hash_to_stack_map_indices_;
 
   StackMapEntry current_entry_;
+  InlineInfoEntry current_inline_info_;
+  StackMapEncoding stack_map_encoding_;
   size_t stack_mask_size_;
   size_t inline_info_size_;
   size_t dex_register_maps_size_;
@@ -165,6 +196,8 @@
   size_t dex_register_maps_start_;
   size_t inline_infos_start_;
   size_t needed_size_;
+  uint32_t current_dex_register_;
+  bool in_inline_frame_;
 
   static constexpr uint32_t kNoSameDexMapFound = -1;
 
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 3291a77..b4ac1b4 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -41,8 +41,8 @@
   ArenaBitVector sp_mask(&arena, 0, false);
   size_t number_of_dex_registers = 2;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInStack, 0);         // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);       // Short location.
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Short location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -51,32 +51,33 @@
   stream.FillIn(region);
 
   CodeInfo code_info(region);
-  ASSERT_EQ(0u, code_info.GetStackMaskSize());
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+  ASSERT_EQ(0u, encoding.NumberOfBytesForStackMask());
   ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
 
   uint32_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
   ASSERT_EQ(2u, number_of_location_catalog_entries);
-  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog();
+  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding);
   // The Dex register location catalog contains:
   // - one 1-byte short Dex register location, and
   // - one 5-byte large Dex register location.
   size_t expected_location_catalog_size = 1u + 5u;
   ASSERT_EQ(expected_location_catalog_size, location_catalog.Size());
 
-  StackMap stack_map = code_info.GetStackMapAt(0);
-  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
-  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64)));
-  ASSERT_EQ(0u, stack_map.GetDexPc(code_info));
-  ASSERT_EQ(64u, stack_map.GetNativePcOffset(code_info));
-  ASSERT_EQ(0x3u, stack_map.GetRegisterMask(code_info));
+  StackMap stack_map = code_info.GetStackMapAt(0, encoding);
+  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding)));
+  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding)));
+  ASSERT_EQ(0u, stack_map.GetDexPc(encoding));
+  ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding));
+  ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding));
 
-  MemoryRegion stack_mask = stack_map.GetStackMask(code_info);
+  MemoryRegion stack_mask = stack_map.GetStackMask(encoding);
   ASSERT_TRUE(SameBits(stack_mask, sp_mask));
 
-  ASSERT_TRUE(stack_map.HasDexRegisterMap(code_info));
+  ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding));
   DexRegisterMap dex_register_map =
-      code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+      code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
   ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0));
   ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1));
   ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers));
@@ -86,16 +87,17 @@
   size_t expected_dex_register_map_size = 1u + 1u;
   ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size());
 
-  ASSERT_EQ(Kind::kInStack,
-            dex_register_map.GetLocationKind(0, number_of_dex_registers, code_info));
-  ASSERT_EQ(Kind::kConstant,
-            dex_register_map.GetLocationKind(1, number_of_dex_registers, code_info));
-  ASSERT_EQ(Kind::kInStack,
-            dex_register_map.GetLocationInternalKind(0, number_of_dex_registers, code_info));
-  ASSERT_EQ(Kind::kConstantLargeValue,
-            dex_register_map.GetLocationInternalKind(1, number_of_dex_registers, code_info));
-  ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(0, number_of_dex_registers, code_info));
-  ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info));
+  ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind(
+                0, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(
+                1, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationInternalKind(
+                0, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind(
+                1, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(
+                0, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info, encoding));
 
   size_t index0 = dex_register_map.GetLocationCatalogEntryIndex(
       0, number_of_dex_registers, number_of_location_catalog_entries);
@@ -112,7 +114,7 @@
   ASSERT_EQ(0, location0.GetValue());
   ASSERT_EQ(-2, location1.GetValue());
 
-  ASSERT_FALSE(stack_map.HasInlineInfo(code_info));
+  ASSERT_FALSE(stack_map.HasInlineInfo(encoding));
 }
 
 TEST(StackMapTest, Test2) {
@@ -124,19 +126,22 @@
   sp_mask1.SetBit(2);
   sp_mask1.SetBit(4);
   size_t number_of_dex_registers = 2;
+  size_t number_of_dex_registers_in_inline_info = 0;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, number_of_dex_registers, 2);
-  stream.AddDexRegisterEntry(0, Kind::kInStack, 0);         // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);       // Large location.
-  stream.AddInlineInfoEntry(42);
-  stream.AddInlineInfoEntry(82);
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);         // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
+  stream.BeginInlineInfoEntry(82, 3, kDirect, number_of_dex_registers_in_inline_info);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(42, 2, kStatic, number_of_dex_registers_in_inline_info);
+  stream.EndInlineInfoEntry();
   stream.EndStackMapEntry();
 
   ArenaBitVector sp_mask2(&arena, 0, true);
   sp_mask2.SetBit(3);
-  sp_mask1.SetBit(8);
+  sp_mask2.SetBit(8);
   stream.BeginStackMapEntry(1, 128, 0xFF, &sp_mask2, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 18);     // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kInFpuRegister, 3);   // Short location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 18);     // Short location.
+  stream.AddDexRegisterEntry(Kind::kInFpuRegister, 3);   // Short location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -145,13 +150,14 @@
   stream.FillIn(region);
 
   CodeInfo code_info(region);
-  ASSERT_EQ(1u, code_info.GetStackMaskSize());
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+  ASSERT_EQ(2u, encoding.NumberOfBytesForStackMask());
   ASSERT_EQ(2u, code_info.GetNumberOfStackMaps());
 
   uint32_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
   ASSERT_EQ(4u, number_of_location_catalog_entries);
-  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog();
+  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding);
   // The Dex register location catalog contains:
   // - three 1-byte short Dex register locations, and
   // - one 5-byte large Dex register location.
@@ -160,19 +166,19 @@
 
   // First stack map.
   {
-    StackMap stack_map = code_info.GetStackMapAt(0);
-    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
-    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64)));
-    ASSERT_EQ(0u, stack_map.GetDexPc(code_info));
-    ASSERT_EQ(64u, stack_map.GetNativePcOffset(code_info));
-    ASSERT_EQ(0x3u, stack_map.GetRegisterMask(code_info));
+    StackMap stack_map = code_info.GetStackMapAt(0, encoding);
+    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding)));
+    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding)));
+    ASSERT_EQ(0u, stack_map.GetDexPc(encoding));
+    ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding));
+    ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding));
 
-    MemoryRegion stack_mask = stack_map.GetStackMask(code_info);
+    MemoryRegion stack_mask = stack_map.GetStackMask(encoding);
     ASSERT_TRUE(SameBits(stack_mask, sp_mask1));
 
-    ASSERT_TRUE(stack_map.HasDexRegisterMap(code_info));
+    ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding));
     DexRegisterMap dex_register_map =
-        code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+        code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
     ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0));
     ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1));
     ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers));
@@ -182,16 +188,17 @@
     size_t expected_dex_register_map_size = 1u + 1u;
     ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size());
 
-    ASSERT_EQ(Kind::kInStack,
-              dex_register_map.GetLocationKind(0, number_of_dex_registers, code_info));
-    ASSERT_EQ(Kind::kConstant,
-              dex_register_map.GetLocationKind(1, number_of_dex_registers, code_info));
-    ASSERT_EQ(Kind::kInStack,
-              dex_register_map.GetLocationInternalKind(0, number_of_dex_registers, code_info));
-    ASSERT_EQ(Kind::kConstantLargeValue,
-              dex_register_map.GetLocationInternalKind(1, number_of_dex_registers, code_info));
-    ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(0, number_of_dex_registers, code_info));
-    ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info));
+    ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind(
+                  0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(
+                  1, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationInternalKind(
+                  0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind(
+                  1, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes(
+                  0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info, encoding));
 
     size_t index0 = dex_register_map.GetLocationCatalogEntryIndex(
         0, number_of_dex_registers, number_of_location_catalog_entries);
@@ -208,28 +215,32 @@
     ASSERT_EQ(0, location0.GetValue());
     ASSERT_EQ(-2, location1.GetValue());
 
-    ASSERT_TRUE(stack_map.HasInlineInfo(code_info));
-    InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map);
+    ASSERT_TRUE(stack_map.HasInlineInfo(encoding));
+    InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
     ASSERT_EQ(2u, inline_info.GetDepth());
-    ASSERT_EQ(42u, inline_info.GetMethodReferenceIndexAtDepth(0));
-    ASSERT_EQ(82u, inline_info.GetMethodReferenceIndexAtDepth(1));
+    ASSERT_EQ(82u, inline_info.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(42u, inline_info.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(0));
+    ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(1));
+    ASSERT_EQ(kDirect, inline_info.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(kStatic, inline_info.GetInvokeTypeAtDepth(1));
   }
 
   // Second stack map.
   {
-    StackMap stack_map = code_info.GetStackMapAt(1);
-    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u)));
-    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u)));
-    ASSERT_EQ(1u, stack_map.GetDexPc(code_info));
-    ASSERT_EQ(128u, stack_map.GetNativePcOffset(code_info));
-    ASSERT_EQ(0xFFu, stack_map.GetRegisterMask(code_info));
+    StackMap stack_map = code_info.GetStackMapAt(1, encoding);
+    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u, encoding)));
+    ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u, encoding)));
+    ASSERT_EQ(1u, stack_map.GetDexPc(encoding));
+    ASSERT_EQ(128u, stack_map.GetNativePcOffset(encoding));
+    ASSERT_EQ(0xFFu, stack_map.GetRegisterMask(encoding));
 
-    MemoryRegion stack_mask = stack_map.GetStackMask(code_info);
+    MemoryRegion stack_mask = stack_map.GetStackMask(encoding);
     ASSERT_TRUE(SameBits(stack_mask, sp_mask2));
 
-    ASSERT_TRUE(stack_map.HasDexRegisterMap(code_info));
+    ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding));
     DexRegisterMap dex_register_map =
-        code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+        code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
     ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0));
     ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1));
     ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers));
@@ -239,16 +250,18 @@
     size_t expected_dex_register_map_size = 1u + 1u;
     ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size());
 
-    ASSERT_EQ(Kind::kInRegister,
-              dex_register_map.GetLocationKind(0, number_of_dex_registers, code_info));
-    ASSERT_EQ(Kind::kInFpuRegister,
-              dex_register_map.GetLocationKind(1, number_of_dex_registers, code_info));
-    ASSERT_EQ(Kind::kInRegister,
-              dex_register_map.GetLocationInternalKind(0, number_of_dex_registers, code_info));
-    ASSERT_EQ(Kind::kInFpuRegister,
-              dex_register_map.GetLocationInternalKind(1, number_of_dex_registers, code_info));
-    ASSERT_EQ(18, dex_register_map.GetMachineRegister(0, number_of_dex_registers, code_info));
-    ASSERT_EQ(3, dex_register_map.GetMachineRegister(1, number_of_dex_registers, code_info));
+    ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind(
+                  0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind(
+                  1, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationInternalKind(
+                  0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationInternalKind(
+                  1, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(18, dex_register_map.GetMachineRegister(
+                  0, number_of_dex_registers, code_info, encoding));
+    ASSERT_EQ(3, dex_register_map.GetMachineRegister(
+                  1, number_of_dex_registers, code_info, encoding));
 
     size_t index0 = dex_register_map.GetLocationCatalogEntryIndex(
         0, number_of_dex_registers, number_of_location_catalog_entries);
@@ -265,7 +278,7 @@
     ASSERT_EQ(18, location0.GetValue());
     ASSERT_EQ(3, location1.GetValue());
 
-    ASSERT_FALSE(stack_map.HasInlineInfo(code_info));
+    ASSERT_FALSE(stack_map.HasInlineInfo(encoding));
   }
 }
 
@@ -277,8 +290,8 @@
   ArenaBitVector sp_mask(&arena, 0, false);
   uint32_t number_of_dex_registers = 2;
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kNone, 0);            // No location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);       // Large location.
+  stream.AddDexRegisterEntry(Kind::kNone, 0);            // No location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);       // Large location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -287,28 +300,29 @@
   stream.FillIn(region);
 
   CodeInfo code_info(region);
-  ASSERT_EQ(0u, code_info.GetStackMaskSize());
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+  ASSERT_EQ(0u, encoding.NumberOfBytesForStackMask());
   ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
 
   uint32_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
   ASSERT_EQ(1u, number_of_location_catalog_entries);
-  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog();
+  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding);
   // The Dex register location catalog contains:
   // - one 5-byte large Dex register location.
   size_t expected_location_catalog_size = 5u;
   ASSERT_EQ(expected_location_catalog_size, location_catalog.Size());
 
-  StackMap stack_map = code_info.GetStackMapAt(0);
-  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
-  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64)));
-  ASSERT_EQ(0u, stack_map.GetDexPc(code_info));
-  ASSERT_EQ(64u, stack_map.GetNativePcOffset(code_info));
-  ASSERT_EQ(0x3u, stack_map.GetRegisterMask(code_info));
+  StackMap stack_map = code_info.GetStackMapAt(0, encoding);
+  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding)));
+  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding)));
+  ASSERT_EQ(0u, stack_map.GetDexPc(encoding));
+  ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding));
+  ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding));
 
-  ASSERT_TRUE(stack_map.HasDexRegisterMap(code_info));
+  ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding));
   DexRegisterMap dex_register_map =
-      code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+      code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
   ASSERT_FALSE(dex_register_map.IsDexRegisterLive(0));
   ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1));
   ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers));
@@ -318,15 +332,15 @@
   size_t expected_dex_register_map_size = 1u + 0u;
   ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size());
 
-  ASSERT_EQ(Kind::kNone,
-            dex_register_map.GetLocationKind(0, number_of_dex_registers, code_info));
-  ASSERT_EQ(Kind::kConstant,
-            dex_register_map.GetLocationKind(1, number_of_dex_registers, code_info));
-  ASSERT_EQ(Kind::kNone,
-            dex_register_map.GetLocationInternalKind(0, number_of_dex_registers, code_info));
-  ASSERT_EQ(Kind::kConstantLargeValue,
-            dex_register_map.GetLocationInternalKind(1, number_of_dex_registers, code_info));
-  ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info));
+  ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationKind(
+                0, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind(
+                1, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationInternalKind(
+                0, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind(
+                1, number_of_dex_registers, code_info, encoding));
+  ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info, encoding));
 
   size_t index0 = dex_register_map.GetLocationCatalogEntryIndex(
       0, number_of_dex_registers, number_of_location_catalog_entries);
@@ -343,7 +357,7 @@
   ASSERT_EQ(0, location0.GetValue());
   ASSERT_EQ(-2, location1.GetValue());
 
-  ASSERT_FALSE(stack_map.HasInlineInfo(code_info));
+  ASSERT_FALSE(stack_map.HasInlineInfo(encoding));
 }
 
 // Generate a stack map whose dex register offset is
@@ -364,13 +378,13 @@
     // as using a single value (in the whole CodeInfo object) would
     // make this Dex register mapping data empty (see
     // art::DexRegisterMap::SingleEntrySizeInBits).
-    stream.AddDexRegisterEntry(i, Kind::kConstant, i % 2);  // Short location.
+    stream.AddDexRegisterEntry(Kind::kConstant, i % 2);  // Short location.
   }
   stream.EndStackMapEntry();
   // Create the second stack map (and its Dex register map).
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
   for (uint32_t i = 0; i < number_of_dex_registers; ++i) {
-    stream.AddDexRegisterEntry(i, Kind::kConstant, 0);  // Short location.
+    stream.AddDexRegisterEntry(Kind::kConstant, 0);  // Short location.
   }
   stream.EndStackMapEntry();
 
@@ -380,6 +394,7 @@
   stream.FillIn(region);
 
   CodeInfo code_info(region);
+  StackMapEncoding encoding = code_info.ExtractEncoding();
   // The location catalog contains two entries (DexRegisterLocation(kConstant, 0)
   // and DexRegisterLocation(kConstant, 1)), therefore the location catalog index
   // has a size of 1 bit.
@@ -395,20 +410,20 @@
   //   locations (that is, 127 bytes of data).
   // Hence it has a size of 255 bytes, and therefore...
   ASSERT_EQ(128u, DexRegisterMap::GetLiveBitMaskSize(number_of_dex_registers));
-  StackMap stack_map0 = code_info.GetStackMapAt(0);
+  StackMap stack_map0 = code_info.GetStackMapAt(0, encoding);
   DexRegisterMap dex_register_map0 =
-      code_info.GetDexRegisterMapOf(stack_map0, number_of_dex_registers);
+      code_info.GetDexRegisterMapOf(stack_map0, encoding, number_of_dex_registers);
   ASSERT_EQ(127u, dex_register_map0.GetLocationMappingDataSize(number_of_dex_registers,
                                                                number_of_location_catalog_entries));
   ASSERT_EQ(255u, dex_register_map0.Size());
 
-  StackMap stack_map1 = code_info.GetStackMapAt(1);
-  ASSERT_TRUE(stack_map1.HasDexRegisterMap(code_info));
+  StackMap stack_map1 = code_info.GetStackMapAt(1, encoding);
+  ASSERT_TRUE(stack_map1.HasDexRegisterMap(encoding));
   // ...the offset of the second Dex register map (relative to the
   // beginning of the Dex register maps region) is 255 (i.e.,
   // kNoDexRegisterMapSmallEncoding).
-  ASSERT_NE(stack_map1.GetDexRegisterMapOffset(code_info), StackMap::kNoDexRegisterMap);
-  ASSERT_EQ(stack_map1.GetDexRegisterMapOffset(code_info), 0xFFu);
+  ASSERT_NE(stack_map1.GetDexRegisterMapOffset(encoding), StackMap::kNoDexRegisterMap);
+  ASSERT_EQ(stack_map1.GetDexRegisterMapOffset(encoding), 0xFFu);
 }
 
 TEST(StackMapTest, TestShareDexRegisterMap) {
@@ -420,18 +435,18 @@
   uint32_t number_of_dex_registers = 2;
   // First stack map.
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 0);  // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);   // Large location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 0);  // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
   stream.EndStackMapEntry();
   // Second stack map, which should share the same dex register map.
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 0);  // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);   // Large location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 0);  // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
   stream.EndStackMapEntry();
   // Third stack map (doesn't share the dex register map).
   stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask, number_of_dex_registers, 0);
-  stream.AddDexRegisterEntry(0, Kind::kInRegister, 2);  // Short location.
-  stream.AddDexRegisterEntry(1, Kind::kConstant, -2);   // Large location.
+  stream.AddDexRegisterEntry(Kind::kInRegister, 2);  // Short location.
+  stream.AddDexRegisterEntry(Kind::kConstant, -2);   // Large location.
   stream.EndStackMapEntry();
 
   size_t size = stream.PrepareForFillIn();
@@ -440,28 +455,30 @@
   stream.FillIn(region);
 
   CodeInfo ci(region);
+  StackMapEncoding encoding = ci.ExtractEncoding();
+
   // Verify first stack map.
-  StackMap sm0 = ci.GetStackMapAt(0);
-  DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, number_of_dex_registers);
-  ASSERT_EQ(0, dex_registers0.GetMachineRegister(0, number_of_dex_registers, ci));
-  ASSERT_EQ(-2, dex_registers0.GetConstant(1, number_of_dex_registers, ci));
+  StackMap sm0 = ci.GetStackMapAt(0, encoding);
+  DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, encoding, number_of_dex_registers);
+  ASSERT_EQ(0, dex_registers0.GetMachineRegister(0, number_of_dex_registers, ci, encoding));
+  ASSERT_EQ(-2, dex_registers0.GetConstant(1, number_of_dex_registers, ci, encoding));
 
   // Verify second stack map.
-  StackMap sm1 = ci.GetStackMapAt(1);
-  DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1, number_of_dex_registers);
-  ASSERT_EQ(0, dex_registers1.GetMachineRegister(0, number_of_dex_registers, ci));
-  ASSERT_EQ(-2, dex_registers1.GetConstant(1, number_of_dex_registers, ci));
+  StackMap sm1 = ci.GetStackMapAt(1, encoding);
+  DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1, encoding, number_of_dex_registers);
+  ASSERT_EQ(0, dex_registers1.GetMachineRegister(0, number_of_dex_registers, ci, encoding));
+  ASSERT_EQ(-2, dex_registers1.GetConstant(1, number_of_dex_registers, ci, encoding));
 
   // Verify third stack map.
-  StackMap sm2 = ci.GetStackMapAt(2);
-  DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2, number_of_dex_registers);
-  ASSERT_EQ(2, dex_registers2.GetMachineRegister(0, number_of_dex_registers, ci));
-  ASSERT_EQ(-2, dex_registers2.GetConstant(1, number_of_dex_registers, ci));
+  StackMap sm2 = ci.GetStackMapAt(2, encoding);
+  DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2, encoding, number_of_dex_registers);
+  ASSERT_EQ(2, dex_registers2.GetMachineRegister(0, number_of_dex_registers, ci, encoding));
+  ASSERT_EQ(-2, dex_registers2.GetConstant(1, number_of_dex_registers, ci, encoding));
 
   // Verify dex register map offsets.
-  ASSERT_EQ(sm0.GetDexRegisterMapOffset(ci), sm1.GetDexRegisterMapOffset(ci));
-  ASSERT_NE(sm0.GetDexRegisterMapOffset(ci), sm2.GetDexRegisterMapOffset(ci));
-  ASSERT_NE(sm1.GetDexRegisterMapOffset(ci), sm2.GetDexRegisterMapOffset(ci));
+  ASSERT_EQ(sm0.GetDexRegisterMapOffset(encoding), sm1.GetDexRegisterMapOffset(encoding));
+  ASSERT_NE(sm0.GetDexRegisterMapOffset(encoding), sm2.GetDexRegisterMapOffset(encoding));
+  ASSERT_NE(sm1.GetDexRegisterMapOffset(encoding), sm2.GetDexRegisterMapOffset(encoding));
 }
 
 TEST(StackMapTest, TestNoDexRegisterMap) {
@@ -480,24 +497,197 @@
   stream.FillIn(region);
 
   CodeInfo code_info(region);
-  ASSERT_EQ(0u, code_info.GetStackMaskSize());
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+  ASSERT_EQ(0u, encoding.NumberOfBytesForStackMask());
   ASSERT_EQ(1u, code_info.GetNumberOfStackMaps());
 
   uint32_t number_of_location_catalog_entries =
       code_info.GetNumberOfDexRegisterLocationCatalogEntries();
   ASSERT_EQ(0u, number_of_location_catalog_entries);
-  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog();
+  DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding);
   ASSERT_EQ(0u, location_catalog.Size());
 
-  StackMap stack_map = code_info.GetStackMapAt(0);
-  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0)));
-  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64)));
-  ASSERT_EQ(0u, stack_map.GetDexPc(code_info));
-  ASSERT_EQ(64u, stack_map.GetNativePcOffset(code_info));
-  ASSERT_EQ(0x3u, stack_map.GetRegisterMask(code_info));
+  StackMap stack_map = code_info.GetStackMapAt(0, encoding);
+  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding)));
+  ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding)));
+  ASSERT_EQ(0u, stack_map.GetDexPc(encoding));
+  ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding));
+  ASSERT_EQ(0x3u, stack_map.GetRegisterMask(encoding));
 
-  ASSERT_FALSE(stack_map.HasDexRegisterMap(code_info));
-  ASSERT_FALSE(stack_map.HasInlineInfo(code_info));
+  ASSERT_FALSE(stack_map.HasDexRegisterMap(encoding));
+  ASSERT_FALSE(stack_map.HasInlineInfo(encoding));
+}
+
+TEST(StackMapTest, InlineTest) {
+  ArenaPool pool;
+  ArenaAllocator arena(&pool);
+  StackMapStream stream(&arena);
+
+  ArenaBitVector sp_mask1(&arena, 0, true);
+  sp_mask1.SetBit(2);
+  sp_mask1.SetBit(4);
+
+  // First stack map.
+  stream.BeginStackMapEntry(0, 64, 0x3, &sp_mask1, 2, 2);
+  stream.AddDexRegisterEntry(Kind::kInStack, 0);
+  stream.AddDexRegisterEntry(Kind::kConstant, 4);
+
+  stream.BeginInlineInfoEntry(42, 2, kStatic, 1);
+  stream.AddDexRegisterEntry(Kind::kInStack, 8);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(82, 3, kStatic, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 16);
+  stream.AddDexRegisterEntry(Kind::kConstant, 20);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 15);
+  stream.EndInlineInfoEntry();
+
+  stream.EndStackMapEntry();
+
+  // Second stack map.
+  stream.BeginStackMapEntry(2, 22, 0x3, &sp_mask1, 2, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 56);
+  stream.AddDexRegisterEntry(Kind::kConstant, 0);
+
+  stream.BeginInlineInfoEntry(42, 2, kDirect, 1);
+  stream.AddDexRegisterEntry(Kind::kInStack, 12);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(82, 3, kStatic, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 80);
+  stream.AddDexRegisterEntry(Kind::kConstant, 10);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 5);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(52, 5, kVirtual, 0);
+  stream.EndInlineInfoEntry();
+
+  stream.EndStackMapEntry();
+
+  // Third stack map.
+  stream.BeginStackMapEntry(4, 56, 0x3, &sp_mask1, 2, 0);
+  stream.AddDexRegisterEntry(Kind::kNone, 0);
+  stream.AddDexRegisterEntry(Kind::kConstant, 4);
+  stream.EndStackMapEntry();
+
+  // Fourth stack map.
+  stream.BeginStackMapEntry(6, 78, 0x3, &sp_mask1, 2, 3);
+  stream.AddDexRegisterEntry(Kind::kInStack, 56);
+  stream.AddDexRegisterEntry(Kind::kConstant, 0);
+
+  stream.BeginInlineInfoEntry(42, 2, kVirtual, 0);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(52, 5, kInterface, 1);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 2);
+  stream.EndInlineInfoEntry();
+  stream.BeginInlineInfoEntry(52, 10, kStatic, 2);
+  stream.AddDexRegisterEntry(Kind::kNone, 0);
+  stream.AddDexRegisterEntry(Kind::kInRegister, 3);
+  stream.EndInlineInfoEntry();
+
+  stream.EndStackMapEntry();
+
+  size_t size = stream.PrepareForFillIn();
+  void* memory = arena.Alloc(size, kArenaAllocMisc);
+  MemoryRegion region(memory, size);
+  stream.FillIn(region);
+
+  CodeInfo ci(region);
+  StackMapEncoding encoding = ci.ExtractEncoding();
+
+  {
+    // Verify first stack map.
+    StackMap sm0 = ci.GetStackMapAt(0, encoding);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, encoding, 2);
+    ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0, 2, ci, encoding));
+    ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci, encoding));
+
+    InlineInfo if0 = ci.GetInlineInfoOf(sm0, encoding);
+    ASSERT_EQ(2u, if0.GetDepth());
+    ASSERT_EQ(2u, if0.GetDexPcAtDepth(0));
+    ASSERT_EQ(42u, if0.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(3u, if0.GetDexPcAtDepth(1));
+    ASSERT_EQ(82u, if0.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(1));
+
+    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, encoding, 1);
+    ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding));
+
+    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, encoding, 3);
+    ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0, 3, ci, encoding));
+    ASSERT_EQ(20, dex_registers2.GetConstant(1, 3, ci, encoding));
+    ASSERT_EQ(15, dex_registers2.GetMachineRegister(2, 3, ci, encoding));
+  }
+
+  {
+    // Verify second stack map.
+    StackMap sm1 = ci.GetStackMapAt(1, encoding);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1, encoding, 2);
+    ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci, encoding));
+    ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci, encoding));
+
+    InlineInfo if1 = ci.GetInlineInfoOf(sm1, encoding);
+    ASSERT_EQ(3u, if1.GetDepth());
+    ASSERT_EQ(2u, if1.GetDexPcAtDepth(0));
+    ASSERT_EQ(42u, if1.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(kDirect, if1.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(3u, if1.GetDexPcAtDepth(1));
+    ASSERT_EQ(82u, if1.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(kStatic, if1.GetInvokeTypeAtDepth(1));
+    ASSERT_EQ(5u, if1.GetDexPcAtDepth(2));
+    ASSERT_EQ(52u, if1.GetMethodIndexAtDepth(2));
+    ASSERT_EQ(kVirtual, if1.GetInvokeTypeAtDepth(2));
+
+    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, encoding, 1);
+    ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding));
+
+    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, encoding, 3);
+    ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0, 3, ci, encoding));
+    ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci, encoding));
+    ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci, encoding));
+
+    ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2));
+  }
+
+  {
+    // Verify third stack map.
+    StackMap sm2 = ci.GetStackMapAt(2, encoding);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2, encoding, 2);
+    ASSERT_FALSE(dex_registers0.IsDexRegisterLive(0));
+    ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci, encoding));
+    ASSERT_FALSE(sm2.HasInlineInfo(encoding));
+  }
+
+  {
+    // Verify fourth stack map.
+    StackMap sm3 = ci.GetStackMapAt(3, encoding);
+
+    DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3, encoding, 2);
+    ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci, encoding));
+    ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci, encoding));
+
+    InlineInfo if2 = ci.GetInlineInfoOf(sm3, encoding);
+    ASSERT_EQ(3u, if2.GetDepth());
+    ASSERT_EQ(2u, if2.GetDexPcAtDepth(0));
+    ASSERT_EQ(42u, if2.GetMethodIndexAtDepth(0));
+    ASSERT_EQ(kVirtual, if2.GetInvokeTypeAtDepth(0));
+    ASSERT_EQ(5u, if2.GetDexPcAtDepth(1));
+    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(1));
+    ASSERT_EQ(kInterface, if2.GetInvokeTypeAtDepth(1));
+    ASSERT_EQ(10u, if2.GetDexPcAtDepth(2));
+    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(2));
+    ASSERT_EQ(kStatic, if2.GetInvokeTypeAtDepth(2));
+
+    ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0));
+
+    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, encoding, 1);
+    ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci, encoding));
+
+    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, encoding, 2);
+    ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0));
+    ASSERT_EQ(3, dex_registers2.GetMachineRegister(1, 2, ci, encoding));
+  }
 }
 
 }  // namespace art
diff --git a/compiler/trampolines/trampoline_compiler.cc b/compiler/trampolines/trampoline_compiler.cc
index cb51ed8..facc630 100644
--- a/compiler/trampolines/trampoline_compiler.cc
+++ b/compiler/trampolines/trampoline_compiler.cc
@@ -17,21 +17,21 @@
 #include "trampoline_compiler.h"
 
 #include "jni_env_ext.h"
-#include "utils/arm/assembler_arm.h"
+#include "utils/arm/assembler_thumb2.h"
 #include "utils/arm64/assembler_arm64.h"
 #include "utils/mips/assembler_mips.h"
 #include "utils/mips64/assembler_mips64.h"
 #include "utils/x86/assembler_x86.h"
 #include "utils/x86_64/assembler_x86_64.h"
 
-#define __ assembler->
+#define __ assembler.
 
 namespace art {
 
 namespace arm {
 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
                                                     ThreadOffset<4> offset) {
-  std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kThumb2)));
+  Thumb2Assembler assembler;
 
   switch (abi) {
     case kInterpreterAbi:  // Thread* is first argument (R0) in interpreter ABI.
@@ -46,10 +46,11 @@
   }
   __ bkpt(0);
 
-  size_t cs = assembler->CodeSize();
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
-  assembler->FinalizeInstructions(code);
+  __ FinalizeInstructions(code);
 
   return entry_stub.release();
 }
@@ -58,7 +59,7 @@
 namespace arm64 {
 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
                                                     ThreadOffset<8> offset) {
-  std::unique_ptr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
+  Arm64Assembler assembler;
 
   switch (abi) {
     case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
@@ -82,11 +83,11 @@
       break;
   }
 
-  assembler->EmitSlowPaths();
-  size_t cs = assembler->CodeSize();
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
-  assembler->FinalizeInstructions(code);
+  __ FinalizeInstructions(code);
 
   return entry_stub.release();
 }
@@ -95,7 +96,7 @@
 namespace mips {
 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
                                                     ThreadOffset<4> offset) {
-  std::unique_ptr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
+  MipsAssembler assembler;
 
   switch (abi) {
     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
@@ -112,10 +113,11 @@
   __ Nop();
   __ Break();
 
-  size_t cs = assembler->CodeSize();
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
-  assembler->FinalizeInstructions(code);
+  __ FinalizeInstructions(code);
 
   return entry_stub.release();
 }
@@ -124,7 +126,7 @@
 namespace mips64 {
 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
                                                     ThreadOffset<8> offset) {
-  std::unique_ptr<Mips64Assembler> assembler(static_cast<Mips64Assembler*>(Assembler::Create(kMips64)));
+  Mips64Assembler assembler;
 
   switch (abi) {
     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
@@ -141,10 +143,11 @@
   __ Nop();
   __ Break();
 
-  size_t cs = assembler->CodeSize();
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
-  assembler->FinalizeInstructions(code);
+  __ FinalizeInstructions(code);
 
   return entry_stub.release();
 }
@@ -152,16 +155,17 @@
 
 namespace x86 {
 static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
-  std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
+  X86Assembler assembler;
 
   // All x86 trampolines call via the Thread* held in fs.
   __ fs()->jmp(Address::Absolute(offset));
   __ int3();
 
-  size_t cs = assembler->CodeSize();
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
-  assembler->FinalizeInstructions(code);
+  __ FinalizeInstructions(code);
 
   return entry_stub.release();
 }
@@ -169,17 +173,17 @@
 
 namespace x86_64 {
 static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
-  std::unique_ptr<x86_64::X86_64Assembler>
-      assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
+  x86_64::X86_64Assembler assembler;
 
   // All x86 trampolines call via the Thread* held in gs.
   __ gs()->jmp(x86_64::Address::Absolute(offset, true));
   __ int3();
 
-  size_t cs = assembler->CodeSize();
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
-  assembler->FinalizeInstructions(code);
+  __ FinalizeInstructions(code);
 
   return entry_stub.release();
 }
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index cbbc116..09d2270 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -529,13 +529,13 @@
 }
 
 void ArmAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-                           bool poison_reference) {
+                           bool unpoison_reference) {
   ArmManagedRegister dst = mdest.AsArm();
   CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
   LoadFromOffset(kLoadWord, dst.AsCoreRegister(),
                  base.AsArm().AsCoreRegister(), offs.Int32Value());
-  if (kPoisonHeapReferences && poison_reference) {
-    rsb(dst.AsCoreRegister(), dst.AsCoreRegister(), ShifterOperand(0));
+  if (unpoison_reference) {
+    MaybeUnpoisonHeapReference(dst.AsCoreRegister());
   }
 }
 
@@ -860,8 +860,6 @@
   // Set up call to Thread::Current()->pDeliverException.
   __ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(4, pDeliverException).Int32Value());
   __ blx(R12);
-  // Call never returns.
-  __ bkpt(0);
 #undef __
 }
 
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index c673c6b..5d85d11 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_H_
 
+#include <type_traits>
 #include <vector>
 
 #include "base/bit_utils.h"
@@ -33,6 +34,49 @@
 class Arm32Assembler;
 class Thumb2Assembler;
 
+// Assembler literal is a value embedded in code, retrieved using a PC-relative load.
+class Literal {
+ public:
+  static constexpr size_t kMaxSize = 8;
+
+  Literal(uint32_t size, const uint8_t* data)
+      : label_(), size_(size) {
+    DCHECK_LE(size, Literal::kMaxSize);
+    memcpy(data_, data, size);
+  }
+
+  template <typename T>
+  T GetValue() const {
+    DCHECK_EQ(size_, sizeof(T));
+    T value;
+    memcpy(&value, data_, sizeof(T));
+    return value;
+  }
+
+  uint32_t GetSize() const {
+    return size_;
+  }
+
+  const uint8_t* GetData() const {
+    return data_;
+  }
+
+  Label* GetLabel() {
+    return &label_;
+  }
+
+  const Label* GetLabel() const {
+    return &label_;
+  }
+
+ private:
+  Label label_;
+  const uint32_t size_;
+  uint8_t data_[kMaxSize];
+
+  DISALLOW_COPY_AND_ASSIGN(Literal);
+};
+
 class ShifterOperand {
  public:
   ShifterOperand() : type_(kUnknown), rm_(kNoRegister), rs_(kNoRegister),
@@ -398,6 +442,8 @@
                    Condition cond = AL) = 0;
   virtual void mls(Register rd, Register rn, Register rm, Register ra,
                    Condition cond = AL) = 0;
+  virtual void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+                     Condition cond = AL) = 0;
   virtual void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
                      Condition cond = AL) = 0;
 
@@ -526,9 +572,41 @@
 
   void Pad(uint32_t bytes);
 
+  // Adjust label position.
+  void AdjustLabelPosition(Label* label) {
+    DCHECK(label->IsBound());
+    uint32_t old_position = static_cast<uint32_t>(label->Position());
+    uint32_t new_position = GetAdjustedPosition(old_position);
+    label->Reinitialize();
+    DCHECK_GE(static_cast<int>(new_position), 0);
+    label->BindTo(static_cast<int>(new_position));
+  }
+
+  // Get the final position of a label after local fixup based on the old position
+  // recorded before FinalizeCode().
+  virtual uint32_t GetAdjustedPosition(uint32_t old_position) = 0;
+
   // Macros.
   // Most of these are pure virtual as they need to be implemented per instruction set.
 
+  // Create a new literal with a given value.
+  // NOTE: Force the template parameter to be explicitly specified. In the absence of
+  // std::omit_from_type_deduction<T> or std::identity<T>, use std::decay<T>.
+  template <typename T>
+  Literal* NewLiteral(typename std::decay<T>::type value) {
+    static_assert(std::is_integral<T>::value, "T must be an integral type.");
+    return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
+  }
+
+  // Create a new literal with the given data.
+  virtual Literal* NewLiteral(size_t size, const uint8_t* data) = 0;
+
+  // Load literal.
+  virtual void LoadLiteral(Register rt, Literal* literal) = 0;
+  virtual void LoadLiteral(Register rt, Register rt2, Literal* literal) = 0;
+  virtual void LoadLiteral(SRegister sd, Literal* literal) = 0;
+  virtual void LoadLiteral(DRegister dd, Literal* literal) = 0;
+
   // Add signed constant value to rd. May clobber IP.
   virtual void AddConstant(Register rd, int32_t value, Condition cond = AL) = 0;
   virtual void AddConstant(Register rd, Register rn, int32_t value,
@@ -696,7 +774,7 @@
   void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
 
   void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
-               bool poison_reference) OVERRIDE;
+               bool unpoison_reference) OVERRIDE;
 
   void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
 
@@ -779,6 +857,27 @@
      return r >= R8;
   }
 
+  //
+  // Heap poisoning.
+  //
+
+  // Poison a heap reference contained in `reg`.
+  void PoisonHeapReference(Register reg) {
+    // reg = -reg.
+    rsb(reg, reg, ShifterOperand(0));
+  }
+  // Unpoison a heap reference contained in `reg`.
+  void UnpoisonHeapReference(Register reg) {
+    // reg = -reg.
+    rsb(reg, reg, ShifterOperand(0));
+  }
+  // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
+  void MaybeUnpoisonHeapReference(Register reg) {
+    if (kPoisonHeapReferences) {
+      UnpoisonHeapReference(reg);
+    }
+  }
+
  protected:
   // Returns whether or not the given register is used for passing parameters.
   static int RegisterCompare(const Register* reg1, const Register* reg2) {
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index 1c8ea42..6e60ddc 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -200,6 +200,13 @@
 }
 
 
+void Arm32Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
+                           Register rm, Condition cond) {
+  // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+  EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
+}
+
+
 void Arm32Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
                            Register rm, Condition cond) {
   // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
@@ -1347,6 +1354,41 @@
 }
 
 
+uint32_t Arm32Assembler::GetAdjustedPosition(uint32_t old_position ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "Unimplemented.";
+  UNREACHABLE();
+}
+
+Literal* Arm32Assembler::NewLiteral(size_t size ATTRIBUTE_UNUSED,
+                                    const uint8_t* data ATTRIBUTE_UNUSED)  {
+  LOG(FATAL) << "Unimplemented.";
+  UNREACHABLE();
+}
+
+void Arm32Assembler::LoadLiteral(Register rt ATTRIBUTE_UNUSED,
+                                 Literal* literal ATTRIBUTE_UNUSED)  {
+  LOG(FATAL) << "Unimplemented.";
+  UNREACHABLE();
+}
+
+void Arm32Assembler::LoadLiteral(Register rt ATTRIBUTE_UNUSED, Register rt2 ATTRIBUTE_UNUSED,
+                                 Literal* literal ATTRIBUTE_UNUSED)  {
+  LOG(FATAL) << "Unimplemented.";
+  UNREACHABLE();
+}
+
+void Arm32Assembler::LoadLiteral(SRegister sd ATTRIBUTE_UNUSED,
+                                 Literal* literal ATTRIBUTE_UNUSED)  {
+  LOG(FATAL) << "Unimplemented.";
+  UNREACHABLE();
+}
+
+void Arm32Assembler::LoadLiteral(DRegister dd ATTRIBUTE_UNUSED,
+                                 Literal* literal ATTRIBUTE_UNUSED) {
+  LOG(FATAL) << "Unimplemented.";
+  UNREACHABLE();
+}
+
 void Arm32Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
   AddConstant(rd, rd, value, cond);
 }
diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h
index 80582e5..1c38eec 100644
--- a/compiler/utils/arm/assembler_arm32.h
+++ b/compiler/utils/arm/assembler_arm32.h
@@ -89,6 +89,8 @@
            Condition cond = AL) OVERRIDE;
   void mls(Register rd, Register rn, Register rm, Register ra,
            Condition cond = AL) OVERRIDE;
+  void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+             Condition cond = AL) OVERRIDE;
   void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
              Condition cond = AL) OVERRIDE;
 
@@ -198,8 +200,8 @@
   void vpopd(DRegister reg, int nregs, Condition cond = AL) OVERRIDE;
 
   // Branch instructions.
-  void b(Label* label, Condition cond = AL);
-  void bl(Label* label, Condition cond = AL);
+  void b(Label* label, Condition cond = AL) OVERRIDE;
+  void bl(Label* label, Condition cond = AL) OVERRIDE;
   void blx(Register rm, Condition cond = AL) OVERRIDE;
   void bx(Register rm, Condition cond = AL) OVERRIDE;
   void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
@@ -236,7 +238,16 @@
   // Memory barriers.
   void dmb(DmbOptions flavor) OVERRIDE;
 
-  // Macros.
+  // Get the final position of a label after local fixup based on the old position
+  // recorded before FinalizeCode().
+  uint32_t GetAdjustedPosition(uint32_t old_position) OVERRIDE;
+
+  Literal* NewLiteral(size_t size, const uint8_t* data) OVERRIDE;
+  void LoadLiteral(Register rt, Literal* literal) OVERRIDE;
+  void LoadLiteral(Register rt, Register rt2, Literal* literal) OVERRIDE;
+  void LoadLiteral(SRegister sd, Literal* literal) OVERRIDE;
+  void LoadLiteral(DRegister dd, Literal* literal) OVERRIDE;
+
   // Add signed constant value to rd. May clobber IP.
   void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
   void AddConstant(Register rd, Register rn, int32_t value,
diff --git a/compiler/utils/arm/assembler_arm32_test.cc b/compiler/utils/arm/assembler_arm32_test.cc
index 4a0ae0b..efd517b 100644
--- a/compiler/utils/arm/assembler_arm32_test.cc
+++ b/compiler/utils/arm/assembler_arm32_test.cc
@@ -293,12 +293,29 @@
     f();
   }
 
+  // NOTE: Only support simple test like "aaa=bbb"
+  bool EvalFilterString(std::string filter) {
+    if (filter.compare("") == 0) {
+      return false;
+    }
+
+    size_t equal_sign_index = filter.find('=');
+    if (equal_sign_index == std::string::npos) {
+      EXPECT_TRUE(false) << "Unsupported filter string.";
+    }
+
+    std::string lhs = filter.substr(0, equal_sign_index);
+    std::string rhs = filter.substr(equal_sign_index + 1, std::string::npos);
+    return lhs.compare(rhs) == 0;
+  }
+
   void TemplateHelper(std::function<void(arm::Register)> f, int depth ATTRIBUTE_UNUSED,
-                      bool without_pc,
-                      std::string fmt, std::ostringstream& oss) {
+                      bool without_pc, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
     for (auto reg : registers) {
       std::string after_reg = fmt;
+      std::string after_reg_filter = filter;
 
       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
       size_t reg_index;
@@ -308,14 +325,23 @@
         after_reg.replace(reg_index, strlen(reg_token), reg_string);
       }
 
+      while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
+        after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
+      }
+      if (EvalFilterString(after_reg_filter)) {
+        continue;
+      }
+
       ExecuteAndPrint([&] () { f(*reg); }, after_reg, oss);
     }
   }
 
   void TemplateHelper(std::function<void(const arm::ShifterOperand&)> f, int depth ATTRIBUTE_UNUSED,
-                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
       std::string after_shift = fmt;
+      std::string after_shift_filter = filter;
 
       std::string shift_string = GetShiftString(shift);
       size_t shift_index;
@@ -323,30 +349,48 @@
         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
       }
 
+      while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
+        after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+      }
+      if (EvalFilterString(after_shift_filter)) {
+        continue;
+      }
+
       ExecuteAndPrint([&] () { f(shift); }, after_shift, oss);
     }
   }
 
   void TemplateHelper(std::function<void(arm::Condition)> f, int depth ATTRIBUTE_UNUSED,
-                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::ostringstream& oss) {
+                      bool without_pc ATTRIBUTE_UNUSED, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     for (arm::Condition c : GetConditions()) {
       std::string after_cond = fmt;
+      std::string after_cond_filter = filter;
 
       size_t cond_index = after_cond.find(COND_TOKEN);
       if (cond_index != std::string::npos) {
         after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
       }
 
+      cond_index = after_cond_filter.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+      if (EvalFilterString(after_cond_filter)) {
+        continue;
+      }
+
       ExecuteAndPrint([&] () { f(c); }, after_cond, oss);
     }
   }
 
   template <typename... Args>
   void TemplateHelper(std::function<void(arm::Register, Args...)> f, int depth, bool without_pc,
-                      std::string fmt, std::ostringstream& oss) {
+                      std::string fmt, std::string filter, std::ostringstream& oss) {
     std::vector<arm::Register*> registers = without_pc ? GetRegistersWithoutPC() : GetRegisters();
     for (auto reg : registers) {
       std::string after_reg = fmt;
+      std::string after_reg_filter = filter;
 
       std::string reg_string = GetRegName<RegisterView::kUsePrimaryName>(*reg);
       size_t reg_index;
@@ -356,17 +400,26 @@
         after_reg.replace(reg_index, strlen(reg_token), reg_string);
       }
 
+      while ((reg_index = after_reg_filter.find(reg_token)) != std::string::npos) {
+        after_reg_filter.replace(reg_index, strlen(reg_token), reg_string);
+      }
+      if (EvalFilterString(after_reg_filter)) {
+        continue;
+      }
+
       auto lambda = [&] (Args... args) { f(*reg, args...); };  // NOLINT [readability/braces] [4]
       TemplateHelper(std::function<void(Args...)>(lambda), depth + 1, without_pc,
-          after_reg, oss);
+          after_reg, after_reg_filter, oss);
     }
   }
 
   template <typename... Args>
   void TemplateHelper(std::function<void(const arm::ShifterOperand&, Args...)> f, int depth,
-                      bool without_pc, std::string fmt, std::ostringstream& oss) {
+                      bool without_pc, std::string fmt, std::string filter,
+                      std::ostringstream& oss) {
     for (const arm::ShifterOperand& shift : GetShiftOperands()) {
       std::string after_shift = fmt;
+      std::string after_shift_filter = filter;
 
       std::string shift_string = GetShiftString(shift);
       size_t shift_index;
@@ -374,26 +427,42 @@
         after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
       }
 
+      while ((shift_index = after_shift_filter.find(SHIFT_TOKEN)) != std::string::npos) {
+        after_shift_filter.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string);
+      }
+      if (EvalFilterString(after_shift_filter)) {
+        continue;
+      }
+
       auto lambda = [&] (Args... args) { f(shift, args...); };  // NOLINT [readability/braces] [4]
       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
-          after_shift, oss);
+          after_shift, after_shift_filter, oss);
     }
   }
 
   template <typename... Args>
   void TemplateHelper(std::function<void(arm::Condition, Args...)> f, int depth, bool without_pc,
-                      std::string fmt, std::ostringstream& oss) {
+                      std::string fmt, std::string filter, std::ostringstream& oss) {
     for (arm::Condition c : GetConditions()) {
       std::string after_cond = fmt;
+      std::string after_cond_filter = filter;
 
       size_t cond_index = after_cond.find(COND_TOKEN);
       if (cond_index != std::string::npos) {
         after_cond.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
       }
 
+      cond_index = after_cond_filter.find(COND_TOKEN);
+      if (cond_index != std::string::npos) {
+        after_cond_filter.replace(cond_index, ConstexprStrLen(IMM1_TOKEN), GetConditionString(c));
+      }
+      if (EvalFilterString(after_cond_filter)) {
+        continue;
+      }
+
       auto lambda = [&] (Args... args) { f(c, args...); };  // NOLINT [readability/braces] [4]
       TemplateHelper(std::function<void(Args...)>(lambda), depth, without_pc,
-          after_cond, oss);
+          after_cond, after_cond_filter, oss);
     }
   }
 
@@ -421,13 +490,13 @@
 
   template <typename... Args>
   void GenericTemplateHelper(std::function<void(Args...)> f, bool without_pc,
-                             std::string fmt, std::string test_name) {
+                             std::string fmt, std::string test_name, std::string filter) {
     first_ = false;
     WarnOnCombinations(CountHelper<Args...>(without_pc));
 
     std::ostringstream oss;
 
-    TemplateHelper(f, 0, without_pc, fmt, oss);
+    TemplateHelper(f, 0, without_pc, fmt, filter, oss);
 
     oss << "\n";  // Trailing newline.
 
@@ -436,26 +505,26 @@
 
   template <typename... Args>
   void T2Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-                std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name);
+                std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction2(f), without_pc, fmt, test_name, filter);
   }
 
   template <typename... Args>
   void T3Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-      std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name);
+      std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction3(f), without_pc, fmt, test_name, filter);
   }
 
   template <typename... Args>
   void T4Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-      std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name);
+      std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction4(f), without_pc, fmt, test_name, filter);
   }
 
   template <typename... Args>
   void T5Helper(void (arm::Arm32Assembler::*f)(Args...), bool without_pc, std::string fmt,
-      std::string test_name) {
-    GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name);
+      std::string test_name, std::string filter = "") {
+    GenericTemplateHelper(GetBoundFunction5(f), without_pc, fmt, test_name, filter);
   }
 
  private:
@@ -565,15 +634,18 @@
 }
 
 TEST_F(AssemblerArm32Test, Mla) {
-  T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mul");
+  T5Helper(&arm::Arm32Assembler::mla, true, "mla{cond} {reg1}, {reg2}, {reg3}, {reg4}", "mla");
 }
 
-/* TODO: Needs support to filter out register combinations, as rdhi must not be equal to rdlo.
 TEST_F(AssemblerArm32Test, Umull) {
   T5Helper(&arm::Arm32Assembler::umull, true, "umull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
-           "umull");
+           "umull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
 }
-*/
+
+TEST_F(AssemblerArm32Test, Smull) {
+  T5Helper(&arm::Arm32Assembler::smull, true, "smull{cond} {reg1}, {reg2}, {reg3}, {reg4}",
+           "smull", "{reg1}={reg2}");  // Skip the cases where reg1 == reg2.
+}
 
 TEST_F(AssemblerArm32Test, Sdiv) {
   T4Helper(&arm::Arm32Assembler::sdiv, true, "sdiv{cond} {reg1}, {reg2}, {reg3}", "sdiv");
@@ -655,9 +727,10 @@
   T4Helper(&arm::Arm32Assembler::rsc, true, "rsc{cond} {reg1}, {reg2}, {shift}", "rsc");
 }
 
-/* TODO: Needs support to filter out register combinations, as reg1 must not be equal to reg3.
+/* TODO: Need better filter support.
 TEST_F(AssemblerArm32Test, Strex) {
-  RRRCWithoutPCHelper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex");
+  T4Helper(&arm::Arm32Assembler::strex, "strex{cond} {reg1}, {reg2}, [{reg3}]", "strex",
+           "{reg1}={reg2}||{reg1}={reg3}");  // Skip the cases where reg1 == reg2 || reg1 == reg3.
 }
 */
 
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 85f6670..88b2f2c 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -25,6 +25,309 @@
 namespace art {
 namespace arm {
 
+void Thumb2Assembler::BindLabel(Label* label, uint32_t bound_pc) {
+  CHECK(!label->IsBound());
+
+  while (label->IsLinked()) {
+    FixupId fixup_id = label->Position();                     // The id for linked Fixup.
+    Fixup* fixup = GetFixup(fixup_id);                        // Get the Fixup at this id.
+    fixup->Resolve(bound_pc);                                 // Fixup can be resolved now.
+    // Add this fixup as a dependency of all later fixups.
+    for (FixupId id = fixup_id + 1u, end = fixups_.size(); id != end; ++id) {
+      GetFixup(id)->AddDependent(fixup_id);
+    }
+    uint32_t fixup_location = fixup->GetLocation();
+    uint16_t next = buffer_.Load<uint16_t>(fixup_location);   // Get next in chain.
+    buffer_.Store<int16_t>(fixup_location, 0);
+    label->position_ = next;                                  // Move to next.
+  }
+  label->BindTo(bound_pc);
+}
+
+void Thumb2Assembler::BindLiterals() {
+  // We don't add the padding here, that's done only after adjusting the Fixup sizes.
+  uint32_t code_size = buffer_.Size();
+  for (Literal& lit : literals_) {
+    Label* label = lit.GetLabel();
+    BindLabel(label, code_size);
+    code_size += lit.GetSize();
+  }
+}
+
+void Thumb2Assembler::AdjustFixupIfNeeded(Fixup* fixup, uint32_t* current_code_size,
+                                          std::deque<FixupId>* fixups_to_recalculate) {
+  uint32_t adjustment = fixup->AdjustSizeIfNeeded(*current_code_size);
+  if (adjustment != 0u) {
+    *current_code_size += adjustment;
+    for (FixupId dependent_id : fixup->Dependents()) {
+      Fixup* dependent = GetFixup(dependent_id);
+      dependent->IncreaseAdjustment(adjustment);
+      if (buffer_.Load<int16_t>(dependent->GetLocation()) == 0) {
+        buffer_.Store<int16_t>(dependent->GetLocation(), 1);
+        fixups_to_recalculate->push_back(dependent_id);
+      }
+    }
+  }
+}
+
+uint32_t Thumb2Assembler::AdjustFixups() {
+  uint32_t current_code_size = buffer_.Size();
+  std::deque<FixupId> fixups_to_recalculate;
+  if (kIsDebugBuild) {
+    // We will use the placeholders in the buffer_ to mark whether the fixup has
+    // been added to the fixups_to_recalculate. Make sure we start with zeros.
+    for (Fixup& fixup : fixups_) {
+      CHECK_EQ(buffer_.Load<int16_t>(fixup.GetLocation()), 0);
+    }
+  }
+  for (Fixup& fixup : fixups_) {
+    AdjustFixupIfNeeded(&fixup, &current_code_size, &fixups_to_recalculate);
+  }
+  while (!fixups_to_recalculate.empty()) {
+    // Pop the fixup.
+    FixupId fixup_id = fixups_to_recalculate.front();
+    fixups_to_recalculate.pop_front();
+    Fixup* fixup = GetFixup(fixup_id);
+    DCHECK_NE(buffer_.Load<int16_t>(fixup->GetLocation()), 0);
+    buffer_.Store<int16_t>(fixup->GetLocation(), 0);
+    // See if it needs adjustment.
+    AdjustFixupIfNeeded(fixup, &current_code_size, &fixups_to_recalculate);
+  }
+  if (kIsDebugBuild) {
+    // Check that no fixup is marked as being in fixups_to_recalculate anymore.
+    for (Fixup& fixup : fixups_) {
+      CHECK_EQ(buffer_.Load<int16_t>(fixup.GetLocation()), 0);
+    }
+  }
+
+  // Adjust literal pool labels for padding.
+  DCHECK_EQ(current_code_size & 1u, 0u);
+  uint32_t literals_adjustment = current_code_size + (current_code_size & 2) - buffer_.Size();
+  if (literals_adjustment != 0u) {
+    for (Literal& literal : literals_) {
+      Label* label = literal.GetLabel();
+      DCHECK(label->IsBound());
+      int old_position = label->Position();
+      label->Reinitialize();
+      label->BindTo(old_position + literals_adjustment);
+    }
+  }
+
+  return current_code_size;
+}
+
+void Thumb2Assembler::EmitFixups(uint32_t adjusted_code_size) {
+  // Move non-fixup code to its final place and emit fixups.
+  // Process fixups in reverse order so that we don't repeatedly move the same data.
+  size_t src_end = buffer_.Size();
+  size_t dest_end = adjusted_code_size;
+  buffer_.Resize(dest_end);
+  DCHECK_GE(dest_end, src_end);
+  for (auto i = fixups_.rbegin(), end = fixups_.rend(); i != end; ++i) {
+    Fixup* fixup = &*i;
+    if (fixup->GetOriginalSize() == fixup->GetSize()) {
+      // The size of this Fixup didn't change. To avoid moving the data
+      // in small chunks, emit the code to its original position.
+      fixup->Emit(&buffer_, adjusted_code_size);
+      fixup->Finalize(dest_end - src_end);
+    } else {
+      // Move the data between the end of the fixup and src_end to its final location.
+      size_t old_fixup_location = fixup->GetLocation();
+      size_t src_begin = old_fixup_location + fixup->GetOriginalSizeInBytes();
+      size_t data_size = src_end - src_begin;
+      size_t dest_begin  = dest_end - data_size;
+      buffer_.Move(dest_begin, src_begin, data_size);
+      src_end = old_fixup_location;
+      dest_end = dest_begin - fixup->GetSizeInBytes();
+      // Finalize the Fixup and emit the data to the new location.
+      fixup->Finalize(dest_end - src_end);
+      fixup->Emit(&buffer_, adjusted_code_size);
+    }
+  }
+  CHECK_EQ(src_end, dest_end);
+}
+
+void Thumb2Assembler::EmitLiterals() {
+  if (!literals_.empty()) {
+    // 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);
+    if ((code_size & 2u) != 0u) {
+      Emit16(0);
+    }
+    for (Literal& literal : literals_) {
+      AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+      DCHECK_EQ(static_cast<size_t>(literal.GetLabel()->Position()), buffer_.Size());
+      DCHECK(literal.GetSize() == 4u || literal.GetSize() == 8u);
+      for (size_t i = 0, size = literal.GetSize(); i != size; ++i) {
+        buffer_.Emit<uint8_t>(literal.GetData()[i]);
+      }
+    }
+  }
+}
+
+inline int16_t Thumb2Assembler::BEncoding16(int32_t offset, Condition cond) {
+  DCHECK_EQ(offset & 1, 0);
+  int16_t encoding = B15 | B14;
+  if (cond != AL) {
+    DCHECK(IsInt<9>(offset));
+    encoding |= B12 |  (static_cast<int32_t>(cond) << 8) | ((offset >> 1) & 0xff);
+  } else {
+    DCHECK(IsInt<12>(offset));
+    encoding |= B13 | ((offset >> 1) & 0x7ff);
+  }
+  return encoding;
+}
+
+inline int32_t Thumb2Assembler::BEncoding32(int32_t offset, Condition cond) {
+  DCHECK_EQ(offset & 1, 0);
+  int32_t s = (offset >> 31) & 1;   // Sign bit.
+  int32_t encoding = B31 | B30 | B29 | B28 | B15 |
+      (s << 26) |                   // Sign bit goes to bit 26.
+      ((offset >> 1) & 0x7ff);      // imm11 goes to bits 0-10.
+  if (cond != AL) {
+    DCHECK(IsInt<21>(offset));
+    // Encode cond, move imm6 from bits 12-17 to bits 16-21 and move J1 and J2.
+    encoding |= (static_cast<int32_t>(cond) << 22) | ((offset & 0x3f000) << (16 - 12)) |
+        ((offset & (1 << 19)) >> (19 - 13)) |   // Extract J1 from bit 19 to bit 13.
+        ((offset & (1 << 18)) >> (18 - 11));    // Extract J2 from bit 18 to bit 11.
+  } else {
+    DCHECK(IsInt<25>(offset));
+    int32_t j1 = ((offset >> 23) ^ s ^ 1) & 1;  // Calculate J1 from I1 extracted from bit 23.
+    int32_t j2 = ((offset >> 22)^ s ^ 1) & 1;   // Calculate J2 from I2 extracted from bit 22.
+    // Move imm10 from bits 12-21 to bits 16-25 and add J1 and J2.
+    encoding |= B12 | ((offset & 0x3ff000) << (16 - 12)) |
+        (j1 << 13) | (j2 << 11);
+  }
+  return encoding;
+}
+
+inline int16_t Thumb2Assembler::CbxzEncoding16(Register rn, int32_t offset, Condition cond) {
+  DCHECK(!IsHighRegister(rn));
+  DCHECK_EQ(offset & 1, 0);
+  DCHECK(IsUint<7>(offset));
+  DCHECK(cond == EQ || cond == NE);
+  return B15 | B13 | B12 | B8 | (cond == NE ? B11 : 0) | static_cast<int32_t>(rn) |
+      ((offset & 0x3e) << (3 - 1)) |    // Move imm5 from bits 1-5 to bits 3-7.
+      ((offset & 0x40) << (9 - 6));     // Move i from bit 6 to bit 11
+}
+
+inline int16_t Thumb2Assembler::CmpRnImm8Encoding16(Register rn, int32_t value) {
+  DCHECK(!IsHighRegister(rn));
+  DCHECK(IsUint<8>(value));
+  return B13 | B11 | (rn << 8) | value;
+}
+
+inline int16_t Thumb2Assembler::AddRdnRmEncoding16(Register rdn, Register rm) {
+  // The high bit of rn is moved across 4-bit rm.
+  return B14 | B10 | (static_cast<int32_t>(rm) << 3) |
+      (static_cast<int32_t>(rdn) & 7) | ((static_cast<int32_t>(rdn) & 8) << 4);
+}
+
+inline int32_t Thumb2Assembler::MovwEncoding32(Register rd, int32_t value) {
+  DCHECK(IsUint<16>(value));
+  return B31 | B30 | B29 | B28 | B25 | B22 |
+      (static_cast<int32_t>(rd) << 8) |
+      ((value & 0xf000) << (16 - 12)) |   // Move imm4 from bits 12-15 to bits 16-19.
+      ((value & 0x0800) << (26 - 11)) |   // Move i from bit 11 to bit 26.
+      ((value & 0x0700) << (12 - 8)) |    // Move imm3 from bits 8-10 to bits 12-14.
+      (value & 0xff);                     // Keep imm8 in bits 0-7.
+}
+
+inline int32_t Thumb2Assembler::MovtEncoding32(Register rd, int32_t value) {
+  DCHECK_EQ(value & 0xffff, 0);
+  int32_t movw_encoding = MovwEncoding32(rd, (value >> 16) & 0xffff);
+  return movw_encoding | B25 | B23;
+}
+
+inline int32_t Thumb2Assembler::MovModImmEncoding32(Register rd, int32_t value) {
+  uint32_t mod_imm = ModifiedImmediate(value);
+  DCHECK_NE(mod_imm, kInvalidModifiedImmediate);
+  return B31 | B30 | B29 | B28 | B22 | B19 | B18 | B17 | B16 |
+      (static_cast<int32_t>(rd) << 8) | static_cast<int32_t>(mod_imm);
+}
+
+inline int16_t Thumb2Assembler::LdrLitEncoding16(Register rt, int32_t offset) {
+  DCHECK(!IsHighRegister(rt));
+  DCHECK_EQ(offset & 3, 0);
+  DCHECK(IsUint<10>(offset));
+  return B14 | B11 | (static_cast<int32_t>(rt) << 8) | (offset >> 2);
+}
+
+inline int32_t Thumb2Assembler::LdrLitEncoding32(Register rt, int32_t offset) {
+  // NOTE: We don't support negative offset, i.e. U=0 (B23).
+  return LdrRtRnImm12Encoding(rt, PC, offset);
+}
+
+inline int32_t Thumb2Assembler::LdrdEncoding32(Register rt, Register rt2, Register rn, int32_t offset) {
+  DCHECK_EQ(offset & 3, 0);
+  CHECK(IsUint<10>(offset));
+  return B31 | B30 | B29 | B27 |
+      B24 /* P = 1 */ | B23 /* U = 1 */ | B22 | 0 /* W = 0 */ | B20 |
+      (static_cast<int32_t>(rn) << 16) | (static_cast<int32_t>(rt) << 12) |
+      (static_cast<int32_t>(rt2) << 8) | (offset >> 2);
+}
+
+inline int32_t Thumb2Assembler::VldrsEncoding32(SRegister sd, Register rn, int32_t offset) {
+  DCHECK_EQ(offset & 3, 0);
+  CHECK(IsUint<10>(offset));
+  return B31 | B30 | B29 | B27 | B26 | B24 |
+      B23 /* U = 1 */ | B20 | B11 | B9 |
+      (static_cast<int32_t>(rn) << 16) |
+      ((static_cast<int32_t>(sd) & 0x01) << (22 - 0)) |   // Move D from bit 0 to bit 22.
+      ((static_cast<int32_t>(sd) & 0x1e) << (12 - 1)) |   // Move Vd from bits 1-4 to bits 12-15.
+      (offset >> 2);
+}
+
+inline int32_t Thumb2Assembler::VldrdEncoding32(DRegister dd, Register rn, int32_t offset) {
+  DCHECK_EQ(offset & 3, 0);
+  CHECK(IsUint<10>(offset));
+  return B31 | B30 | B29 | B27 | B26 | B24 |
+      B23 /* U = 1 */ | B20 | B11 | B9 | B8 |
+      (rn << 16) |
+      ((static_cast<int32_t>(dd) & 0x10) << (22 - 4)) |   // Move D from bit 4 to bit 22.
+      ((static_cast<int32_t>(dd) & 0x0f) << (12 - 0)) |   // Move Vd from bits 0-3 to bits 12-15.
+      (offset >> 2);
+}
+
+inline int16_t Thumb2Assembler::LdrRtRnImm5Encoding16(Register rt, Register rn, int32_t offset) {
+  DCHECK(!IsHighRegister(rt));
+  DCHECK(!IsHighRegister(rn));
+  DCHECK_EQ(offset & 3, 0);
+  DCHECK(IsUint<7>(offset));
+  return B14 | B13 | B11 |
+      (static_cast<int32_t>(rn) << 3) | static_cast<int32_t>(rt) |
+      (offset << (6 - 2));                // Move imm5 from bits 2-6 to bits 6-10.
+}
+
+int32_t Thumb2Assembler::Fixup::LoadWideOrFpEncoding(Register rbase, int32_t offset) const {
+  switch (type_) {
+    case kLoadLiteralWide:
+      return LdrdEncoding32(rn_, rt2_, rbase, offset);
+    case kLoadFPLiteralSingle:
+      return VldrsEncoding32(sd_, rbase, offset);
+    case kLoadFPLiteralDouble:
+      return VldrdEncoding32(dd_, rbase, offset);
+    default:
+      LOG(FATAL) << "Unexpected type: " << static_cast<int>(type_);
+      UNREACHABLE();
+  }
+}
+
+inline int32_t Thumb2Assembler::LdrRtRnImm12Encoding(Register rt, Register rn, int32_t offset) {
+  DCHECK(IsUint<12>(offset));
+  return B31 | B30 | B29 | B28 | B27 | B23 | B22 | B20 | (rn << 16) | (rt << 12) | offset;
+}
+
+void Thumb2Assembler::FinalizeCode() {
+  ArmAssembler::FinalizeCode();
+  BindLiterals();
+  uint32_t adjusted_code_size = AdjustFixups();
+  EmitFixups(adjusted_code_size);
+  EmitLiterals();
+}
+
 bool Thumb2Assembler::ShifterOperandCanHold(Register rd ATTRIBUTE_UNUSED,
                                             Register rn ATTRIBUTE_UNUSED,
                                             Opcode opcode,
@@ -238,6 +541,24 @@
 }
 
 
+void Thumb2Assembler::smull(Register rd_lo, Register rd_hi, Register rn,
+                            Register rm, Condition cond) {
+  CheckCondition(cond);
+
+  uint32_t op1 = 0U /* 0b000; */;
+  uint32_t op2 = 0U /* 0b0000 */;
+  int32_t encoding = B31 | B30 | B29 | B28 | B27 | B25 | B24 | B23 |
+      op1 << 20 |
+      op2 << 4 |
+      static_cast<uint32_t>(rd_lo) << 12 |
+      static_cast<uint32_t>(rd_hi) << 8 |
+      static_cast<uint32_t>(rn) << 16 |
+      static_cast<uint32_t>(rm);
+
+  Emit32(encoding);
+}
+
+
 void Thumb2Assembler::umull(Register rd_lo, Register rd_hi, Register rn,
                             Register rm, Condition cond) {
   CheckCondition(cond);
@@ -654,6 +975,7 @@
 }
 
 void Thumb2Assembler::b(Label* label, Condition cond) {
+  DCHECK_EQ(next_condition_, AL);
   EmitBranch(cond, label, false, false);
 }
 
@@ -740,13 +1062,6 @@
     return true;
   }
 
-  // Check for MOV with an ROR.
-  if (opcode == MOV && so.IsRegister() && so.IsShift() && so.GetShift() == ROR) {
-    if (so.GetImmediate() != 0) {
-      return true;
-    }
-  }
-
   bool rn_is_valid = true;
 
   // Check for single operand instructions and ADD/SUB.
@@ -792,6 +1107,19 @@
     }
   }
 
+  // Check for register shift operand.
+  if (so.IsRegister() && so.IsShift()) {
+    if (opcode != MOV) {
+      return true;
+    }
+    // Check for MOV with an ROR.
+    if (so.GetShift() == ROR) {
+      if (so.GetImmediate() != 0) {
+        return true;
+      }
+    }
+  }
+
   // The instruction can be encoded in 16 bits.
   return false;
 }
@@ -1278,79 +1606,359 @@
   }
 }
 
+inline size_t Thumb2Assembler::Fixup::SizeInBytes(Size size) {
+  switch (size) {
+    case kBranch16Bit:
+      return 2u;
+    case kBranch32Bit:
+      return 4u;
 
+    case kCbxz16Bit:
+      return 2u;
+    case kCbxz32Bit:
+      return 4u;
+    case kCbxz48Bit:
+      return 6u;
 
-void Thumb2Assembler::Branch::Emit(AssemblerBuffer* buffer) const {
-  bool link = type_ == kUnconditionalLinkX || type_ == kUnconditionalLink;
-  bool x = type_ == kUnconditionalX || type_ == kUnconditionalLinkX;
-  int32_t offset = target_ - location_;
+    case kLiteral1KiB:
+      return 2u;
+    case kLiteral4KiB:
+      return 4u;
+    case kLiteral64KiB:
+      return 8u;
+    case kLiteral1MiB:
+      return 10u;
+    case kLiteralFar:
+      return 14u;
 
-  if (size_ == k32Bit) {
-    int32_t encoding = B31 | B30 | B29 | B28 | B15;
-    if (link) {
-      // BL or BLX immediate.
-      encoding |= B14;
-      if (!x) {
-        encoding |= B12;
-      } else {
-        // Bottom bit of offset must be 0.
-        CHECK_EQ((offset & 1), 0);
-      }
-    } else {
-      if (x) {
-        LOG(FATAL) << "Invalid use of BX";
-        UNREACHABLE();
-      } else {
-        if (cond_ == AL) {
-          // Can use the T4 encoding allowing a 24 bit offset.
-          if (!x) {
-            encoding |= B12;
-          }
-        } else {
-          // Must be T3 encoding with a 20 bit offset.
-          encoding |= cond_ << 22;
-        }
-      }
-    }
-    encoding = Thumb2Assembler::EncodeBranchOffset(offset, encoding);
-    buffer->Store<int16_t>(location_, static_cast<int16_t>(encoding >> 16));
-    buffer->Store<int16_t>(location_+2, static_cast<int16_t>(encoding & 0xffff));
+    case kLongOrFPLiteral1KiB:
+      return 4u;
+    case kLongOrFPLiteral256KiB:
+      return 10u;
+    case kLongOrFPLiteralFar:
+      return 14u;
+  }
+  LOG(FATAL) << "Unexpected size: " << static_cast<int>(size);
+  UNREACHABLE();
+}
+
+inline uint32_t Thumb2Assembler::Fixup::GetOriginalSizeInBytes() const {
+  return SizeInBytes(original_size_);
+}
+
+inline uint32_t Thumb2Assembler::Fixup::GetSizeInBytes() const {
+  return SizeInBytes(size_);
+}
+
+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);
+  // 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;
+}
+
+inline int32_t Thumb2Assembler::Fixup::GetOffset(uint32_t current_code_size) const {
+  static constexpr int32_t int32_min = std::numeric_limits<int32_t>::min();
+  static constexpr int32_t int32_max = std::numeric_limits<int32_t>::max();
+  DCHECK_LE(target_, static_cast<uint32_t>(int32_max));
+  DCHECK_LE(location_, static_cast<uint32_t>(int32_max));
+  DCHECK_LE(adjustment_, static_cast<uint32_t>(int32_max));
+  int32_t diff = static_cast<int32_t>(target_) - static_cast<int32_t>(location_);
+  if (target_ > location_) {
+    DCHECK_LE(adjustment_, static_cast<uint32_t>(int32_max - diff));
+    diff += static_cast<int32_t>(adjustment_);
   } else {
-    if (IsCompareAndBranch()) {
-      offset -= 4;
-      uint16_t i = (offset >> 6) & 1;
-      uint16_t imm5 = (offset >> 1) & 31U /* 0b11111 */;
-      int16_t encoding = B15 | B13 | B12 |
-            (type_ ==  kCompareAndBranchNonZero ? B11 : 0) |
-            static_cast<uint32_t>(rn_) |
-            B8 |
-            i << 9 |
-            imm5 << 3;
-      buffer->Store<int16_t>(location_, encoding);
-    } else {
-      offset -= 4;    // Account for PC offset.
-      int16_t encoding;
-      // 16 bit.
-      if (cond_ == AL) {
-        encoding = B15 | B14 | B13 |
-            ((offset >> 1) & 0x7ff);
-      } else {
-        encoding = B15 | B14 | B12 |
-            cond_ << 8 | ((offset >> 1) & 0xff);
+    DCHECK_LE(int32_min + static_cast<int32_t>(adjustment_), diff);
+    diff -= static_cast<int32_t>(adjustment_);
+  }
+  // The default PC adjustment for Thumb2 is 4 bytes.
+  DCHECK_GE(diff, int32_min + 4);
+  diff -= 4;
+  // Add additional adjustment for instructions preceding the PC usage, padding
+  // before the literal pool and rounding down the PC for literal loads.
+  switch (GetSize()) {
+    case kBranch16Bit:
+    case kBranch32Bit:
+      break;
+
+    case kCbxz16Bit:
+      break;
+    case kCbxz32Bit:
+    case kCbxz48Bit:
+      DCHECK_GE(diff, int32_min + 2);
+      diff -= 2;        // Extra CMP Rn, #0, 16-bit.
+      break;
+
+    case kLiteral1KiB:
+    case kLiteral4KiB:
+    case kLongOrFPLiteral1KiB:
+      DCHECK(diff >= 0 || (GetSize() == kLiteral1KiB && diff == -2));
+      diff += LiteralPoolPaddingSize(current_code_size);
+      // 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);
+      diff = diff + (diff & 2);
+      DCHECK_GE(diff, 0);
+      break;
+    case kLiteral1MiB:
+    case kLiteral64KiB:
+    case kLongOrFPLiteral256KiB:
+      DCHECK_GE(diff, 4);  // The target must be at least 4 bytes after the ADD rX, PC.
+      diff -= 4;        // One extra 32-bit MOV.
+      diff += LiteralPoolPaddingSize(current_code_size);
+      break;
+    case kLiteralFar:
+    case kLongOrFPLiteralFar:
+      DCHECK_GE(diff, 8);  // The target must be at least 4 bytes after the ADD rX, PC.
+      diff -= 8;        // Extra MOVW+MOVT; both 32-bit.
+      diff += LiteralPoolPaddingSize(current_code_size);
+      break;
+  }
+  return diff;
+}
+
+inline size_t Thumb2Assembler::Fixup::IncreaseSize(Size new_size) {
+  DCHECK_NE(target_, kUnresolved);
+  Size old_size = size_;
+  size_ = new_size;
+  DCHECK_GT(SizeInBytes(new_size), SizeInBytes(old_size));
+  size_t adjustment = SizeInBytes(new_size) - SizeInBytes(old_size);
+  if (target_ > location_) {
+    adjustment_ += adjustment;
+  }
+  return adjustment;
+}
+
+uint32_t Thumb2Assembler::Fixup::AdjustSizeIfNeeded(uint32_t current_code_size) {
+  uint32_t old_code_size = current_code_size;
+  switch (GetSize()) {
+    case kBranch16Bit:
+      if (IsInt(cond_ != AL ? 9 : 12, GetOffset(current_code_size))) {
+        break;
       }
+      current_code_size += IncreaseSize(kBranch32Bit);
+      FALLTHROUGH_INTENDED;
+    case kBranch32Bit:
+      // We don't support conditional branches beyond +-1MiB
+      // or unconditional branches beyond +-16MiB.
+      break;
+
+    case kCbxz16Bit:
+      if (IsUint<7>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kCbxz32Bit);
+      FALLTHROUGH_INTENDED;
+    case kCbxz32Bit:
+      if (IsInt<9>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kCbxz48Bit);
+      FALLTHROUGH_INTENDED;
+    case kCbxz48Bit:
+      // We don't support conditional branches beyond +-1MiB.
+      break;
+
+    case kLiteral1KiB:
+      DCHECK(!IsHighRegister(rn_));
+      if (IsUint<10>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kLiteral4KiB);
+      FALLTHROUGH_INTENDED;
+    case kLiteral4KiB:
+      if (IsUint<12>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kLiteral64KiB);
+      FALLTHROUGH_INTENDED;
+    case kLiteral64KiB:
+      // Can't handle high register which we can encounter by fall-through from kLiteral4KiB.
+      if (!IsHighRegister(rn_) && IsUint<16>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kLiteral1MiB);
+      FALLTHROUGH_INTENDED;
+    case kLiteral1MiB:
+      if (IsUint<20>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kLiteralFar);
+      FALLTHROUGH_INTENDED;
+    case kLiteralFar:
+      // This encoding can reach any target.
+      break;
+
+    case kLongOrFPLiteral1KiB:
+      if (IsUint<10>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kLongOrFPLiteral256KiB);
+      FALLTHROUGH_INTENDED;
+    case kLongOrFPLiteral256KiB:
+      if (IsUint<18>(GetOffset(current_code_size))) {
+        break;
+      }
+      current_code_size += IncreaseSize(kLongOrFPLiteralFar);
+      FALLTHROUGH_INTENDED;
+    case kLongOrFPLiteralFar:
+      // This encoding can reach any target.
+      break;
+  }
+  return current_code_size - old_code_size;
+}
+
+void Thumb2Assembler::Fixup::Emit(AssemblerBuffer* buffer, uint32_t code_size) const {
+  switch (GetSize()) {
+    case kBranch16Bit: {
+      DCHECK(type_ == kUnconditional || type_ == kConditional);
+      DCHECK_EQ(type_ == kConditional, cond_ != AL);
+      int16_t encoding = BEncoding16(GetOffset(code_size), cond_);
       buffer->Store<int16_t>(location_, encoding);
+      break;
+    }
+    case kBranch32Bit: {
+      DCHECK(type_ == kConditional || type_ == kUnconditional ||
+             type_ == kUnconditionalLink || type_ == kUnconditionalLinkX);
+      DCHECK_EQ(type_ == kConditional, cond_ != AL);
+      int32_t encoding = BEncoding32(GetOffset(code_size), cond_);
+      if (type_ == kUnconditionalLink) {
+        DCHECK_NE(encoding & B12, 0);
+        encoding |= B14;
+      } else if (type_ == kUnconditionalLinkX) {
+        DCHECK_NE(encoding & B12, 0);
+        encoding ^= B14 | B12;
+      }
+      buffer->Store<int16_t>(location_, encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(encoding & 0xffff));
+      break;
+    }
+
+    case kCbxz16Bit: {
+      DCHECK(type_ == kCompareAndBranchXZero);
+      int16_t encoding = CbxzEncoding16(rn_, GetOffset(code_size), cond_);
+      buffer->Store<int16_t>(location_, encoding);
+      break;
+    }
+    case kCbxz32Bit: {
+      DCHECK(type_ == kCompareAndBranchXZero);
+      DCHECK(cond_ == EQ || cond_ == NE);
+      int16_t cmp_encoding = CmpRnImm8Encoding16(rn_, 0);
+      int16_t b_encoding = BEncoding16(GetOffset(code_size), cond_);
+      buffer->Store<int16_t>(location_, cmp_encoding);
+      buffer->Store<int16_t>(location_ + 2, b_encoding);
+      break;
+    }
+    case kCbxz48Bit: {
+      DCHECK(type_ == kCompareAndBranchXZero);
+      DCHECK(cond_ == EQ || cond_ == NE);
+      int16_t cmp_encoding = CmpRnImm8Encoding16(rn_, 0);
+      int32_t b_encoding = BEncoding32(GetOffset(code_size), cond_);
+      buffer->Store<int16_t>(location_, cmp_encoding);
+      buffer->Store<int16_t>(location_ + 2u, b_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 4u, static_cast<int16_t>(b_encoding & 0xffff));
+      break;
+    }
+
+    case kLiteral1KiB: {
+      DCHECK(type_ == kLoadLiteralNarrow);
+      int16_t encoding = LdrLitEncoding16(rn_, GetOffset(code_size));
+      buffer->Store<int16_t>(location_, encoding);
+      break;
+    }
+    case kLiteral4KiB: {
+      DCHECK(type_ == kLoadLiteralNarrow);
+      // GetOffset() uses PC+4 but load literal uses AlignDown(PC+4, 4). Adjust offset accordingly.
+      int32_t encoding = LdrLitEncoding32(rn_, GetOffset(code_size));
+      buffer->Store<int16_t>(location_, encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(encoding & 0xffff));
+      break;
+    }
+    case kLiteral64KiB: {
+      DCHECK(type_ == kLoadLiteralNarrow);
+      int32_t mov_encoding = MovwEncoding32(rn_, GetOffset(code_size));
+      int16_t add_pc_encoding = AddRdnRmEncoding16(rn_, PC);
+      int16_t ldr_encoding = LdrRtRnImm5Encoding16(rn_, rn_, 0);
+      buffer->Store<int16_t>(location_, mov_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(mov_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 4u, add_pc_encoding);
+      buffer->Store<int16_t>(location_ + 6u, ldr_encoding);
+      break;
+    }
+    case kLiteral1MiB: {
+      DCHECK(type_ == kLoadLiteralNarrow);
+      int32_t offset = GetOffset(code_size);
+      int32_t mov_encoding = MovModImmEncoding32(rn_, offset & ~0xfff);
+      int16_t add_pc_encoding = AddRdnRmEncoding16(rn_, PC);
+      int32_t ldr_encoding = LdrRtRnImm12Encoding(rn_, rn_, offset & 0xfff);
+      buffer->Store<int16_t>(location_, mov_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(mov_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 4u, add_pc_encoding);
+      buffer->Store<int16_t>(location_ + 6u, ldr_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 8u, static_cast<int16_t>(ldr_encoding & 0xffff));
+      break;
+    }
+    case kLiteralFar: {
+      DCHECK(type_ == kLoadLiteralNarrow);
+      int32_t offset = GetOffset(code_size);
+      int32_t movw_encoding = MovwEncoding32(rn_, offset & 0xffff);
+      int32_t movt_encoding = MovtEncoding32(rn_, offset & ~0xffff);
+      int16_t add_pc_encoding = AddRdnRmEncoding16(rn_, PC);
+      int32_t ldr_encoding = LdrRtRnImm12Encoding(rn_, rn_, 0);
+      buffer->Store<int16_t>(location_, movw_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(movw_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 4u, movt_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 6u, static_cast<int16_t>(movt_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 8u, add_pc_encoding);
+      buffer->Store<int16_t>(location_ + 10u, ldr_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 12u, static_cast<int16_t>(ldr_encoding & 0xffff));
+      break;
+    }
+
+    case kLongOrFPLiteral1KiB: {
+      int32_t encoding = LoadWideOrFpEncoding(PC, GetOffset(code_size));  // DCHECKs type_.
+      buffer->Store<int16_t>(location_, encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(encoding & 0xffff));
+      break;
+    }
+    case kLongOrFPLiteral256KiB: {
+      int32_t offset = GetOffset(code_size);
+      int32_t mov_encoding = MovModImmEncoding32(IP, offset & ~0x3ff);
+      int16_t add_pc_encoding = AddRdnRmEncoding16(IP, PC);
+      int32_t ldr_encoding = LoadWideOrFpEncoding(IP, offset & 0x3ff);    // DCHECKs type_.
+      buffer->Store<int16_t>(location_, mov_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(mov_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 4u, add_pc_encoding);
+      buffer->Store<int16_t>(location_ + 6u, ldr_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 8u, static_cast<int16_t>(ldr_encoding & 0xffff));
+      break;
+    }
+    case kLongOrFPLiteralFar: {
+      int32_t offset = GetOffset(code_size);
+      int32_t movw_encoding = MovwEncoding32(IP, offset & 0xffff);
+      int32_t movt_encoding = MovtEncoding32(IP, offset & ~0xffff);
+      int16_t add_pc_encoding = AddRdnRmEncoding16(IP, PC);
+      int32_t ldr_encoding = LoadWideOrFpEncoding(IP, 0);                 // DCHECKs type_.
+      buffer->Store<int16_t>(location_, movw_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 2u, static_cast<int16_t>(movw_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 4u, movt_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 6u, static_cast<int16_t>(movt_encoding & 0xffff));
+      buffer->Store<int16_t>(location_ + 8u, add_pc_encoding);
+      buffer->Store<int16_t>(location_ + 10u, ldr_encoding >> 16);
+      buffer->Store<int16_t>(location_ + 12u, static_cast<int16_t>(ldr_encoding & 0xffff));
+      break;
     }
   }
 }
 
-
 uint16_t Thumb2Assembler::EmitCompareAndBranch(Register rn, uint16_t prev, bool n) {
+  CHECK(IsLowRegister(rn));
   uint32_t location = buffer_.Size();
 
   // This is always unresolved as it must be a forward branch.
   Emit16(prev);      // Previous link.
-  return AddBranch(n ? Branch::kCompareAndBranchNonZero : Branch::kCompareAndBranchZero,
-      location, rn);
+  return AddFixup(Fixup::CompareAndBranch(location, rn, n ? NE : EQ));
 }
 
 
@@ -1588,48 +2196,53 @@
   }
 }
 
-
 void Thumb2Assembler::EmitBranch(Condition cond, Label* label, bool link, bool x) {
+  bool use32bit = IsForced32Bit() || !CanRelocateBranches();
   uint32_t pc = buffer_.Size();
-  Branch::Type branch_type;
+  Fixup::Type branch_type;
   if (cond == AL) {
     if (link) {
+      use32bit = true;
       if (x) {
-        branch_type = Branch::kUnconditionalLinkX;      // BLX.
+        branch_type = Fixup::kUnconditionalLinkX;      // BLX.
       } else {
-        branch_type = Branch::kUnconditionalLink;       // BX.
+        branch_type = Fixup::kUnconditionalLink;       // BX.
       }
     } else {
-      branch_type = Branch::kUnconditional;             // B.
+      branch_type = Fixup::kUnconditional;             // B.
     }
   } else {
-    branch_type = Branch::kConditional;                 // B<cond>.
+    branch_type = Fixup::kConditional;                 // B<cond>.
   }
 
+  Fixup::Size size = use32bit ? Fixup::kBranch32Bit : Fixup::kBranch16Bit;
+  FixupId branch_id = AddFixup(Fixup::Branch(pc, branch_type, size, cond));
+
   if (label->IsBound()) {
-    Branch::Size size = AddBranch(branch_type, pc, label->Position(), cond);  // Resolved branch.
-
-    // The branch is to a bound label which means that it's a backwards branch.  We know the
-    // current size of it so we can emit the appropriate space.  Note that if it's a 16 bit
-    // branch the size may change if it so happens that other branches change size that change
-    // the distance to the target and that distance puts this branch over the limit for 16 bits.
-    if (size == Branch::k16Bit) {
-      DCHECK(!force_32bit_branches_);
-      Emit16(0);          // Space for a 16 bit branch.
-    } else {
-      Emit32(0);            // Space for a 32 bit branch.
+    // The branch is to a bound label which means that it's a backwards branch.
+    // Record this branch as a dependency of all Fixups between the label and the branch.
+    GetFixup(branch_id)->Resolve(label->Position());
+    for (FixupId fixup_id = branch_id; fixup_id != 0u; ) {
+      --fixup_id;
+      Fixup* fixup = GetFixup(fixup_id);
+      DCHECK_GE(label->Position(), 0);
+      if (fixup->GetLocation() < static_cast<uint32_t>(label->Position())) {
+        break;
+      }
+      fixup->AddDependent(branch_id);
     }
+    Emit16(0);
   } else {
-    // Branch is to an unbound label.  Emit space for it.
-    uint16_t branch_id = AddBranch(branch_type, pc, cond);    // Unresolved branch.
-    if (force_32bit_branches_ || force_32bit_) {
-      Emit16(static_cast<uint16_t>(label->position_));    // Emit current label link.
-      Emit16(0);                   // another 16 bits.
-    } else {
-      Emit16(static_cast<uint16_t>(label->position_));    // Emit current label link.
-    }
-    label->LinkTo(branch_id);           // Link to the branch ID.
+    // Branch target is an unbound label. Add it to a singly-linked list maintained within
+    // the code with the label serving as the head.
+    Emit16(static_cast<uint16_t>(label->position_));
+    label->LinkTo(branch_id);
   }
+
+  if (use32bit) {
+    Emit16(0);
+  }
+  DCHECK_EQ(buffer_.Size() - pc, GetFixup(branch_id)->GetSizeInBytes());
 }
 
 
@@ -2176,6 +2789,9 @@
   if (label->IsBound()) {
     LOG(FATAL) << "cbz can only be used to branch forwards";
     UNREACHABLE();
+  } else if (IsHighRegister(rn)) {
+    LOG(FATAL) << "cbz can only be used with low registers";
+    UNREACHABLE();
   } else {
     uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), false);
     label->LinkTo(branchid);
@@ -2188,6 +2804,9 @@
   if (label->IsBound()) {
     LOG(FATAL) << "cbnz can only be used to branch forwards";
     UNREACHABLE();
+  } else if (IsHighRegister(rn)) {
+    LOG(FATAL) << "cbnz can only be used with low registers";
+    UNREACHABLE();
   } else {
     uint16_t branchid = EmitCompareAndBranch(rn, static_cast<uint16_t>(label->position_), true);
     label->LinkTo(branchid);
@@ -2238,82 +2857,8 @@
 }
 
 
-// A branch has changed size.  Make a hole for it.
-void Thumb2Assembler::MakeHoleForBranch(uint32_t location, uint32_t delta) {
-  // Move the contents of the buffer using: Move(newposition, oldposition)
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-  buffer_.Move(location + delta, location);
-}
-
-
 void Thumb2Assembler::Bind(Label* label) {
-  CHECK(!label->IsBound());
-  uint32_t bound_pc = buffer_.Size();
-  std::vector<Branch*> changed_branches;
-
-  while (label->IsLinked()) {
-    uint16_t position = label->Position();                  // Branch id for linked branch.
-    Branch* branch = GetBranch(position);                   // Get the branch at this id.
-    bool changed = branch->Resolve(bound_pc);               // Branch can be resolved now.
-    uint32_t branch_location = branch->GetLocation();
-    uint16_t next = buffer_.Load<uint16_t>(branch_location);       // Get next in chain.
-    if (changed) {
-      DCHECK(!force_32bit_branches_);
-      MakeHoleForBranch(branch->GetLocation(), 2);
-      if (branch->IsCompareAndBranch()) {
-        // A cbz/cbnz instruction has changed size.  There is no valid encoding for
-        // a 32 bit cbz/cbnz so we need to change this to an instruction pair:
-        // cmp rn, #0
-        // b<eq|ne> target
-        bool n = branch->GetType() == Branch::kCompareAndBranchNonZero;
-        Condition cond = n ? NE : EQ;
-        branch->Move(2);      // Move the branch forward by 2 bytes.
-        branch->ResetTypeAndCondition(Branch::kConditional, cond);
-        branch->ResetSize(Branch::k16Bit);
-
-        // Now add a compare instruction in the place the branch was.
-        buffer_.Store<int16_t>(branch_location,
-                               B13 | B11 | static_cast<int16_t>(branch->GetRegister()) << 8);
-
-        // Since have moved made a hole in the code we need to reload the
-        // current pc.
-        bound_pc = buffer_.Size();
-
-        // Now resolve the newly added branch.
-        changed = branch->Resolve(bound_pc);
-        if (changed) {
-          MakeHoleForBranch(branch->GetLocation(), 2);
-          changed_branches.push_back(branch);
-        }
-      } else {
-        changed_branches.push_back(branch);
-      }
-    }
-    label->position_ = next;                                // Move to next.
-  }
-  label->BindTo(bound_pc);
-
-  // Now relocate any changed branches.  Do this until there are no more changes.
-  std::vector<Branch*> branches_to_process = changed_branches;
-  while (branches_to_process.size() != 0) {
-    changed_branches.clear();
-    for (auto& changed_branch : branches_to_process) {
-      for (auto& branch : branches_) {
-        bool changed = branch->Relocate(changed_branch->GetLocation(), 2);
-        if (changed) {
-          changed_branches.push_back(branch);
-        }
-      }
-      branches_to_process = changed_branches;
-    }
-  }
-}
-
-
-void Thumb2Assembler::EmitBranches() {
-  for (auto& branch : branches_) {
-    branch->Emit(&buffer_);
-  }
+  BindLabel(label, buffer_.Size());
 }
 
 
@@ -2451,6 +2996,85 @@
   return imm32;
 }
 
+uint32_t Thumb2Assembler::GetAdjustedPosition(uint32_t old_position) {
+  // We can reconstruct the adjustment by going through all the fixups from the beginning
+  // up to the old_position. Since we expect AdjustedPosition() to be called in a loop
+  // with increasing old_position, we can use the data from last AdjustedPosition() to
+  // continue where we left off and the whole loop should be O(m+n) where m is the number
+  // of positions to adjust and n is the number of fixups.
+  if (old_position < last_old_position_) {
+    last_position_adjustment_ = 0u;
+    last_old_position_ = 0u;
+    last_fixup_id_ = 0u;
+  }
+  while (last_fixup_id_ != fixups_.size()) {
+    Fixup* fixup = GetFixup(last_fixup_id_);
+    if (fixup->GetLocation() >= old_position + last_position_adjustment_) {
+      break;
+    }
+    if (fixup->GetSize() != fixup->GetOriginalSize()) {
+      last_position_adjustment_ += fixup->GetSizeInBytes() - fixup->GetOriginalSizeInBytes();
+    }
+     ++last_fixup_id_;
+  }
+  last_old_position_ = old_position;
+  return old_position + last_position_adjustment_;
+}
+
+Literal* Thumb2Assembler::NewLiteral(size_t size, const uint8_t* data)  {
+  DCHECK(size == 4u || size == 8u) << size;
+  literals_.emplace_back(size, data);
+  return &literals_.back();
+}
+
+void Thumb2Assembler::LoadLiteral(Register rt, Literal* literal)  {
+  DCHECK_EQ(literal->GetSize(), 4u);
+  DCHECK(!literal->GetLabel()->IsBound());
+  bool use32bit = IsForced32Bit() || IsHighRegister(rt);
+  uint32_t location = buffer_.Size();
+  Fixup::Size size = use32bit ? Fixup::kLiteral4KiB : Fixup::kLiteral1KiB;
+  FixupId fixup_id = AddFixup(Fixup::LoadNarrowLiteral(location, rt, size));
+  Emit16(static_cast<uint16_t>(literal->GetLabel()->position_));
+  literal->GetLabel()->LinkTo(fixup_id);
+  if (use32bit) {
+    Emit16(0);
+  }
+  DCHECK_EQ(location + GetFixup(fixup_id)->GetSizeInBytes(), buffer_.Size());
+}
+
+void Thumb2Assembler::LoadLiteral(Register rt, Register rt2, Literal* literal)  {
+  DCHECK_EQ(literal->GetSize(), 8u);
+  DCHECK(!literal->GetLabel()->IsBound());
+  uint32_t location = buffer_.Size();
+  FixupId fixup_id =
+      AddFixup(Fixup::LoadWideLiteral(location, rt, rt2, Fixup::kLongOrFPLiteral1KiB));
+  Emit16(static_cast<uint16_t>(literal->GetLabel()->position_));
+  literal->GetLabel()->LinkTo(fixup_id);
+  Emit16(0);
+  DCHECK_EQ(location + GetFixup(fixup_id)->GetSizeInBytes(), buffer_.Size());
+}
+
+void Thumb2Assembler::LoadLiteral(SRegister sd, Literal* literal)  {
+  DCHECK_EQ(literal->GetSize(), 4u);
+  DCHECK(!literal->GetLabel()->IsBound());
+  uint32_t location = buffer_.Size();
+  FixupId fixup_id = AddFixup(Fixup::LoadSingleLiteral(location, sd, Fixup::kLongOrFPLiteral1KiB));
+  Emit16(static_cast<uint16_t>(literal->GetLabel()->position_));
+  literal->GetLabel()->LinkTo(fixup_id);
+  Emit16(0);
+  DCHECK_EQ(location + GetFixup(fixup_id)->GetSizeInBytes(), buffer_.Size());
+}
+
+void Thumb2Assembler::LoadLiteral(DRegister dd, Literal* literal) {
+  DCHECK_EQ(literal->GetSize(), 8u);
+  DCHECK(!literal->GetLabel()->IsBound());
+  uint32_t location = buffer_.Size();
+  FixupId fixup_id = AddFixup(Fixup::LoadDoubleLiteral(location, dd, Fixup::kLongOrFPLiteral1KiB));
+  Emit16(static_cast<uint16_t>(literal->GetLabel()->position_));
+  literal->GetLabel()->LinkTo(fixup_id);
+  Emit16(0);
+  DCHECK_EQ(location + GetFixup(fixup_id)->GetSizeInBytes(), buffer_.Size());
+}
 
 void Thumb2Assembler::AddConstant(Register rd, int32_t value, Condition cond) {
   AddConstant(rd, rd, value, cond);
@@ -2718,21 +3342,21 @@
 
 
 void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
-  if (force_32bit_branches_) {
+  if (CanRelocateBranches() && IsLowRegister(r) && !label->IsBound()) {
+    cbz(r, label);
+  } else {
     cmp(r, ShifterOperand(0));
     b(label, EQ);
-  } else {
-    cbz(r, label);
   }
 }
 
 
 void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
-  if (force_32bit_branches_) {
+  if (CanRelocateBranches() && IsLowRegister(r) && !label->IsBound()) {
+    cbnz(r, label);
+  } else {
     cmp(r, ShifterOperand(0));
     b(label, NE);
-  } else {
-    cbnz(r, label);
   }
 }
 }  // namespace arm
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 05caeb3..5e6969b 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_
 #define ART_COMPILER_UTILS_ARM_ASSEMBLER_THUMB2_H_
 
+#include <deque>
 #include <vector>
 
 #include "base/logging.h"
@@ -30,17 +31,19 @@
 
 class Thumb2Assembler FINAL : public ArmAssembler {
  public:
-  explicit Thumb2Assembler(bool force_32bit_branches = false)
-      : force_32bit_branches_(force_32bit_branches),
+  explicit Thumb2Assembler(bool can_relocate_branches = true)
+      : can_relocate_branches_(can_relocate_branches),
         force_32bit_(false),
         it_cond_index_(kNoItCondition),
-        next_condition_(AL) {
+        next_condition_(AL),
+        fixups_(),
+        literals_(),
+        last_position_adjustment_(0u),
+        last_old_position_(0u),
+        last_fixup_id_(0u) {
   }
 
   virtual ~Thumb2Assembler() {
-    for (auto& branch : branches_) {
-      delete branch;
-    }
   }
 
   bool IsThumb() const OVERRIDE {
@@ -51,14 +54,11 @@
     return force_32bit_;
   }
 
-  bool IsForced32BitBranches() const {
-    return force_32bit_branches_;
+  bool CanRelocateBranches() const {
+    return can_relocate_branches_;
   }
 
-  void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
-    EmitBranches();
-    Assembler::FinalizeInstructions(region);
-  }
+  void FinalizeCode() OVERRIDE;
 
   // Data-processing instructions.
   void and_(Register rd, Register rn, const ShifterOperand& so, Condition cond = AL) OVERRIDE;
@@ -111,6 +111,8 @@
            Condition cond = AL) OVERRIDE;
   void mls(Register rd, Register rn, Register rm, Register ra,
            Condition cond = AL) OVERRIDE;
+  void smull(Register rd_lo, Register rd_hi, Register rn, Register rm,
+             Condition cond = AL) OVERRIDE;
   void umull(Register rd_lo, Register rd_hi, Register rn, Register rm,
              Condition cond = AL) OVERRIDE;
 
@@ -275,7 +277,18 @@
   // Memory barriers.
   void dmb(DmbOptions flavor) OVERRIDE;
 
-  // Macros.
+  // Get the final position of a label after local fixup based on the old position
+  // recorded before FinalizeCode().
+  uint32_t GetAdjustedPosition(uint32_t old_position) OVERRIDE;
+
+  using ArmAssembler::NewLiteral;  // Make the helper template visible.
+
+  Literal* NewLiteral(size_t size, const uint8_t* data) OVERRIDE;
+  void LoadLiteral(Register rt, Literal* literal) OVERRIDE;
+  void LoadLiteral(Register rt, Register rt2, Literal* literal) OVERRIDE;
+  void LoadLiteral(SRegister sd, Literal* literal) OVERRIDE;
+  void LoadLiteral(DRegister dd, Literal* literal) OVERRIDE;
+
   // Add signed constant value to rd. May clobber IP.
   void AddConstant(Register rd, int32_t value, Condition cond = AL) OVERRIDE;
   void AddConstant(Register rd, Register rn, int32_t value,
@@ -336,6 +349,244 @@
   }
 
  private:
+  typedef uint16_t FixupId;
+
+  // Fixup: branches and literal pool references.
+  //
+  // The thumb2 architecture allows branches to be either 16 or 32 bit instructions. This
+  // depends on both the type of branch and the offset to which it is branching. The 16-bit
+  // cbz and cbnz instructions may also need to be replaced with a separate 16-bit compare
+  // instruction and a 16- or 32-bit branch instruction. Load from a literal pool can also be
+  // 16-bit or 32-bit instruction and, if the method is large, we may need to use a sequence
+  // of instructions to make up for the limited range of load literal instructions (up to
+  // 4KiB for the 32-bit variant). When generating code for these insns we don't know the
+  // size before hand, so we assume it is the smallest available size and determine the final
+  // code offsets and sizes and emit code in FinalizeCode().
+  //
+  // To handle this, we keep a record of every branch and literal pool load in the program.
+  // The actual instruction encoding for these is delayed until we know the final size of
+  // every instruction. When we bind a label to a branch we don't know the final location yet
+  // as some preceding instructions may need to be expanded, so we record a non-final offset.
+  // In FinalizeCode(), we expand the sizes of branches and literal loads that are out of
+  // range. With each expansion, we need to update dependent Fixups, i.e. insntructios with
+  // target on the other side of the expanded insn, as their offsets change and this may
+  // trigger further expansion.
+  //
+  // All Fixups have a 'fixup id' which is a 16 bit unsigned number used to identify the
+  // Fixup. For each unresolved label we keep a singly-linked list of all Fixups pointing
+  // to it, using the fixup ids as links. The first link is stored in the label's position
+  // (the label is linked but not bound), the following links are stored in the code buffer,
+  // in the placeholder where we will eventually emit the actual code.
+
+  class Fixup {
+   public:
+    // Branch type.
+    enum Type : uint8_t {
+      kConditional,               // B<cond>.
+      kUnconditional,             // B.
+      kUnconditionalLink,         // BL.
+      kUnconditionalLinkX,        // BLX.
+      kCompareAndBranchXZero,     // cbz/cbnz.
+      kLoadLiteralNarrow,         // Load narrrow integer literal.
+      kLoadLiteralWide,           // Load wide integer literal.
+      kLoadFPLiteralSingle,       // Load FP literal single.
+      kLoadFPLiteralDouble,       // Load FP literal double.
+    };
+
+    // Calculated size of branch instruction based on type and offset.
+    enum Size : uint8_t {
+      // Branch variants.
+      kBranch16Bit,
+      kBranch32Bit,
+      // NOTE: We don't support branches which would require multiple instructions, i.e.
+      // conditinoal branches beyond +-1MiB and unconditional branches beyond +-16MiB.
+
+      // CBZ/CBNZ variants.
+      kCbxz16Bit,   // CBZ/CBNZ rX, label; X < 8; 7-bit positive offset.
+      kCbxz32Bit,   // CMP rX, #0 + Bcc label; X < 8; 16-bit Bcc; +-8-bit offset.
+      kCbxz48Bit,   // CMP rX, #0 + Bcc label; X < 8; 32-bit Bcc; up to +-1MiB offset.
+
+      // Load integer literal variants.
+      // LDR rX, label; X < 8; 16-bit variant up to 1KiB offset; 2 bytes.
+      kLiteral1KiB,
+      // LDR rX, label; 32-bit variant up to 4KiB offset; 4 bytes.
+      kLiteral4KiB,
+      // MOV rX, imm16 + ADD rX, pc + LDR rX, [rX]; X < 8; up to 64KiB offset; 8 bytes.
+      kLiteral64KiB,
+      // MOV rX, modimm + ADD rX, pc + LDR rX, [rX, #imm12]; up to 1MiB offset; 10 bytes.
+      kLiteral1MiB,
+      // NOTE: We don't provide the 12-byte version of kLiteralFar below where the LDR is 16-bit.
+      // MOV rX, imm16 + MOVT rX, imm16 + ADD rX, pc + LDR rX, [rX]; any offset; 14 bytes.
+      kLiteralFar,
+
+      // Load long or FP literal variants.
+      // VLDR s/dX, label; 32-bit insn, up to 1KiB offset; 4 bytes.
+      kLongOrFPLiteral1KiB,
+      // MOV ip, modimm + ADD ip, pc + VLDR s/dX, [IP, #imm8*4]; up to 256KiB offset; 10 bytes.
+      kLongOrFPLiteral256KiB,
+      // MOV ip, imm16 + MOVT ip, imm16 + ADD ip, pc + VLDR s/dX, [IP]; any offset; 14 bytes.
+      kLongOrFPLiteralFar,
+    };
+
+    // Unresolved branch possibly with a condition.
+    static Fixup Branch(uint32_t location, Type type, Size size = kBranch16Bit,
+                        Condition cond = AL) {
+      DCHECK(type == kConditional || type == kUnconditional ||
+             type == kUnconditionalLink || type == kUnconditionalLinkX);
+      DCHECK(size == kBranch16Bit || size == kBranch32Bit);
+      DCHECK(size == kBranch32Bit || (type == kConditional || type == kUnconditional));
+      return Fixup(kNoRegister, kNoRegister, kNoSRegister, kNoDRegister,
+                   cond, type, size, location);
+    }
+
+    // Unresolved compare-and-branch instruction with a register and condition (EQ or NE).
+    static Fixup CompareAndBranch(uint32_t location, Register rn, Condition cond) {
+      DCHECK(cond == EQ || cond == NE);
+      return Fixup(rn, kNoRegister, kNoSRegister, kNoDRegister,
+                   cond, kCompareAndBranchXZero, kCbxz16Bit, location);
+    }
+
+    // Load narrow literal.
+    static Fixup LoadNarrowLiteral(uint32_t location, Register rt, Size size = kLiteral1KiB) {
+      DCHECK(size == kLiteral1KiB || size == kLiteral4KiB || size == kLiteral64KiB ||
+             size == kLiteral1MiB || size == kLiteralFar);
+      DCHECK(!IsHighRegister(rt) || (size != kLiteral1KiB && size != kLiteral64KiB));
+      return Fixup(rt, kNoRegister, kNoSRegister, kNoDRegister,
+                   AL, kLoadLiteralNarrow, size, location);
+    }
+
+    // Load wide literal.
+    static Fixup LoadWideLiteral(uint32_t location, Register rt, Register rt2,
+                                 Size size = kLongOrFPLiteral1KiB) {
+      DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
+             size == kLongOrFPLiteralFar);
+      DCHECK(!IsHighRegister(rt) || (size != kLiteral1KiB && size != kLiteral64KiB));
+      return Fixup(rt, rt2, kNoSRegister, kNoDRegister,
+                   AL, kLoadLiteralWide, size, location);
+    }
+
+    // Load FP single literal.
+    static Fixup LoadSingleLiteral(uint32_t location, SRegister sd,
+                                   Size size = kLongOrFPLiteral1KiB) {
+      DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
+             size == kLongOrFPLiteralFar);
+      return Fixup(kNoRegister, kNoRegister, sd, kNoDRegister,
+                   AL, kLoadFPLiteralSingle, size, location);
+    }
+
+    // Load FP double literal.
+    static Fixup LoadDoubleLiteral(uint32_t location, DRegister dd,
+                                   Size size = kLongOrFPLiteral1KiB) {
+      DCHECK(size == kLongOrFPLiteral1KiB || size == kLongOrFPLiteral256KiB ||
+             size == kLongOrFPLiteralFar);
+      return Fixup(kNoRegister, kNoRegister, kNoSRegister, dd,
+                   AL, kLoadFPLiteralDouble, size, location);
+    }
+
+    Type GetType() const {
+      return type_;
+    }
+
+    Size GetOriginalSize() const {
+      return original_size_;
+    }
+
+    Size GetSize() const {
+      return size_;
+    }
+
+    uint32_t GetOriginalSizeInBytes() const;
+
+    uint32_t GetSizeInBytes() const;
+
+    uint32_t GetLocation() const {
+      return location_;
+    }
+
+    uint32_t GetAdjustment() const {
+      return adjustment_;
+    }
+
+    const std::vector<FixupId>& Dependents() const {
+      return dependents_;
+    }
+
+    void AddDependent(FixupId dependent_id) {
+      dependents_.push_back(dependent_id);
+    }
+
+    // Resolve a branch when the target is known.
+    void Resolve(uint32_t target) {
+      DCHECK_EQ(target_, kUnresolved);
+      DCHECK_NE(target, kUnresolved);
+      target_ = target;
+    }
+
+    // Check if the current size is OK for current location_, target_ and adjustment_.
+    // If not, increase the size. Return the size increase, 0 if unchanged.
+    // If the target if after this Fixup, also add the difference to adjustment_,
+    // so that we don't need to consider forward Fixups as their own dependencies.
+    uint32_t AdjustSizeIfNeeded(uint32_t current_code_size);
+
+    // Increase adjustments. This is called for dependents of a Fixup when its size changes.
+    void IncreaseAdjustment(uint32_t increase) {
+      adjustment_ += increase;
+    }
+
+    // Finalize the branch with an adjustment to the location. Both location and target are updated.
+    void Finalize(uint32_t location_adjustment) {
+      DCHECK_NE(target_, kUnresolved);
+      location_ += location_adjustment;
+      target_ += location_adjustment;
+    }
+
+    // Emit the branch instruction into the assembler buffer.  This does the
+    // encoding into the thumb instruction.
+    void Emit(AssemblerBuffer* buffer, uint32_t code_size) const;
+
+   private:
+    Fixup(Register rn, Register rt2, SRegister sd, DRegister dd,
+          Condition cond, Type type, Size size, uint32_t location)
+        : rn_(rn),
+          rt2_(rt2),
+          sd_(sd),
+          dd_(dd),
+          cond_(cond),
+          type_(type),
+          original_size_(size), size_(size),
+          location_(location),
+          target_(kUnresolved),
+          adjustment_(0u),
+          dependents_() {
+    }
+    static size_t SizeInBytes(Size size);
+
+    // The size of padding added before the literal pool.
+    static size_t LiteralPoolPaddingSize(uint32_t current_code_size);
+
+    // Returns the offset from the PC-using insn to the target.
+    int32_t GetOffset(uint32_t current_code_size) const;
+
+    size_t IncreaseSize(Size new_size);
+
+    int32_t LoadWideOrFpEncoding(Register rbase, int32_t offset) const;
+
+    static constexpr uint32_t kUnresolved = 0xffffffff;     // Value for target_ for unresolved.
+
+    const Register rn_;   // Rn for cbnz/cbz, Rt for literal loads.
+    Register rt2_;        // For kLoadLiteralWide.
+    SRegister sd_;        // For kLoadFPLiteralSingle.
+    DRegister dd_;        // For kLoadFPLiteralDouble.
+    const Condition cond_;
+    const Type type_;
+    Size original_size_;
+    Size size_;
+    uint32_t location_;     // Offset into assembler buffer in bytes.
+    uint32_t target_;       // Offset into assembler buffer in bytes.
+    uint32_t adjustment_;   // The number of extra bytes inserted between location_ and target_.
+    std::vector<FixupId> dependents_;  // Fixups that require adjustment when current size changes.
+  };
+
   // Emit a single 32 or 16 bit data processing instruction.
   void EmitDataProcessing(Condition cond,
                           Opcode opcode,
@@ -436,8 +687,12 @@
   void EmitShift(Register rd, Register rm, Shift shift, uint8_t amount, bool setcc = false);
   void EmitShift(Register rd, Register rn, Shift shift, Register rm, bool setcc = false);
 
-  bool force_32bit_branches_;  // Force the assembler to use 32 bit branch instructions.
-  bool force_32bit_;           // Force the assembler to use 32 bit thumb2 instructions.
+  // Whether the assembler can relocate branches. If false, unresolved branches will be
+  // emitted on 32bits.
+  bool can_relocate_branches_;
+
+  // Force the assembler to use 32 bit thumb2 instructions.
+  bool force_32bit_;
 
   // IfThen conditions.  Used to check that conditional instructions match the preceding IT.
   Condition it_conditions_[4];
@@ -467,252 +722,53 @@
     CheckCondition(cond);
   }
 
-  // Branches.
-  //
-  // The thumb2 architecture allows branches to be either 16 or 32 bit instructions.  This
-  // depends on both the type of branch and the offset to which it is branching.  When
-  // generating code for branches we don't know the size before hand (if the branch is
-  // going forward, because we haven't seen the target address yet), so we need to assume
-  // that it is going to be one of 16 or 32 bits.  When we know the target (the label is 'bound')
-  // we can determine the actual size of the branch.  However, if we had guessed wrong before
-  // we knew the target there will be no room in the instruction sequence for the new
-  // instruction (assume that we never decrease the size of a branch).
-  //
-  // To handle this, we keep a record of every branch in the program.  The actual instruction
-  // encoding for these is delayed until we know the final size of every branch.  When we
-  // bind a label to a branch (we then know the target address) we determine if the branch
-  // has changed size.  If it has we need to move all the instructions in the buffer after
-  // the branch point forward by the change in size of the branch.  This will create a gap
-  // in the code big enough for the new branch encoding.  However, since we have moved
-  // a chunk of code we need to relocate the branches in that code to their new address.
-  //
-  // Creating a hole in the code for the new branch encoding might cause another branch that was
-  // 16 bits to become 32 bits, so we need to find this in another pass.
-  //
-  // We also need to deal with a cbz/cbnz instruction that becomes too big for its offset
-  // range.  We do this by converting it to two instructions:
-  //     cmp Rn, #0
-  //     b<cond> target
-  // But we also need to handle the case where the conditional branch is out of range and
-  // becomes a 32 bit conditional branch.
-  //
-  // All branches have a 'branch id' which is a 16 bit unsigned number used to identify
-  // the branch.  Unresolved labels use the branch id to link to the next unresolved branch.
-
-  class Branch {
-   public:
-    // Branch type.
-    enum Type {
-      kUnconditional,             // B.
-      kConditional,               // B<cond>.
-      kCompareAndBranchZero,      // cbz.
-      kCompareAndBranchNonZero,   // cbnz.
-      kUnconditionalLink,         // BL.
-      kUnconditionalLinkX,        // BLX.
-      kUnconditionalX             // BX.
-    };
-
-    // Calculated size of branch instruction based on type and offset.
-    enum Size {
-      k16Bit,
-      k32Bit
-    };
-
-    // Unresolved branch possibly with a condition.
-    Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, Condition cond = AL) :
-        assembler_(assembler), type_(type), location_(location),
-        target_(kUnresolved),
-        cond_(cond), rn_(R0) {
-      CHECK(!IsCompareAndBranch());
-      size_ = CalculateSize();
-    }
-
-    // Unresolved compare-and-branch instruction with a register.
-    Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, Register rn) :
-        assembler_(assembler), type_(type), location_(location),
-        target_(kUnresolved), cond_(AL), rn_(rn) {
-      CHECK(IsCompareAndBranch());
-      size_ = CalculateSize();
-    }
-
-    // Resolved branch (can't be compare-and-branch) with a target and possibly a condition.
-    Branch(const Thumb2Assembler* assembler, Type type, uint32_t location, uint32_t target,
-           Condition cond = AL) :
-           assembler_(assembler), type_(type), location_(location),
-           target_(target), cond_(cond), rn_(R0) {
-      CHECK(!IsCompareAndBranch());
-      // Resolved branch.
-      size_ = CalculateSize();
-    }
-
-    bool IsCompareAndBranch() const {
-      return type_ == kCompareAndBranchNonZero || type_ == kCompareAndBranchZero;
-    }
-
-    // Resolve a branch when the target is known.  If this causes the
-    // size of the branch to change return true.  Otherwise return false.
-    bool Resolve(uint32_t target) {
-      target_ = target;
-      Size newsize = CalculateSize();
-      if (size_ != newsize) {
-        size_ = newsize;
-        return true;
-      }
-      return false;
-    }
-
-    // Move a cbz/cbnz branch.  This is always forward.
-    void Move(int32_t delta) {
-      CHECK(IsCompareAndBranch());
-      CHECK_GT(delta, 0);
-      location_ += delta;
-      target_ += delta;
-    }
-
-    // Relocate a branch by a given delta.  This changed the location and
-    // target if they need to be changed.  It also recalculates the
-    // size of the branch instruction.  It returns true if the branch
-    // has changed size.
-    bool Relocate(uint32_t oldlocation, int32_t delta) {
-      if (location_ > oldlocation) {
-        location_ += delta;
-      }
-      if (target_ != kUnresolved) {
-        if (target_ > oldlocation) {
-          target_ += delta;
-        }
-      } else {
-        return false;       // Don't know the size yet.
-      }
-
-      // Calculate the new size.
-      Size newsize = CalculateSize();
-      if (size_ != newsize) {
-        size_ = newsize;
-        return true;
-      }
-      return false;
-    }
-
-    Size GetSize() const {
-      return size_;
-    }
-
-    Type GetType() const {
-      return type_;
-    }
-
-    uint32_t GetLocation() const {
-      return location_;
-    }
-
-    // Emit the branch instruction into the assembler buffer.  This does the
-    // encoding into the thumb instruction.
-    void Emit(AssemblerBuffer* buffer) const;
-
-    // Reset the type and condition to those given.  This used for
-    // cbz/cbnz instructions when they are converted to cmp/b<cond>
-    void ResetTypeAndCondition(Type type, Condition cond) {
-      CHECK(IsCompareAndBranch());
-      CHECK(cond == EQ || cond == NE);
-      type_ = type;
-      cond_ = cond;
-    }
-
-    Register GetRegister() const {
-      return rn_;
-    }
-
-    void ResetSize(Size size) {
-      size_ = size;
-    }
-
-   private:
-    // Calculate the size of the branch instruction based on its type and offset.
-    Size CalculateSize() const {
-      if (assembler_->IsForced32BitBranches()) {
-        return k32Bit;
-      }
-      if (target_ == kUnresolved) {
-        if (assembler_->IsForced32Bit() && (type_ == kUnconditional || type_ == kConditional)) {
-          return k32Bit;
-        }
-        return k16Bit;
-      }
-      int32_t delta = target_ - location_ - 4;
-      if (delta < 0) {
-        delta = -delta;
-      }
-      switch (type_) {
-        case kUnconditional:
-          if (assembler_->IsForced32Bit() || delta >= (1 << 11)) {
-            return k32Bit;
-          } else {
-            return k16Bit;
-          }
-        case kConditional:
-          if (assembler_->IsForced32Bit() || delta >= (1 << 8)) {
-            return k32Bit;
-          } else {
-            return k16Bit;
-          }
-        case kCompareAndBranchZero:
-        case kCompareAndBranchNonZero:
-          if (delta >= (1 << 7)) {
-            return k32Bit;      // Will cause this branch to become invalid.
-          }
-          return k16Bit;
-
-        case kUnconditionalX:
-        case kUnconditionalLinkX:
-          return k16Bit;
-        case kUnconditionalLink:
-          return k32Bit;
-      }
-      LOG(FATAL) << "Cannot reach";
-      return k16Bit;
-    }
-
-    static constexpr uint32_t kUnresolved = 0xffffffff;     // Value for target_ for unresolved.
-    const Thumb2Assembler* assembler_;
-    Type type_;
-    uint32_t location_;     // Offset into assembler buffer in bytes.
-    uint32_t target_;       // Offset into assembler buffer in bytes.
-    Size size_;
-    Condition cond_;
-    const Register rn_;
-  };
-
-  std::vector<Branch*> branches_;
-
-  // Add a resolved branch and return its size.
-  Branch::Size AddBranch(Branch::Type type, uint32_t location, uint32_t target,
-                         Condition cond = AL) {
-    branches_.push_back(new Branch(this, type, location, target, cond));
-    return branches_[branches_.size()-1]->GetSize();
+  FixupId AddFixup(Fixup fixup) {
+    FixupId fixup_id = static_cast<FixupId>(fixups_.size());
+    fixups_.push_back(fixup);
+    // For iterating using FixupId, we need the next id to be representable.
+    DCHECK_EQ(static_cast<size_t>(static_cast<FixupId>(fixups_.size())), fixups_.size());
+    return fixup_id;
   }
 
-  // Add a compare and branch (with a register) and return its id.
-  uint16_t AddBranch(Branch::Type type, uint32_t location, Register rn) {
-    branches_.push_back(new Branch(this, type, location, rn));
-    return branches_.size() - 1;
+  Fixup* GetFixup(FixupId fixup_id) {
+    DCHECK_LT(fixup_id, fixups_.size());
+    return &fixups_[fixup_id];
   }
 
-  // Add an unresolved branch and return its id.
-  uint16_t AddBranch(Branch::Type type, uint32_t location, Condition cond = AL) {
-    branches_.push_back(new Branch(this, type, location, cond));
-    return branches_.size() - 1;
-  }
+  void BindLabel(Label* label, uint32_t bound_pc);
+  void BindLiterals();
+  void AdjustFixupIfNeeded(Fixup* fixup, uint32_t* current_code_size,
+                           std::deque<FixupId>* fixups_to_recalculate);
+  uint32_t AdjustFixups();
+  void EmitFixups(uint32_t adjusted_code_size);
+  void EmitLiterals();
 
-  Branch* GetBranch(uint16_t branchid) {
-    if (branchid >= branches_.size()) {
-      return nullptr;
-    }
-    return branches_[branchid];
-  }
+  static int16_t BEncoding16(int32_t offset, Condition cond);
+  static int32_t BEncoding32(int32_t offset, Condition cond);
+  static int16_t CbxzEncoding16(Register rn, int32_t offset, Condition cond);
+  static int16_t CmpRnImm8Encoding16(Register rn, int32_t value);
+  static int16_t AddRdnRmEncoding16(Register rdn, Register rm);
+  static int32_t MovwEncoding32(Register rd, int32_t value);
+  static int32_t MovtEncoding32(Register rd, int32_t value);
+  static int32_t MovModImmEncoding32(Register rd, int32_t value);
+  static int16_t LdrLitEncoding16(Register rt, int32_t offset);
+  static int32_t LdrLitEncoding32(Register rt, int32_t offset);
+  static int32_t LdrdEncoding32(Register rt, Register rt2, Register rn, int32_t offset);
+  static int32_t VldrsEncoding32(SRegister sd, Register rn, int32_t offset);
+  static int32_t VldrdEncoding32(DRegister dd, Register rn, int32_t offset);
+  static int16_t LdrRtRnImm5Encoding16(Register rt, Register rn, int32_t offset);
+  static int32_t LdrRtRnImm12Encoding(Register rt, Register rn, int32_t offset);
 
-  void EmitBranches();
-  void MakeHoleForBranch(uint32_t location, uint32_t size);
+  std::vector<Fixup> fixups_;
+
+  // Use std::deque<> for literal labels to allow insertions at the end
+  // without invalidating pointers and references to existing elements.
+  std::deque<Literal> literals_;
+
+  // Data for AdjustedPosition(), see the description there.
+  uint32_t last_position_adjustment_;
+  uint32_t last_old_position_;
+  FixupId last_fixup_id_;
 };
 
 }  // namespace arm
diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc
index 5f5561a..68b7931 100644
--- a/compiler/utils/arm/assembler_thumb2_test.cc
+++ b/compiler/utils/arm/assembler_thumb2_test.cc
@@ -78,34 +78,42 @@
     return imm_value;
   }
 
+  std::string RepeatInsn(size_t count, const std::string& insn) {
+    std::string result;
+    for (; count != 0u; --count) {
+      result += insn;
+    }
+    return result;
+  }
+
  private:
   std::vector<arm::Register*> registers_;
 
   static constexpr const char* kThumb2AssemblyHeader = ".syntax unified\n.thumb\n";
 };
 
-
 TEST_F(AssemblerThumb2Test, Toolchain) {
   EXPECT_TRUE(CheckTools());
 }
 
+#define __ GetAssembler()->
 
 TEST_F(AssemblerThumb2Test, Sbfx) {
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 1);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 8);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 16);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 0, 32);
+  __ sbfx(arm::R0, arm::R1, 0, 1);
+  __ sbfx(arm::R0, arm::R1, 0, 8);
+  __ sbfx(arm::R0, arm::R1, 0, 16);
+  __ sbfx(arm::R0, arm::R1, 0, 32);
 
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 1);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 8);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 16);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 8, 24);
+  __ sbfx(arm::R0, arm::R1, 8, 1);
+  __ sbfx(arm::R0, arm::R1, 8, 8);
+  __ sbfx(arm::R0, arm::R1, 8, 16);
+  __ sbfx(arm::R0, arm::R1, 8, 24);
 
-  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 1);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 8);
-  GetAssembler()->sbfx(arm::R0, arm::R1, 16, 16);
+  __ sbfx(arm::R0, arm::R1, 16, 1);
+  __ sbfx(arm::R0, arm::R1, 16, 8);
+  __ sbfx(arm::R0, arm::R1, 16, 16);
 
-  GetAssembler()->sbfx(arm::R0, arm::R1, 31, 1);
+  __ sbfx(arm::R0, arm::R1, 31, 1);
 
   const char* expected =
       "sbfx r0, r1, #0, #1\n"
@@ -127,21 +135,21 @@
 }
 
 TEST_F(AssemblerThumb2Test, Ubfx) {
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 1);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 8);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 16);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 0, 32);
+  __ ubfx(arm::R0, arm::R1, 0, 1);
+  __ ubfx(arm::R0, arm::R1, 0, 8);
+  __ ubfx(arm::R0, arm::R1, 0, 16);
+  __ ubfx(arm::R0, arm::R1, 0, 32);
 
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 1);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 8);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 16);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 8, 24);
+  __ ubfx(arm::R0, arm::R1, 8, 1);
+  __ ubfx(arm::R0, arm::R1, 8, 8);
+  __ ubfx(arm::R0, arm::R1, 8, 16);
+  __ ubfx(arm::R0, arm::R1, 8, 24);
 
-  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 1);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 8);
-  GetAssembler()->ubfx(arm::R0, arm::R1, 16, 16);
+  __ ubfx(arm::R0, arm::R1, 16, 1);
+  __ ubfx(arm::R0, arm::R1, 16, 8);
+  __ ubfx(arm::R0, arm::R1, 16, 16);
 
-  GetAssembler()->ubfx(arm::R0, arm::R1, 31, 1);
+  __ ubfx(arm::R0, arm::R1, 31, 1);
 
   const char* expected =
       "ubfx r0, r1, #0, #1\n"
@@ -163,7 +171,7 @@
 }
 
 TEST_F(AssemblerThumb2Test, Vmstat) {
-  GetAssembler()->vmstat();
+  __ vmstat();
 
   const char* expected = "vmrs APSR_nzcv, FPSCR\n";
 
@@ -171,10 +179,10 @@
 }
 
 TEST_F(AssemblerThumb2Test, ldrexd) {
-  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R0);
-  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R1);
-  GetAssembler()->ldrexd(arm::R0, arm::R1, arm::R2);
-  GetAssembler()->ldrexd(arm::R5, arm::R3, arm::R7);
+  __ ldrexd(arm::R0, arm::R1, arm::R0);
+  __ ldrexd(arm::R0, arm::R1, arm::R1);
+  __ ldrexd(arm::R0, arm::R1, arm::R2);
+  __ ldrexd(arm::R5, arm::R3, arm::R7);
 
   const char* expected =
       "ldrexd r0, r1, [r0]\n"
@@ -185,10 +193,10 @@
 }
 
 TEST_F(AssemblerThumb2Test, strexd) {
-  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R0);
-  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R1);
-  GetAssembler()->strexd(arm::R9, arm::R0, arm::R1, arm::R2);
-  GetAssembler()->strexd(arm::R9, arm::R5, arm::R3, arm::R7);
+  __ strexd(arm::R9, arm::R0, arm::R1, arm::R0);
+  __ strexd(arm::R9, arm::R0, arm::R1, arm::R1);
+  __ strexd(arm::R9, arm::R0, arm::R1, arm::R2);
+  __ strexd(arm::R9, arm::R5, arm::R3, arm::R7);
 
   const char* expected =
       "strexd r9, r0, r1, [r0]\n"
@@ -199,9 +207,9 @@
 }
 
 TEST_F(AssemblerThumb2Test, LdrdStrd) {
-  GetAssembler()->ldrd(arm::R0, arm::Address(arm::R2, 8));
-  GetAssembler()->ldrd(arm::R0, arm::Address(arm::R12));
-  GetAssembler()->strd(arm::R0, arm::Address(arm::R2, 8));
+  __ ldrd(arm::R0, arm::Address(arm::R2, 8));
+  __ ldrd(arm::R0, arm::Address(arm::R12));
+  __ strd(arm::R0, arm::Address(arm::R2, 8));
 
   const char* expected =
       "ldrd r0, r1, [r2, #8]\n"
@@ -211,7 +219,6 @@
 }
 
 TEST_F(AssemblerThumb2Test, eor) {
-#define __ GetAssembler()->
   __ eor(arm::R1, arm::R1, arm::ShifterOperand(arm::R0));
   __ eor(arm::R1, arm::R0, arm::ShifterOperand(arm::R1));
   __ eor(arm::R1, arm::R8, arm::ShifterOperand(arm::R0));
@@ -230,23 +237,47 @@
 TEST_F(AssemblerThumb2Test, sub) {
   __ subs(arm::R1, arm::R0, arm::ShifterOperand(42));
   __ sub(arm::R1, arm::R0, arm::ShifterOperand(42));
+  __ subs(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
+  __ sub(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
 
   const char* expected =
       "subs r1, r0, #42\n"
-      "subw r1, r0, #42\n";
+      "subw r1, r0, #42\n"
+      "subs r1, r0, r2, asr #31\n"
+      "sub r1, r0, r2, asr #31\n";
   DriverStr(expected, "sub");
 }
 
 TEST_F(AssemblerThumb2Test, add) {
   __ adds(arm::R1, arm::R0, arm::ShifterOperand(42));
   __ add(arm::R1, arm::R0, arm::ShifterOperand(42));
+  __ adds(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
+  __ add(arm::R1, arm::R0, arm::ShifterOperand(arm::R2, arm::ASR, 31));
 
   const char* expected =
       "adds r1, r0, #42\n"
-      "addw r1, r0, #42\n";
+      "addw r1, r0, #42\n"
+      "adds r1, r0, r2, asr #31\n"
+      "add r1, r0, r2, asr #31\n";
   DriverStr(expected, "add");
 }
 
+TEST_F(AssemblerThumb2Test, umull) {
+  __ umull(arm::R0, arm::R1, arm::R2, arm::R3);
+
+  const char* expected =
+      "umull r0, r1, r2, r3\n";
+  DriverStr(expected, "umull");
+}
+
+TEST_F(AssemblerThumb2Test, smull) {
+  __ smull(arm::R0, arm::R1, arm::R2, arm::R3);
+
+  const char* expected =
+      "smull r0, r1, r2, r3\n";
+  DriverStr(expected, "smull");
+}
+
 TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) {
   arm::StoreOperandType type = arm::kStoreWord;
   int32_t offset = 4092;
@@ -346,4 +377,577 @@
   DriverStr(expected, "StoreWordPairToNonThumbOffset");
 }
 
+TEST_F(AssemblerThumb2Test, TwoCbzMaxOffset) {
+  Label label0, label1, label2;
+  __ cbz(arm::R0, &label1);
+  constexpr size_t kLdrR0R0Count1 = 63;
+  for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label0);
+  __ cbz(arm::R0, &label2);
+  __ Bind(&label1);
+  constexpr size_t kLdrR0R0Count2 = 64;
+  for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label2);
+
+  std::string expected =
+      "cbz r0, 1f\n" +            // cbz r0, label1
+      RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+      "0:\n"
+      "cbz r0, 2f\n"              // cbz r0, label2
+      "1:\n" +
+      RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+      "2:\n";
+  DriverStr(expected, "TwoCbzMaxOffset");
+
+  EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u,
+            __ GetAdjustedPosition(label0.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 0u,
+            __ GetAdjustedPosition(label1.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 0u,
+            __ GetAdjustedPosition(label2.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, TwoCbzBeyondMaxOffset) {
+  Label label0, label1, label2;
+  __ cbz(arm::R0, &label1);
+  constexpr size_t kLdrR0R0Count1 = 63;
+  for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label0);
+  __ cbz(arm::R0, &label2);
+  __ Bind(&label1);
+  constexpr size_t kLdrR0R0Count2 = 65;
+  for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label2);
+
+  std::string expected =
+      "cmp r0, #0\n"              // cbz r0, label1
+      "beq.n 1f\n" +
+      RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+      "0:\n"
+      "cmp r0, #0\n"              // cbz r0, label2
+      "beq.n 2f\n"
+      "1:\n" +
+      RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+      "2:\n";
+  DriverStr(expected, "TwoCbzBeyondMaxOffset");
+
+  EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
+            __ GetAdjustedPosition(label0.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 4u,
+            __ GetAdjustedPosition(label1.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 4u,
+            __ GetAdjustedPosition(label2.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, TwoCbzSecondAtMaxB16Offset) {
+  Label label0, label1, label2;
+  __ cbz(arm::R0, &label1);
+  constexpr size_t kLdrR0R0Count1 = 62;
+  for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label0);
+  __ cbz(arm::R0, &label2);
+  __ Bind(&label1);
+  constexpr size_t kLdrR0R0Count2 = 128;
+  for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label2);
+
+  std::string expected =
+      "cbz r0, 1f\n" +            // cbz r0, label1
+      RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+      "0:\n"
+      "cmp r0, #0\n"              // cbz r0, label2
+      "beq.n 2f\n"
+      "1:\n" +
+      RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+      "2:\n";
+  DriverStr(expected, "TwoCbzSecondAtMaxB16Offset");
+
+  EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 0u,
+            __ GetAdjustedPosition(label0.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u,
+            __ GetAdjustedPosition(label1.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u,
+            __ GetAdjustedPosition(label2.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, TwoCbzSecondBeyondMaxB16Offset) {
+  Label label0, label1, label2;
+  __ cbz(arm::R0, &label1);
+  constexpr size_t kLdrR0R0Count1 = 62;
+  for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label0);
+  __ cbz(arm::R0, &label2);
+  __ Bind(&label1);
+  constexpr size_t kLdrR0R0Count2 = 129;
+  for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label2);
+
+  std::string expected =
+      "cmp r0, #0\n"              // cbz r0, label1
+      "beq.n 1f\n" +
+      RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+      "0:\n"
+      "cmp r0, #0\n"              // cbz r0, label2
+      "beq.w 2f\n"
+      "1:\n" +
+      RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+      "2:\n";
+  DriverStr(expected, "TwoCbzSecondBeyondMaxB16Offset");
+
+  EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
+            __ GetAdjustedPosition(label0.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u,
+            __ GetAdjustedPosition(label1.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u,
+            __ GetAdjustedPosition(label2.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, TwoCbzFirstAtMaxB16Offset) {
+  Label label0, label1, label2;
+  __ cbz(arm::R0, &label1);
+  constexpr size_t kLdrR0R0Count1 = 127;
+  for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label0);
+  __ cbz(arm::R0, &label2);
+  __ Bind(&label1);
+  constexpr size_t kLdrR0R0Count2 = 64;
+  for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label2);
+
+  std::string expected =
+      "cmp r0, #0\n"              // cbz r0, label1
+      "beq.n 1f\n" +
+      RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+      "0:\n"
+      "cbz r0, 2f\n"              // cbz r0, label2
+      "1:\n" +
+      RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+      "2:\n";
+  DriverStr(expected, "TwoCbzFirstAtMaxB16Offset");
+
+  EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 2u,
+            __ GetAdjustedPosition(label0.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 2u,
+            __ GetAdjustedPosition(label1.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 2u,
+            __ GetAdjustedPosition(label2.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, TwoCbzFirstBeyondMaxB16Offset) {
+  Label label0, label1, label2;
+  __ cbz(arm::R0, &label1);
+  constexpr size_t kLdrR0R0Count1 = 127;
+  for (size_t i = 0; i != kLdrR0R0Count1; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label0);
+  __ cbz(arm::R0, &label2);
+  __ Bind(&label1);
+  constexpr size_t kLdrR0R0Count2 = 65;
+  for (size_t i = 0; i != kLdrR0R0Count2; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+  __ Bind(&label2);
+
+  std::string expected =
+      "cmp r0, #0\n"              // cbz r0, label1
+      "beq.w 1f\n" +
+      RepeatInsn(kLdrR0R0Count1, "ldr r0, [r0]\n") +
+      "0:\n"
+      "cmp r0, #0\n"              // cbz r0, label2
+      "beq.n 2f\n"
+      "1:\n" +
+      RepeatInsn(kLdrR0R0Count2, "ldr r0, [r0]\n") +
+      "2:\n";
+  DriverStr(expected, "TwoCbzFirstBeyondMaxB16Offset");
+
+  EXPECT_EQ(static_cast<uint32_t>(label0.Position()) + 4u,
+            __ GetAdjustedPosition(label0.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label1.Position()) + 6u,
+            __ GetAdjustedPosition(label1.Position()));
+  EXPECT_EQ(static_cast<uint32_t>(label2.Position()) + 6u,
+            __ GetAdjustedPosition(label2.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralMax1KiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R0, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = 511;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "1:\n"
+      "ldr.n r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralMax1KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1KiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R0, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = 512;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "1:\n"
+      "ldr.w r0, [pc, #((2f - 1b - 2) & ~2)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralBeyondMax1KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralMax4KiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = 2046;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "1:\n"
+      "ldr.w r1, [pc, #((2f - 1b - 2) & ~2)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralMax4KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 2u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax4KiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = 2047;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "movw r1, #4096\n"  // "as" does not consider (2f - 1f - 4) a constant expression for movw.
+      "1:\n"
+      "add r1, pc\n"
+      "ldr r1, [r1, #0]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralBeyondMax4KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralMax64KiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1u << 15) - 2u;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "movw r1, #0xfffc\n"  // "as" does not consider (2f - 1f - 4) a constant expression for movw.
+      "1:\n"
+      "add r1, pc\n"
+      "ldr r1, [r1, #0]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralMax64KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax64KiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1u << 15) - 1u;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n"
+      "1:\n"
+      "add r1, pc\n"
+      "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralBeyondMax64KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralMax1MiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1u << 19) - 3u;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "mov.w r1, #((2f - 1f - 4) & ~0xfff)\n"
+      "1:\n"
+      "add r1, pc\n"
+      "ldr r1, [r1, #((2f - 1b - 4) & 0xfff)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralMax1MiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 8u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralBeyondMax1MiB) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1u << 19) - 2u;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
+      "movw r1, #(0x100000 & 0xffff)\n"
+      // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
+      "movt r1, #(0x100000 >> 16)\n"
+      "1:\n"
+      "add r1, pc\n"
+      "ldr.w r1, [r1, #0]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralBeyondMax1MiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralFar) {
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::R1, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1u << 19) - 2u + 0x1234;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
+      "movw r1, #((0x100000 + 2 * 0x1234) & 0xffff)\n"
+      // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
+      "movt r1, #((0x100000 + 2 * 0x1234) >> 16)\n"
+      "1:\n"
+      "add r1, pc\n"
+      "ldr.w r1, [r1, #0]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralFar");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 12u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralWideMax1KiB) {
+  arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
+  __ LoadLiteral(arm::R1, arm::R3, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = 510;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "1:\n"
+      "ldrd r1, r3, [pc, #((2f - 1b - 2) & ~2)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x87654321\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralWideMax1KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 0u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralWideBeyondMax1KiB) {
+  arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
+  __ LoadLiteral(arm::R1, arm::R3, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = 511;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n"
+      "1:\n"
+      "add ip, pc\n"
+      "ldrd r1, r3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x87654321\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralWideBeyondMax1KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralSingleMax256KiB) {
+  // The literal size must match but the type doesn't, so use an int32_t rather than float.
+  arm::Literal* literal = __ NewLiteral<int32_t>(0x12345678);
+  __ LoadLiteral(arm::S3, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1 << 17) - 3u;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      "mov.w ip, #((2f - 1f - 4) & ~0x3ff)\n"
+      "1:\n"
+      "add ip, pc\n"
+      "vldr s3, [ip, #((2f - 1b - 4) & 0x3ff)]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralSingleMax256KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 6u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralDoubleBeyondMax256KiB) {
+  // The literal size must match but the type doesn't, so use an int64_t rather than double.
+  arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
+  __ LoadLiteral(arm::D3, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1 << 17) - 2u;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
+      "movw ip, #(0x40000 & 0xffff)\n"
+      // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
+      "movt ip, #(0x40000 >> 16)\n"
+      "1:\n"
+      "add ip, pc\n"
+      "vldr d3, [ip, #0]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x87654321\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralDoubleBeyondMax256KiB");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
+TEST_F(AssemblerThumb2Test, LoadLiteralDoubleFar) {
+  // The literal size must match but the type doesn't, so use an int64_t rather than double.
+  arm::Literal* literal = __ NewLiteral<int64_t>(INT64_C(0x1234567887654321));
+  __ LoadLiteral(arm::D3, literal);
+  Label label;
+  __ Bind(&label);
+  constexpr size_t kLdrR0R0Count = (1 << 17) - 2u + 0x1234;
+  for (size_t i = 0; i != kLdrR0R0Count; ++i) {
+    __ ldr(arm::R0, arm::Address(arm::R0));
+  }
+
+  std::string expected =
+      // "as" does not consider ((2f - 1f - 4) & 0xffff) a constant expression for movw.
+      "movw ip, #((0x40000 + 2 * 0x1234) & 0xffff)\n"
+      // "as" does not consider ((2f - 1f - 4) >> 16) a constant expression for movt.
+      "movt ip, #((0x40000 + 2 * 0x1234) >> 16)\n"
+      "1:\n"
+      "add ip, pc\n"
+      "vldr d3, [ip, #0]\n" +
+      RepeatInsn(kLdrR0R0Count, "ldr r0, [r0]\n") +
+      ".align 2, 0\n"
+      "2:\n"
+      ".word 0x87654321\n"
+      ".word 0x12345678\n";
+  DriverStr(expected, "LoadLiteralDoubleFar");
+
+  EXPECT_EQ(static_cast<uint32_t>(label.Position()) + 10u,
+            __ GetAdjustedPosition(label.Position()));
+}
+
 }  // namespace art
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index 7d98a30..0e17512 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -31,7 +31,7 @@
 #define ___   vixl_masm_->
 #endif
 
-void Arm64Assembler::EmitSlowPaths() {
+void Arm64Assembler::FinalizeCode() {
   if (!exception_blocks_.empty()) {
     for (size_t i = 0; i < exception_blocks_.size(); i++) {
       EmitExceptionPoll(exception_blocks_.at(i));
@@ -44,6 +44,10 @@
   return vixl_masm_->BufferCapacity() - vixl_masm_->RemainingBufferSpace();
 }
 
+const uint8_t* Arm64Assembler::CodeBufferBaseAddress() const {
+  return vixl_masm_->GetStartAddress<uint8_t*>();
+}
+
 void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
   // Copy the instructions from the buffer.
   MemoryRegion from(vixl_masm_->GetStartAddress<void*>(), CodeSize());
@@ -51,11 +55,11 @@
 }
 
 void Arm64Assembler::GetCurrentThread(ManagedRegister tr) {
-  ___ Mov(reg_x(tr.AsArm64().AsXRegister()), reg_x(ETR));
+  ___ Mov(reg_x(tr.AsArm64().AsXRegister()), reg_x(TR));
 }
 
 void Arm64Assembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scratch */) {
-  StoreToOffset(ETR, SP, offset.Int32Value());
+  StoreToOffset(TR, SP, offset.Int32Value());
 }
 
 // See Arm64 PCS Section 5.2.2.1.
@@ -167,7 +171,7 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsXRegister()) << scratch;
   LoadImmediate(scratch.AsXRegister(), imm);
-  StoreToOffset(scratch.AsXRegister(), ETR, offs.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), TR, offs.Int32Value());
 }
 
 void Arm64Assembler::StoreStackOffsetToThread64(ThreadOffset<8> tr_offs,
@@ -176,14 +180,14 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsXRegister()) << scratch;
   AddConstant(scratch.AsXRegister(), SP, fr_offs.Int32Value());
-  StoreToOffset(scratch.AsXRegister(), ETR, tr_offs.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
 }
 
 void Arm64Assembler::StoreStackPointerToThread64(ThreadOffset<8> tr_offs) {
   vixl::UseScratchRegisterScope temps(vixl_masm_);
   vixl::Register temp = temps.AcquireX();
   ___ Mov(temp, reg_x(SP));
-  ___ Str(temp, MEM_OP(reg_x(ETR), tr_offs.Int32Value()));
+  ___ Str(temp, MEM_OP(reg_x(TR), tr_offs.Int32Value()));
 }
 
 void Arm64Assembler::StoreSpanning(FrameOffset dest_off, ManagedRegister m_source,
@@ -284,7 +288,7 @@
 }
 
 void Arm64Assembler::LoadFromThread64(ManagedRegister m_dst, ThreadOffset<8> src, size_t size) {
-  return Load(m_dst.AsArm64(), ETR, src.Int32Value(), size);
+  return Load(m_dst.AsArm64(), TR, src.Int32Value(), size);
 }
 
 void Arm64Assembler::LoadRef(ManagedRegister m_dst, FrameOffset offs) {
@@ -294,15 +298,15 @@
 }
 
 void Arm64Assembler::LoadRef(ManagedRegister m_dst, ManagedRegister m_base, MemberOffset offs,
-                             bool poison_reference) {
+                             bool unpoison_reference) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
   Arm64ManagedRegister base = m_base.AsArm64();
   CHECK(dst.IsXRegister() && base.IsXRegister());
   LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), base.AsXRegister(),
                   offs.Int32Value());
-  if (kPoisonHeapReferences && poison_reference) {
+  if (unpoison_reference) {
     WRegister ref_reg = dst.AsOverlappingWRegister();
-    ___ Neg(reg_w(ref_reg), vixl::Operand(reg_w(ref_reg)));
+    MaybeUnpoisonHeapReference(reg_w(ref_reg));
   }
 }
 
@@ -319,7 +323,7 @@
 void Arm64Assembler::LoadRawPtrFromThread64(ManagedRegister m_dst, ThreadOffset<8> offs) {
   Arm64ManagedRegister dst = m_dst.AsArm64();
   CHECK(dst.IsXRegister()) << dst;
-  LoadFromOffset(dst.AsXRegister(), ETR, offs.Int32Value());
+  LoadFromOffset(dst.AsXRegister(), TR, offs.Int32Value());
 }
 
 // Copying routines.
@@ -357,7 +361,7 @@
                                           ManagedRegister m_scratch) {
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsXRegister()) << scratch;
-  LoadFromOffset(scratch.AsXRegister(), ETR, tr_offs.Int32Value());
+  LoadFromOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
   StoreToOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
 }
 
@@ -367,7 +371,7 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   CHECK(scratch.IsXRegister()) << scratch;
   LoadFromOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value());
-  StoreToOffset(scratch.AsXRegister(), ETR, tr_offs.Int32Value());
+  StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value());
 }
 
 void Arm64Assembler::CopyRef(FrameOffset dest, FrameOffset src,
@@ -611,7 +615,7 @@
   Arm64ManagedRegister scratch = m_scratch.AsArm64();
   Arm64Exception *current_exception = new Arm64Exception(scratch, stack_adjust);
   exception_blocks_.push_back(current_exception);
-  LoadFromOffset(scratch.AsXRegister(), ETR, Thread::ExceptionOffset<8>().Int32Value());
+  LoadFromOffset(scratch.AsXRegister(), TR, Thread::ExceptionOffset<8>().Int32Value());
   ___ Cbnz(reg_x(scratch.AsXRegister()), current_exception->Entry());
 }
 
@@ -628,12 +632,7 @@
   // Pass exception object as argument.
   // Don't care about preserving X0 as this won't return.
   ___ Mov(reg_x(X0), reg_x(exception->scratch_.AsXRegister()));
-  ___ Ldr(temp, MEM_OP(reg_x(ETR), QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value()));
-
-  // Move ETR(Callee saved) back to TR(Caller saved) reg. We use ETR on calls
-  // to external functions that might trash TR. We do not need the original
-  // ETR(X21) saved in BuildFrame().
-  ___ Mov(reg_x(TR), reg_x(ETR));
+  ___ Ldr(temp, MEM_OP(reg_x(TR), QUICK_ENTRYPOINT_OFFSET(8, pDeliverException).Int32Value()));
 
   ___ Blr(temp);
   // Call should never return.
@@ -714,12 +713,7 @@
   SpillRegisters(core_reg_list, frame_size - core_reg_size);
   SpillRegisters(fp_reg_list, frame_size - core_reg_size - fp_reg_size);
 
-  // Note: This is specific to JNI method frame.
-  // We will need to move TR(Caller saved in AAPCS) to ETR(Callee saved in AAPCS). The original
-  // (ETR)X21 has been saved on stack. In this way, we can restore TR later.
-  DCHECK(!core_reg_list.IncludesAliasOf(reg_x(TR)));
-  DCHECK(core_reg_list.IncludesAliasOf(reg_x(ETR)));
-  ___ Mov(reg_x(ETR), reg_x(TR));
+  DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR)));
 
   // Write ArtMethod*
   DCHECK(X0 == method_reg.AsArm64().AsXRegister());
@@ -771,11 +765,7 @@
   DCHECK_GE(frame_size, core_reg_size + fp_reg_size + kArm64PointerSize);
   DCHECK_ALIGNED(frame_size, kStackAlignment);
 
-  // Note: This is specific to JNI method frame.
-  // Restore TR(Caller saved in AAPCS) from ETR(Callee saved in AAPCS).
-  DCHECK(!core_reg_list.IncludesAliasOf(reg_x(TR)));
-  DCHECK(core_reg_list.IncludesAliasOf(reg_x(ETR)));
-  ___ Mov(reg_x(TR), reg_x(ETR));
+  DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR)));
 
   cfi_.RememberState();
 
@@ -794,5 +784,25 @@
   cfi_.DefCFAOffset(frame_size);
 }
 
+void Arm64Assembler::PoisonHeapReference(vixl::Register reg) {
+  DCHECK(reg.IsW());
+  // reg = -reg.
+  ___ Neg(reg, vixl::Operand(reg));
+}
+
+void Arm64Assembler::UnpoisonHeapReference(vixl::Register reg) {
+  DCHECK(reg.IsW());
+  // reg = -reg.
+  ___ Neg(reg, vixl::Operand(reg));
+}
+
+void Arm64Assembler::MaybeUnpoisonHeapReference(vixl::Register reg) {
+  if (kPoisonHeapReferences) {
+    UnpoisonHeapReference(reg);
+  }
+}
+
+#undef ___
+
 }  // namespace arm64
 }  // namespace art
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index fa9faed..05882a3 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -10,7 +10,7 @@
  * 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
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -73,11 +73,12 @@
     delete vixl_masm_;
   }
 
-  // Emit slow paths queued during assembly.
-  void EmitSlowPaths();
+  // Finalize the code.
+  void FinalizeCode() OVERRIDE;
 
   // Size of generated code.
-  size_t CodeSize() const;
+  size_t CodeSize() const OVERRIDE;
+  const uint8_t* CodeBufferBaseAddress() const OVERRIDE;
 
   // Copy instructions out of assembly buffer into the given region of memory.
   void FinalizeInstructions(const MemoryRegion& region);
@@ -115,7 +116,7 @@
   void LoadFromThread64(ManagedRegister dest, ThreadOffset<8> src, size_t size) OVERRIDE;
   void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
   void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
-               bool poison_reference) OVERRIDE;
+               bool unpoison_reference) OVERRIDE;
   void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
   void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset<8> offs) OVERRIDE;
 
@@ -181,6 +182,17 @@
   // and branch to a ExceptionSlowPath if it is.
   void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
 
+  //
+  // Heap poisoning.
+  //
+
+  // Poison a heap reference contained in `reg`.
+  void PoisonHeapReference(vixl::Register reg);
+  // Unpoison a heap reference contained in `reg`.
+  void UnpoisonHeapReference(vixl::Register reg);
+  // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
+  void MaybeUnpoisonHeapReference(vixl::Register reg);
+
  private:
   static vixl::Register reg_x(int code) {
     CHECK(code < kNumberOfXRegisters) << code;
diff --git a/compiler/utils/arm64/managed_register_arm64_test.cc b/compiler/utils/arm64/managed_register_arm64_test.cc
index 32c2e62..e27115d 100644
--- a/compiler/utils/arm64/managed_register_arm64_test.cc
+++ b/compiler/utils/arm64/managed_register_arm64_test.cc
@@ -623,7 +623,7 @@
   EXPECT_TRUE(vixl::x29.Is(Arm64Assembler::reg_x(X29)));
   EXPECT_TRUE(vixl::x30.Is(Arm64Assembler::reg_x(X30)));
 
-  EXPECT_TRUE(vixl::x18.Is(Arm64Assembler::reg_x(TR)));
+  EXPECT_TRUE(vixl::x19.Is(Arm64Assembler::reg_x(TR)));
   EXPECT_TRUE(vixl::ip0.Is(Arm64Assembler::reg_x(IP0)));
   EXPECT_TRUE(vixl::ip1.Is(Arm64Assembler::reg_x(IP1)));
   EXPECT_TRUE(vixl::x29.Is(Arm64Assembler::reg_x(FP)));
diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc
index b016e74..6d8a989 100644
--- a/compiler/utils/assembler.cc
+++ b/compiler/utils/assembler.cc
@@ -80,10 +80,11 @@
 }
 
 
-void AssemblerBuffer::ExtendCapacity() {
+void AssemblerBuffer::ExtendCapacity(size_t min_capacity) {
   size_t old_size = Size();
   size_t old_capacity = Capacity();
   size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
+  new_capacity = std::max(new_capacity, min_capacity);
 
   // Allocate the new data area and copy contents of the old one to it.
   uint8_t* new_contents = NewContents(new_capacity);
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 672e150..3097cd5 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -199,13 +199,18 @@
     *reinterpret_cast<T*>(contents_ + position) = value;
   }
 
-  void Move(size_t newposition, size_t oldposition) {
-    CHECK(HasEnsuredCapacity());
-    // Move the contents of the buffer from oldposition to
-    // newposition by nbytes.
-    size_t nbytes = Size() - oldposition;
-    memmove(contents_ + newposition, contents_ + oldposition, nbytes);
-    cursor_ += newposition - oldposition;
+  void Resize(size_t new_size) {
+    if (new_size > Capacity()) {
+      ExtendCapacity(new_size);
+    }
+    cursor_ = contents_ + new_size;
+  }
+
+  void Move(size_t newposition, size_t oldposition, size_t size) {
+    // Move a chunk of the buffer from oldposition to newposition.
+    DCHECK_LE(oldposition + size, Size());
+    DCHECK_LE(newposition + size, Size());
+    memmove(contents_ + newposition, contents_ + oldposition, size);
   }
 
   // Emit a fixup at the current location.
@@ -350,7 +355,7 @@
     return data + capacity - kMinimumGap;
   }
 
-  void ExtendCapacity();
+  void ExtendCapacity(size_t min_capacity = 0u);
 
   friend class AssemblerFixup;
 };
@@ -376,11 +381,12 @@
  public:
   static Assembler* Create(InstructionSet instruction_set);
 
-  // Emit slow paths queued during assembly
-  virtual void EmitSlowPaths() { buffer_.EmitSlowPaths(this); }
+  // Finalize the code; emit slow paths, fixup branches, add literal pool, etc.
+  virtual void FinalizeCode() { buffer_.EmitSlowPaths(this); }
 
   // Size of generated code
   virtual size_t CodeSize() const { return buffer_.Size(); }
+  virtual const uint8_t* CodeBufferBaseAddress() const { return buffer_.contents(); }
 
   // Copy instructions out of assembly buffer into the given region of memory
   virtual void FinalizeInstructions(const MemoryRegion& region) {
@@ -435,9 +441,9 @@
   virtual void LoadFromThread64(ManagedRegister dest, ThreadOffset<8> src, size_t size);
 
   virtual void LoadRef(ManagedRegister dest, FrameOffset src) = 0;
-  // If poison_reference is true and kPoisonReference is true, then we negate the read reference.
+  // If unpoison_reference is true and kPoisonReference is true, then we negate the read reference.
   virtual void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
-                       bool poison_reference) = 0;
+                       bool unpoison_reference) = 0;
 
   virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) = 0;
 
diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h
index a339633..017402d 100644
--- a/compiler/utils/assembler_test.h
+++ b/compiler/utils/assembler_test.h
@@ -544,6 +544,7 @@
   }
 
   void DriverWrapper(std::string assembly_text, std::string test_name) {
+    assembler_->FinalizeCode();
     size_t cs = assembler_->CodeSize();
     std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>(cs));
     MemoryRegion code(&(*data)[0], data->size());
diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h
index 574051a..c8b3fe5 100644
--- a/compiler/utils/assembler_test_base.h
+++ b/compiler/utils/assembler_test_base.h
@@ -216,9 +216,9 @@
 
     bool success = Exec(args, error_msg);
     if (!success) {
-      LOG(INFO) << "Assembler command line:";
+      LOG(ERROR) << "Assembler command line:";
       for (std::string arg : args) {
-        LOG(INFO) << arg;
+        LOG(ERROR) << arg;
       }
     }
     return success;
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 772fa9a..20f61f9 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -15,9 +15,11 @@
  */
 
 #include <dirent.h>
+#include <errno.h>
 #include <fstream>
-#include <sys/types.h>
 #include <map>
+#include <string.h>
+#include <sys/types.h>
 
 #include "gtest/gtest.h"
 #include "utils/arm/assembler_thumb2.h"
@@ -63,20 +65,33 @@
   return *s1 - *s2;
 }
 
-void dump(std::vector<uint8_t>& code, const char* testname) {
-  // This will only work on the host.  There is no as, objcopy or objdump on the
-  // device.
+void InitResults() {
+  if (test_results.empty()) {
+    setup_results();
+  }
+}
+
+std::string GetToolsDir() {
 #ifndef HAVE_ANDROID_OS
-  static bool results_ok = false;
+  // This will only work on the host.  There is no as, objcopy or objdump on the device.
   static std::string toolsdir;
 
-  if (!results_ok) {
+  if (toolsdir.empty()) {
     setup_results();
     toolsdir = CommonRuntimeTest::GetAndroidTargetToolsDir(kThumb2);
     SetAndroidData();
-    results_ok = true;
   }
 
+  return toolsdir;
+#else
+  return std::string();
+#endif
+}
+
+void DumpAndCheck(std::vector<uint8_t>& code, const char* testname, const char* const* results) {
+#ifndef HAVE_ANDROID_OS
+  static std::string toolsdir = GetToolsDir();
+
   ScratchFile file;
 
   const char* filename = file.GetFilename().c_str();
@@ -105,12 +120,14 @@
 
   // Assemble the .S
   snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
-  system(cmd);
+  int cmd_result = system(cmd);
+  ASSERT_EQ(cmd_result, 0) << strerror(errno);
 
   // Remove the $d symbols to prevent the disassembler dumping the instructions
   // as .word
   snprintf(cmd, sizeof(cmd), "%sobjcopy -N '$d' %s.o %s.oo", toolsdir.c_str(), filename, filename);
-  system(cmd);
+  int cmd_result2 = system(cmd);
+  ASSERT_EQ(cmd_result2, 0) << strerror(errno);
 
   // Disassemble.
 
@@ -119,15 +136,13 @@
   if (kPrintResults) {
     // Print the results only, don't check. This is used to generate new output for inserting
     // into the .inc file.
-    system(cmd);
+    int cmd_result3 = system(cmd);
+    ASSERT_EQ(cmd_result3, 0) << strerror(errno);
   } else {
     // Check the results match the appropriate results in the .inc file.
     FILE *fp = popen(cmd, "r");
     ASSERT_TRUE(fp != nullptr);
 
-    std::map<std::string, const char**>::iterator results = test_results.find(testname);
-    ASSERT_NE(results, test_results.end());
-
     uint32_t lineindex = 0;
 
     while (!feof(fp)) {
@@ -136,14 +151,14 @@
       if (s == nullptr) {
         break;
       }
-      if (CompareIgnoringSpace(results->second[lineindex], testline) != 0) {
+      if (CompareIgnoringSpace(results[lineindex], testline) != 0) {
         LOG(FATAL) << "Output is not as expected at line: " << lineindex
-          << results->second[lineindex] << "/" << testline;
+          << results[lineindex] << "/" << testline;
       }
       ++lineindex;
     }
     // Check that we are at the end.
-    ASSERT_TRUE(results->second[lineindex] == nullptr);
+    ASSERT_TRUE(results[lineindex] == nullptr);
     fclose(fp);
   }
 
@@ -158,8 +173,31 @@
 
 #define __ assembler->
 
+void EmitAndCheck(arm::Thumb2Assembler* assembler, const char* testname,
+                  const char* const* results) {
+  __ FinalizeCode();
+  size_t cs = __ CodeSize();
+  std::vector<uint8_t> managed_code(cs);
+  MemoryRegion code(&managed_code[0], managed_code.size());
+  __ FinalizeInstructions(code);
+
+  DumpAndCheck(managed_code, testname, results);
+}
+
+void EmitAndCheck(arm::Thumb2Assembler* assembler, const char* testname) {
+  InitResults();
+  std::map<std::string, const char* const*>::iterator results = test_results.find(testname);
+  ASSERT_NE(results, test_results.end());
+
+  EmitAndCheck(assembler, testname, results->second);
+}
+
+#undef __
+
+#define __ assembler.
+
 TEST(Thumb2AssemblerTest, SimpleMov) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R0, ShifterOperand(R1));
   __ mov(R8, ShifterOperand(R9));
@@ -167,46 +205,31 @@
   __ mov(R0, ShifterOperand(1));
   __ mov(R8, ShifterOperand(9));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "SimpleMov");
-  delete assembler;
+  EmitAndCheck(&assembler, "SimpleMov");
 }
 
 TEST(Thumb2AssemblerTest, SimpleMov32) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
-  assembler->Force32Bit();
+  arm::Thumb2Assembler assembler;
+  __ Force32Bit();
 
   __ mov(R0, ShifterOperand(R1));
   __ mov(R8, ShifterOperand(R9));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "SimpleMov32");
-  delete assembler;
+  EmitAndCheck(&assembler, "SimpleMov32");
 }
 
 TEST(Thumb2AssemblerTest, SimpleMovAdd) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R0, ShifterOperand(R1));
   __ add(R0, R1, ShifterOperand(R2));
   __ add(R0, R1, ShifterOperand());
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "SimpleMovAdd");
-  delete assembler;
+  EmitAndCheck(&assembler, "SimpleMovAdd");
 }
 
 TEST(Thumb2AssemblerTest, DataProcessingRegister) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R0, ShifterOperand(R1));
   __ mvn(R0, ShifterOperand(R1));
@@ -244,16 +267,11 @@
   // 32 bit variants.
   __ add(R12, R1, ShifterOperand(R0));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "DataProcessingRegister");
-  delete assembler;
+  EmitAndCheck(&assembler, "DataProcessingRegister");
 }
 
 TEST(Thumb2AssemblerTest, DataProcessingImmediate) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R0, ShifterOperand(0x55));
   __ mvn(R0, ShifterOperand(0x55));
@@ -278,16 +296,11 @@
   __ movs(R0, ShifterOperand(0x55));
   __ mvns(R0, ShifterOperand(0x55));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "DataProcessingImmediate");
-  delete assembler;
+  EmitAndCheck(&assembler, "DataProcessingImmediate");
 }
 
 TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediate) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R0, ShifterOperand(0x550055));
   __ mvn(R0, ShifterOperand(0x550055));
@@ -306,17 +319,12 @@
   __ cmp(R0, ShifterOperand(0x550055));
   __ cmn(R0, ShifterOperand(0x550055));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "DataProcessingModifiedImmediate");
-  delete assembler;
+  EmitAndCheck(&assembler, "DataProcessingModifiedImmediate");
 }
 
 
 TEST(Thumb2AssemblerTest, DataProcessingModifiedImmediates) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R0, ShifterOperand(0x550055));
   __ mov(R0, ShifterOperand(0x55005500));
@@ -326,16 +334,11 @@
   __ mov(R0, ShifterOperand(0x350));            // rotated to 2nd last position
   __ mov(R0, ShifterOperand(0x1a8));            // rotated to last position
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "DataProcessingModifiedImmediates");
-  delete assembler;
+  EmitAndCheck(&assembler, "DataProcessingModifiedImmediates");
 }
 
 TEST(Thumb2AssemblerTest, DataProcessingShiftedRegister) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mov(R3, ShifterOperand(R4, LSL, 4));
   __ mov(R3, ShifterOperand(R4, LSR, 5));
@@ -350,17 +353,12 @@
   __ mov(R8, ShifterOperand(R4, ROR, 7));
   __ mov(R8, ShifterOperand(R4, RRX));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "DataProcessingShiftedRegister");
-  delete assembler;
+  EmitAndCheck(&assembler, "DataProcessingShiftedRegister");
 }
 
 
 TEST(Thumb2AssemblerTest, BasicLoad) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ ldr(R3, Address(R4, 24));
   __ ldrb(R3, Address(R4, 24));
@@ -377,17 +375,12 @@
   __ ldrsb(R8, Address(R4, 24));
   __ ldrsh(R8, Address(R4, 24));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "BasicLoad");
-  delete assembler;
+  EmitAndCheck(&assembler, "BasicLoad");
 }
 
 
 TEST(Thumb2AssemblerTest, BasicStore) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ str(R3, Address(R4, 24));
   __ strb(R3, Address(R4, 24));
@@ -400,16 +393,11 @@
   __ strb(R8, Address(R4, 24));
   __ strh(R8, Address(R4, 24));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "BasicStore");
-  delete assembler;
+  EmitAndCheck(&assembler, "BasicStore");
 }
 
 TEST(Thumb2AssemblerTest, ComplexLoad) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ ldr(R3, Address(R4, 24, Address::Mode::Offset));
   __ ldr(R3, Address(R4, 24, Address::Mode::PreIndex));
@@ -446,17 +434,12 @@
   __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPreIndex));
   __ ldrsh(R3, Address(R4, 24, Address::Mode::NegPostIndex));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "ComplexLoad");
-  delete assembler;
+  EmitAndCheck(&assembler, "ComplexLoad");
 }
 
 
 TEST(Thumb2AssemblerTest, ComplexStore) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ str(R3, Address(R4, 24, Address::Mode::Offset));
   __ str(R3, Address(R4, 24, Address::Mode::PreIndex));
@@ -479,16 +462,11 @@
   __ strh(R3, Address(R4, 24, Address::Mode::NegPreIndex));
   __ strh(R3, Address(R4, 24, Address::Mode::NegPostIndex));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "ComplexStore");
-  delete assembler;
+  EmitAndCheck(&assembler, "ComplexStore");
 }
 
 TEST(Thumb2AssemblerTest, NegativeLoadStore) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ ldr(R3, Address(R4, -24, Address::Mode::Offset));
   __ ldr(R3, Address(R4, -24, Address::Mode::PreIndex));
@@ -546,30 +524,20 @@
   __ strh(R3, Address(R4, -24, Address::Mode::NegPreIndex));
   __ strh(R3, Address(R4, -24, Address::Mode::NegPostIndex));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "NegativeLoadStore");
-  delete assembler;
+  EmitAndCheck(&assembler, "NegativeLoadStore");
 }
 
 TEST(Thumb2AssemblerTest, SimpleLoadStoreDual) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ strd(R2, Address(R0, 24, Address::Mode::Offset));
   __ ldrd(R2, Address(R0, 24, Address::Mode::Offset));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "SimpleLoadStoreDual");
-  delete assembler;
+  EmitAndCheck(&assembler, "SimpleLoadStoreDual");
 }
 
 TEST(Thumb2AssemblerTest, ComplexLoadStoreDual) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ strd(R2, Address(R0, 24, Address::Mode::Offset));
   __ strd(R2, Address(R0, 24, Address::Mode::PreIndex));
@@ -585,16 +553,11 @@
   __ ldrd(R2, Address(R0, 24, Address::Mode::NegPreIndex));
   __ ldrd(R2, Address(R0, 24, Address::Mode::NegPostIndex));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "ComplexLoadStoreDual");
-  delete assembler;
+  EmitAndCheck(&assembler, "ComplexLoadStoreDual");
 }
 
 TEST(Thumb2AssemblerTest, NegativeLoadStoreDual) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ strd(R2, Address(R0, -24, Address::Mode::Offset));
   __ strd(R2, Address(R0, -24, Address::Mode::PreIndex));
@@ -610,16 +573,11 @@
   __ ldrd(R2, Address(R0, -24, Address::Mode::NegPreIndex));
   __ ldrd(R2, Address(R0, -24, Address::Mode::NegPostIndex));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "NegativeLoadStoreDual");
-  delete assembler;
+  EmitAndCheck(&assembler, "NegativeLoadStoreDual");
 }
 
 TEST(Thumb2AssemblerTest, SimpleBranch) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ mov(R0, ShifterOperand(2));
@@ -653,17 +611,12 @@
   __ Bind(&l5);
   __ mov(R0, ShifterOperand(6));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "SimpleBranch");
-  delete assembler;
+  EmitAndCheck(&assembler, "SimpleBranch");
 }
 
 TEST(Thumb2AssemblerTest, LongBranch) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
-  assembler->Force32Bit();
+  arm::Thumb2Assembler assembler;
+  __ Force32Bit();
   // 32 bit branches.
   Label l1;
   __ mov(R0, ShifterOperand(2));
@@ -698,16 +651,11 @@
   __ Bind(&l5);
   __ mov(R0, ShifterOperand(6));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "LongBranch");
-  delete assembler;
+  EmitAndCheck(&assembler, "LongBranch");
 }
 
 TEST(Thumb2AssemblerTest, LoadMultiple) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   // 16 bit.
   __ ldm(DB_W, R4, (1 << R0 | 1 << R3));
@@ -719,16 +667,11 @@
   // Single reg is converted to ldr
   __ ldm(DB_W, R4, (1 << R5));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "LoadMultiple");
-  delete assembler;
+  EmitAndCheck(&assembler, "LoadMultiple");
 }
 
 TEST(Thumb2AssemblerTest, StoreMultiple) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   // 16 bit.
   __ stm(IA_W, R4, (1 << R0 | 1 << R3));
@@ -741,16 +684,11 @@
   __ stm(IA_W, R4, (1 << R5));
   __ stm(IA, R4, (1 << R5));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "StoreMultiple");
-  delete assembler;
+  EmitAndCheck(&assembler, "StoreMultiple");
 }
 
 TEST(Thumb2AssemblerTest, MovWMovT) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ movw(R4, 0);         // 16 bit.
   __ movw(R4, 0x34);      // 16 bit.
@@ -763,16 +701,11 @@
   __ movt(R0, 0x1234);
   __ movt(R1, 0xffff);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "MovWMovT");
-  delete assembler;
+  EmitAndCheck(&assembler, "MovWMovT");
 }
 
 TEST(Thumb2AssemblerTest, SpecialAddSub) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ add(R2, SP, ShifterOperand(0x50));   // 16 bit.
   __ add(SP, SP, ShifterOperand(0x50));   // 16 bit.
@@ -787,16 +720,11 @@
 
   __ sub(SP, SP, ShifterOperand(0xf00));   // 32 bit due to imm size
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "SpecialAddSub");
-  delete assembler;
+  EmitAndCheck(&assembler, "SpecialAddSub");
 }
 
 TEST(Thumb2AssemblerTest, StoreToOffset) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ StoreToOffset(kStoreWord, R2, R4, 12);     // Simple
   __ StoreToOffset(kStoreWord, R2, R4, 0x2000);     // Offset too big.
@@ -804,17 +732,12 @@
   __ StoreToOffset(kStoreHalfword, R0, R12, 12);
   __ StoreToOffset(kStoreByte, R2, R12, 12);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "StoreToOffset");
-  delete assembler;
+  EmitAndCheck(&assembler, "StoreToOffset");
 }
 
 
 TEST(Thumb2AssemblerTest, IfThen) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ it(EQ);
   __ mov(R1, ShifterOperand(1), EQ);
@@ -843,16 +766,11 @@
   __ mov(R3, ShifterOperand(3), EQ);
   __ mov(R4, ShifterOperand(4), NE);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "IfThen");
-  delete assembler;
+  EmitAndCheck(&assembler, "IfThen");
 }
 
 TEST(Thumb2AssemblerTest, CbzCbnz) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ cbz(R2, &l1);
@@ -868,16 +786,11 @@
   __ Bind(&l2);
   __ mov(R2, ShifterOperand(4));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "CbzCbnz");
-  delete assembler;
+  EmitAndCheck(&assembler, "CbzCbnz");
 }
 
 TEST(Thumb2AssemblerTest, Multiply) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ mul(R0, R1, R0);
   __ mul(R0, R1, R2);
@@ -893,16 +806,11 @@
   __ umull(R0, R1, R2, R3);
   __ umull(R8, R9, R10, R11);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Multiply");
-  delete assembler;
+  EmitAndCheck(&assembler, "Multiply");
 }
 
 TEST(Thumb2AssemblerTest, Divide) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ sdiv(R0, R1, R2);
   __ sdiv(R8, R9, R10);
@@ -910,16 +818,11 @@
   __ udiv(R0, R1, R2);
   __ udiv(R8, R9, R10);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Divide");
-  delete assembler;
+  EmitAndCheck(&assembler, "Divide");
 }
 
 TEST(Thumb2AssemblerTest, VMov) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ vmovs(S1, 1.0);
   __ vmovd(D1, 1.0);
@@ -927,17 +830,12 @@
   __ vmovs(S1, S2);
   __ vmovd(D1, D2);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "VMov");
-  delete assembler;
+  EmitAndCheck(&assembler, "VMov");
 }
 
 
 TEST(Thumb2AssemblerTest, BasicFloatingPoint) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ vadds(S0, S1, S2);
   __ vsubs(S0, S1, S2);
@@ -959,16 +857,11 @@
   __ vnegd(D0, D1);
   __ vsqrtd(D0, D1);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "BasicFloatingPoint");
-  delete assembler;
+  EmitAndCheck(&assembler, "BasicFloatingPoint");
 }
 
 TEST(Thumb2AssemblerTest, FloatingPointConversions) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ vcvtsd(S2, D2);
   __ vcvtds(D2, S2);
@@ -985,16 +878,11 @@
   __ vcvtud(S1, D2);
   __ vcvtdu(D1, S2);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "FloatingPointConversions");
-  delete assembler;
+  EmitAndCheck(&assembler, "FloatingPointConversions");
 }
 
 TEST(Thumb2AssemblerTest, FloatingPointComparisons) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ vcmps(S0, S1);
   __ vcmpd(D0, D1);
@@ -1002,57 +890,37 @@
   __ vcmpsz(S2);
   __ vcmpdz(D2);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "FloatingPointComparisons");
-  delete assembler;
+  EmitAndCheck(&assembler, "FloatingPointComparisons");
 }
 
 TEST(Thumb2AssemblerTest, Calls) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ blx(LR);
   __ bx(LR);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Calls");
-  delete assembler;
+  EmitAndCheck(&assembler, "Calls");
 }
 
 TEST(Thumb2AssemblerTest, Breakpoint) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ bkpt(0);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Breakpoint");
-  delete assembler;
+  EmitAndCheck(&assembler, "Breakpoint");
 }
 
 TEST(Thumb2AssemblerTest, StrR1) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ str(R1, Address(SP, 68));
   __ str(R1, Address(SP, 1068));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "StrR1");
-  delete assembler;
+  EmitAndCheck(&assembler, "StrR1");
 }
 
 TEST(Thumb2AssemblerTest, VPushPop) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ vpushs(S2, 4);
   __ vpushd(D2, 4);
@@ -1060,16 +928,11 @@
   __ vpops(S2, 4);
   __ vpopd(D2, 4);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "VPushPop");
-  delete assembler;
+  EmitAndCheck(&assembler, "VPushPop");
 }
 
 TEST(Thumb2AssemblerTest, Max16BitBranch) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ b(&l1);
@@ -1079,16 +942,11 @@
   __ Bind(&l1);
   __ mov(R1, ShifterOperand(R2));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Max16BitBranch");
-  delete assembler;
+  EmitAndCheck(&assembler, "Max16BitBranch");
 }
 
 TEST(Thumb2AssemblerTest, Branch32) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ b(&l1);
@@ -1098,16 +956,11 @@
   __ Bind(&l1);
   __ mov(R1, ShifterOperand(R2));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Branch32");
-  delete assembler;
+  EmitAndCheck(&assembler, "Branch32");
 }
 
 TEST(Thumb2AssemblerTest, CompareAndBranchMax) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ cbz(R4, &l1);
@@ -1117,16 +970,11 @@
   __ Bind(&l1);
   __ mov(R1, ShifterOperand(R2));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "CompareAndBranchMax");
-  delete assembler;
+  EmitAndCheck(&assembler, "CompareAndBranchMax");
 }
 
 TEST(Thumb2AssemblerTest, CompareAndBranchRelocation16) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ cbz(R4, &l1);
@@ -1136,16 +984,11 @@
   __ Bind(&l1);
   __ mov(R1, ShifterOperand(R2));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "CompareAndBranchRelocation16");
-  delete assembler;
+  EmitAndCheck(&assembler, "CompareAndBranchRelocation16");
 }
 
 TEST(Thumb2AssemblerTest, CompareAndBranchRelocation32) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   __ cbz(R4, &l1);
@@ -1155,16 +998,11 @@
   __ Bind(&l1);
   __ mov(R1, ShifterOperand(R2));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "CompareAndBranchRelocation32");
-  delete assembler;
+  EmitAndCheck(&assembler, "CompareAndBranchRelocation32");
 }
 
 TEST(Thumb2AssemblerTest, MixedBranch32) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   Label l1;
   Label l2;
@@ -1179,16 +1017,11 @@
   __ Bind(&l1);
   __ mov(R1, ShifterOperand(R2));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "MixedBranch32");
-  delete assembler;
+  EmitAndCheck(&assembler, "MixedBranch32");
 }
 
 TEST(Thumb2AssemblerTest, Shifts) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   // 16 bit
   __ Lsl(R0, R1, 5);
@@ -1235,16 +1068,11 @@
   __ Lsr(R0, R8, R2, true);
   __ Asr(R0, R1, R8, true);
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "Shifts");
-  delete assembler;
+  EmitAndCheck(&assembler, "Shifts");
 }
 
 TEST(Thumb2AssemblerTest, LoadStoreRegOffset) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   // 16 bit.
   __ ldr(R0, Address(R1, R2));
@@ -1267,16 +1095,11 @@
   __ ldr(R0, Address(R1, R8));
   __ str(R0, Address(R1, R8));
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "LoadStoreRegOffset");
-  delete assembler;
+  EmitAndCheck(&assembler, "LoadStoreRegOffset");
 }
 
 TEST(Thumb2AssemblerTest, LoadStoreLiteral) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ ldr(R0, Address(4));
   __ str(R0, Address(4));
@@ -1290,16 +1113,11 @@
   __ str(R0, Address(0x3ff));       // 32 bit (no 16 bit str(literal)).
   __ str(R0, Address(0x7ff));       // 11 bits (32 bit).
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "LoadStoreLiteral");
-  delete assembler;
+  EmitAndCheck(&assembler, "LoadStoreLiteral");
 }
 
 TEST(Thumb2AssemblerTest, LoadStoreLimits) {
-  arm::Thumb2Assembler* assembler = static_cast<arm::Thumb2Assembler*>(Assembler::Create(kThumb2));
+  arm::Thumb2Assembler assembler;
 
   __ ldr(R0, Address(R4, 124));     // 16 bit.
   __ ldr(R0, Address(R4, 128));     // 32 bit.
@@ -1325,12 +1143,20 @@
   __ strh(R0, Address(R4, 62));     // 16 bit.
   __ strh(R0, Address(R4, 64));     // 32 bit.
 
-  size_t cs = __ CodeSize();
-  std::vector<uint8_t> managed_code(cs);
-  MemoryRegion code(&managed_code[0], managed_code.size());
-  __ FinalizeInstructions(code);
-  dump(managed_code, "LoadStoreLimits");
-  delete assembler;
+  EmitAndCheck(&assembler, "LoadStoreLimits");
+}
+
+TEST(Thumb2AssemblerTest, CompareAndBranch) {
+  arm::Thumb2Assembler assembler;
+
+  Label label;
+  __ CompareAndBranchIfZero(arm::R0, &label);
+  __ CompareAndBranchIfZero(arm::R11, &label);
+  __ CompareAndBranchIfNonZero(arm::R0, &label);
+  __ CompareAndBranchIfNonZero(arm::R11, &label);
+  __ Bind(&label);
+
+  EmitAndCheck(&assembler, "CompareAndBranch");
 }
 
 #undef __
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index 3d03234..280ed77 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -4822,7 +4822,17 @@
   "  30:   f8a4 0040       strh.w  r0, [r4, #64]   ; 0x40\n",
   nullptr
 };
-std::map<std::string, const char**> test_results;
+const char* CompareAndBranchResults[] = {
+  "  0: b130        cbz r0, 10 <CompareAndBranch+0x10>\n",
+  "  2: f1bb 0f00   cmp.w fp, #0\n",
+  "  6: d003        beq.n 10 <CompareAndBranch+0x10>\n",
+  "  8: b910        cbnz r0, 10 <CompareAndBranch+0x10>\n",
+  "  a: f1bb 0f00   cmp.w fp, #0\n",
+  "  e: d1ff        bne.n 10 <CompareAndBranch+0x10>\n",
+  nullptr
+};
+
+std::map<std::string, const char* const*> test_results;
 void setup_results() {
     test_results["SimpleMov"] = SimpleMovResults;
     test_results["SimpleMov32"] = SimpleMov32Results;
@@ -4869,4 +4879,5 @@
     test_results["LoadStoreRegOffset"] = LoadStoreRegOffsetResults;
     test_results["LoadStoreLiteral"] = LoadStoreLiteralResults;
     test_results["LoadStoreLimits"] = LoadStoreLimitsResults;
+    test_results["CompareAndBranch"] = CompareAndBranchResults;
 }
diff --git a/compiler/utils/growable_array.h b/compiler/utils/growable_array.h
index e4b1e7d..f85e026 100644
--- a/compiler/utils/growable_array.h
+++ b/compiler/utils/growable_array.h
@@ -46,8 +46,8 @@
       }
     }
 
-    bool Contains(T value) const {
-      for (size_t i = 0; i < num_used_; ++i) {
+    bool Contains(T value, size_t start_from = 0) const {
+      for (size_t i = start_from; i < num_used_; ++i) {
         if (elem_list_[i] == value) {
           return true;
         }
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index e55b461..c09dfcc 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -697,12 +697,12 @@
 }
 
 void MipsAssembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-                            bool poison_reference) {
+                            bool unpoison_reference) {
   MipsManagedRegister dest = mdest.AsMips();
   CHECK(dest.IsCoreRegister() && dest.IsCoreRegister());
   LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
                  base.AsMips().AsCoreRegister(), offs.Int32Value());
-  if (kPoisonHeapReferences && poison_reference) {
+  if (kPoisonHeapReferences && unpoison_reference) {
     Subu(dest.AsCoreRegister(), ZERO, dest.AsCoreRegister());
   }
 }
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 7b0fc39..0d1b82c 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -192,7 +192,7 @@
   void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
 
   void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-               bool poison_reference) OVERRIDE;
+               bool unpoison_reference) OVERRIDE;
 
   void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
 
diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc
index 3333cd2..24ea9e2 100644
--- a/compiler/utils/mips64/assembler_mips64.cc
+++ b/compiler/utils/mips64/assembler_mips64.cc
@@ -1242,12 +1242,12 @@
 }
 
 void Mips64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-                              bool poison_reference) {
+                              bool unpoison_reference) {
   Mips64ManagedRegister dest = mdest.AsMips64();
   CHECK(dest.IsGpuRegister() && base.AsMips64().IsGpuRegister());
   LoadFromOffset(kLoadUnsignedWord, dest.AsGpuRegister(),
                  base.AsMips64().AsGpuRegister(), offs.Int32Value());
-  if (kPoisonHeapReferences && poison_reference) {
+  if (kPoisonHeapReferences && unpoison_reference) {
     // TODO: review
     // Negate the 32-bit ref
     Dsubu(dest.AsGpuRegister(), ZERO, dest.AsGpuRegister());
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index 88cc4bc..47b146a 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -265,7 +265,7 @@
   void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
 
   void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-               bool poison_reference) OVERRIDE;
+               bool unpoison_reference) OVERRIDE;
 
   void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE;
 
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 390d46e..fa85ada 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1910,12 +1910,12 @@
 }
 
 void X86Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-                           bool poison_reference) {
+                           bool unpoison_reference) {
   X86ManagedRegister dest = mdest.AsX86();
   CHECK(dest.IsCpuRegister() && dest.IsCpuRegister());
   movl(dest.AsCpuRegister(), Address(base.AsX86().AsCpuRegister(), offs));
-  if (kPoisonHeapReferences && poison_reference) {
-    negl(dest.AsCpuRegister());
+  if (unpoison_reference) {
+    MaybeUnpoisonHeapReference(dest.AsCpuRegister());
   }
 }
 
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 1c1c023..d1b4e1d 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -541,7 +541,7 @@
   void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE;
 
   void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
-               bool poison_reference) OVERRIDE;
+               bool unpoison_reference) OVERRIDE;
 
   void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
 
@@ -616,6 +616,21 @@
   // and branch to a ExceptionSlowPath if it is.
   void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
 
+  //
+  // Heap poisoning.
+  //
+
+  // Poison a heap reference contained in `reg`.
+  void PoisonHeapReference(Register reg) { negl(reg); }
+  // Unpoison a heap reference contained in `reg`.
+  void UnpoisonHeapReference(Register reg) { negl(reg); }
+  // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
+  void MaybeUnpoisonHeapReference(Register reg) {
+    if (kPoisonHeapReferences) {
+      UnpoisonHeapReference(reg);
+    }
+  }
+
  private:
   inline void EmitUint8(uint8_t value);
   inline void EmitInt32(int32_t value);
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index ac95c71..f35f51c 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -2597,12 +2597,12 @@
 }
 
 void X86_64Assembler::LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs,
-                              bool poison_reference) {
+                              bool unpoison_reference) {
   X86_64ManagedRegister dest = mdest.AsX86_64();
   CHECK(dest.IsCpuRegister() && dest.IsCpuRegister());
   movl(dest.AsCpuRegister(), Address(base.AsX86_64().AsCpuRegister(), offs));
-  if (kPoisonHeapReferences && poison_reference) {
-    negl(dest.AsCpuRegister());
+  if (unpoison_reference) {
+    MaybeUnpoisonHeapReference(dest.AsCpuRegister());
   }
 }
 
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 6b2b65d..61ffeab 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -669,7 +669,7 @@
   void LoadRef(ManagedRegister dest, FrameOffset  src) OVERRIDE;
 
   void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
-               bool poison_reference) OVERRIDE;
+               bool unpoison_reference) OVERRIDE;
 
   void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE;
 
@@ -767,6 +767,21 @@
   // Is the constant area empty? Return true if there are no literals in the constant area.
   bool IsConstantAreaEmpty() const { return constant_area_.GetSize() == 0; }
 
+  //
+  // Heap poisoning.
+  //
+
+  // Poison a heap reference contained in `reg`.
+  void PoisonHeapReference(CpuRegister reg) { negl(reg); }
+  // Unpoison a heap reference contained in `reg`.
+  void UnpoisonHeapReference(CpuRegister reg) { negl(reg); }
+  // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
+  void MaybeUnpoisonHeapReference(CpuRegister reg) {
+    if (kPoisonHeapReferences) {
+      UnpoisonHeapReference(reg);
+    }
+  }
+
  private:
   void EmitUint8(uint8_t value);
   void EmitInt32(int32_t value);
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 d21f5cb..a4e74d4 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1040,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_;
@@ -1131,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;
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..f55dccd
--- /dev/null
+++ b/dexdump/dexdump.cc
@@ -0,0 +1,1298 @@
+/*
+ * 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, but tests can modify.
+ */
+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 int8_t   s1;
+typedef int16_t  s2;
+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;
+  }
+
+  // Determine if opening file yielded a single dex file. On failure,
+  // the parse error message of the original dexdump utility is shown.
+  //
+  // TODO(ajcbik): this restriction is not really needed, but kept
+  //               for now to stay close to original dexdump; we can
+  //               later relax this!
+  //
+  if (dex_files.size() != 1) {
+    fprintf(stderr, "ERROR: DEX parse failed\n");
+    return -1;
+  }
+
+  // Success. Either report checksum verification or process dex file.
+  if (gOptions.checksumOnly) {
+    fprintf(gOutFile, "Checksum verified\n");
+  } else {
+    processDexFile(fileName, dex_files[0].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..756f879
--- /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;
+    }
+  }
+
+  // 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++]);
+  }
+  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..d7c0e4c
--- /dev/null
+++ b/dexlist/dexlist.cc
@@ -0,0 +1,308 @@
+/*
+ * 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 uint16_t u2;
+typedef uint32_t u4;
+typedef uint64_t u8;
+typedef int32_t  s4;
+typedef int64_t  s8;
+
+/*
+ * 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;
+  }
+
+  // Determine if opening file yielded a single dex file.
+  //
+  // TODO(ajcbik): this restriction is not really needed, but kept
+  //               for now to stay close to original dexlist; we can
+  //               later relax this!
+  //
+  if (dex_files.size() != 1) {
+    fprintf(stderr, "ERROR: DEX parse failed\n");
+    return -1;
+  }
+  const DexFile* pDexFile = dex_files[0].get();
+
+  // Success. Iterate over all classes.
+  fprintf(gOutFile, "#%s\n", fileName);
+  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/disassembler/Android.mk b/disassembler/Android.mk
index 691c43f..039986c 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -59,12 +59,13 @@
   LOCAL_SRC_FILES := $$(LIBART_DISASSEMBLER_SRC_FILES)
 
   ifeq ($$(art_target_or_host),target)
-  	$(call set-target-local-clang-vars)
-  	$(call set-target-local-cflags-vars,$(2))
+    $(call set-target-local-clang-vars)
+    $(call set-target-local-cflags-vars,$(2))
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS)
     LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+    LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
     else
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index 6334717..e604c1f 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -55,4 +55,8 @@
   }
 }
 
+Disassembler* create_disassembler(InstructionSet instruction_set, DisassemblerOptions* options) {
+  return Disassembler::Create(instruction_set, options);
+}
+
 }  // namespace art
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 966ee3a..b99e5c2 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -63,6 +63,10 @@
   // Dump instructions within a range.
   virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0;
 
+  const DisassemblerOptions* GetDisassemblerOptions() const {
+    return disassembler_options_;
+  }
+
  protected:
   explicit Disassembler(DisassemblerOptions* disassembler_options)
       : disassembler_options_(disassembler_options) {
@@ -80,6 +84,9 @@
   return (value & (1 << bit)) != 0;
 }
 
+extern "C"
+Disassembler* create_disassembler(InstructionSet instruction_set, DisassemblerOptions* options);
+
 }  // namespace art
 
 #endif  // ART_DISASSEMBLER_DISASSEMBLER_H_
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index d195efc..348b2a5 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -31,8 +31,7 @@
 // runtime/arch/arm64/registers_arm64.h. We do not include that file to
 // avoid a dependency on libart.
 enum {
-  TR  = 18,
-  ETR = 21,
+  TR  = 19,
   IP0 = 16,
   IP1 = 17,
   FP  = 29,
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/Android.mk b/oatdump/Android.mk
index f01afc5..a3ef38d 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -47,12 +47,28 @@
 	@echo Output in $(ART_DUMP_OAT_PATH)/core.host.oatdump.txt
 endif
 
-.PHONY: dump-oat-core-target
+.PHONY: dump-oat-core-target-$(TARGET_ARCH)
 ifeq ($(ART_BUILD_TARGET),true)
-dump-oat-core-target: $(TARGET_CORE_IMAGE_default_no-pic_32) $(OATDUMP)
+dump-oat-core-target-$(TARGET_ARCH): $(TARGET_CORE_IMAGE_default_no-pic_$(ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
 	$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
-	  --output=$(ART_DUMP_OAT_PATH)/core.target.oatdump.txt --instruction-set=$(TARGET_ARCH)
-	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.oatdump.txt
+	  --output=$(ART_DUMP_OAT_PATH)/core.target.$(TARGET_ARCH).oatdump.txt --instruction-set=$(TARGET_ARCH)
+	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.$(TARGET_ARCH).oatdump.txt
+endif
+
+ifdef TARGET_2ND_ARCH
+.PHONY: dump-oat-core-target-$(TARGET_2ND_ARCH)
+ifeq ($(ART_BUILD_TARGET),true)
+dump-oat-core-target-$(TARGET_2ND_ARCH): $(TARGET_CORE_IMAGE_default_no-pic_$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)) $(OATDUMP)
+	$(OATDUMP) --image=$(TARGET_CORE_IMG_LOCATION) \
+	  --output=$(ART_DUMP_OAT_PATH)/core.target.$(TARGET_2ND_ARCH).oatdump.txt --instruction-set=$(TARGET_2ND_ARCH)
+	@echo Output in $(ART_DUMP_OAT_PATH)/core.target.$(TARGET_2ND_ARCH).oatdump.txt
+endif
+endif
+
+.PHONY: dump-oat-core-target
+dump-oat-core-target: dump-oat-core-target-$(TARGET_ARCH)
+ifdef TARGET_2ND_ARCH
+dump-oat-core-target: dump-oat-core-target-$(TARGET_2ND_ARCH)
 endif
 
 .PHONY: dump-oat-boot-$(TARGET_ARCH)
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 7ab6626..8dde547 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -306,6 +306,7 @@
   OatDumperOptions(bool dump_raw_mapping_table,
                    bool dump_raw_gc_map,
                    bool dump_vmap,
+                   bool dump_code_info_stack_maps,
                    bool disassemble_code,
                    bool absolute_addresses,
                    const char* class_filter,
@@ -317,6 +318,7 @@
     : dump_raw_mapping_table_(dump_raw_mapping_table),
       dump_raw_gc_map_(dump_raw_gc_map),
       dump_vmap_(dump_vmap),
+      dump_code_info_stack_maps_(dump_code_info_stack_maps),
       disassemble_code_(disassemble_code),
       absolute_addresses_(absolute_addresses),
       class_filter_(class_filter),
@@ -330,6 +332,7 @@
   const bool dump_raw_mapping_table_;
   const bool dump_raw_gc_map_;
   const bool dump_vmap_;
+  const bool dump_code_info_stack_maps_;
   const bool disassemble_code_;
   const bool absolute_addresses_;
   const char* const class_filter_;
@@ -352,7 +355,7 @@
       disassembler_(Disassembler::Create(instruction_set_,
                                          new DisassemblerOptions(options_.absolute_addresses_,
                                                                  oat_file.Begin(),
-                                                                 true /* can_read_litals_ */))) {
+                                                                 true /* can_read_literals_ */))) {
     CHECK(options_.class_loader_ != nullptr);
     CHECK(options_.class_filter_ != nullptr);
     CHECK(options_.method_filter_ != nullptr);
@@ -1013,15 +1016,13 @@
   void DumpVmapData(std::ostream& os,
                     const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem* code_item) {
-    if (oat_method.GetGcMap() == nullptr) {
-      // If the native GC map is null, then this method has been
-      // compiled with the optimizing compiler. The optimizing
-      // compiler currently outputs its stack maps in the vmap table.
+    if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
+      // The optimizing compiler outputs its CodeInfo data in the vmap table.
       const void* raw_code_info = oat_method.GetVmapTable();
       if (raw_code_info != nullptr) {
         CodeInfo code_info(raw_code_info);
         DCHECK(code_item != nullptr);
-        DumpCodeInfo(os, code_info, *code_item);
+        DumpCodeInfo(os, code_info, oat_method, *code_item);
       }
     } else {
       // Otherwise, display the vmap table.
@@ -1036,8 +1037,12 @@
   // Display a CodeInfo object emitted by the optimizing compiler.
   void DumpCodeInfo(std::ostream& os,
                     const CodeInfo& code_info,
+                    const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem& code_item) {
-    code_info.Dump(os, code_item.registers_size_);
+    code_info.Dump(os,
+                   oat_method.GetCodeOffset(),
+                   code_item.registers_size_,
+                   options_.dump_code_info_stack_maps_);
   }
 
   // Display a vmap table.
@@ -1200,6 +1205,23 @@
     }
   }
 
+  uint32_t DumpInformationAtOffset(std::ostream& os,
+                                   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);
+      }
+      // 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);
+    }
+  }
+
   uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
                                size_t offset, bool suspend_point_mapping) {
     MappingTable table(oat_method.GetMappingTable());
@@ -1302,6 +1324,37 @@
     }
   }
 
+  // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
+  // the optimizing compiler?
+  static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
+                                                    const DexFile::CodeItem* code_item) {
+    // 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;
+  }
+
+  void DumpDexRegisterMapAtOffset(std::ostream& os,
+                                  const OatFile::OatMethod& oat_method,
+                                  const DexFile::CodeItem* code_item,
+                                  size_t offset) {
+    // This method is only relevant for oat methods compiled with the
+    // optimizing compiler.
+    DCHECK(IsMethodGeneratedByOptimizingCompiler(oat_method, code_item));
+
+    // The optimizing compiler outputs its CodeInfo data in the vmap table.
+    const void* raw_code_info = oat_method.GetVmapTable();
+    if (raw_code_info != nullptr) {
+      CodeInfo code_info(raw_code_info);
+      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_);
+      }
+    }
+  }
+
   verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
                                          const DexFile* dex_file,
                                          const DexFile::ClassDef& class_def,
@@ -1337,11 +1390,11 @@
       size_t offset = 0;
       while (offset < code_size) {
         if (!bad_input) {
-          DumpMappingAtOffset(os, oat_method, offset, false);
+          DumpInformationAtOffset(os, oat_method, code_item, offset, false);
         }
         offset += disassembler_->Dump(os, quick_native_pc + offset);
         if (!bad_input) {
-          uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
+          uint32_t dex_pc = DumpInformationAtOffset(os, oat_method, code_item, offset, true);
           if (dex_pc != DexFile::kDexNoIndex) {
             DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
             if (verifier != nullptr) {
@@ -1565,7 +1618,8 @@
     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);
     os << "\n";
@@ -1836,10 +1890,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);
@@ -2317,6 +2375,8 @@
       dump_raw_gc_map_ = true;
     } else if (option == "--no-dump:vmap") {
       dump_vmap_ = false;
+    } else if (option =="--dump:code_info_stack_maps") {
+      dump_code_info_stack_maps_ = true;
     } else if (option == "--no-disassemble") {
       disassemble_code_ = false;
     } else if (option.starts_with("--symbolize=")) {
@@ -2396,6 +2456,9 @@
         "  --no-dump:vmap may be used to disable vmap dumping.\n"
         "      Example: --no-dump:vmap\n"
         "\n"
+        "  --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
+        "      Example: --dump:code_info_stack_maps\n"
+        "\n"
         "  --no-disassemble may be used to disable disassembly.\n"
         "      Example: --no-disassemble\n"
         "\n"
@@ -2436,6 +2499,7 @@
   bool dump_raw_mapping_table_ = false;
   bool dump_raw_gc_map_ = false;
   bool dump_vmap_ = true;
+  bool dump_code_info_stack_maps_ = false;
   bool disassemble_code_ = true;
   bool symbolize_ = false;
   bool list_classes_ = false;
@@ -2455,6 +2519,7 @@
         args_->dump_raw_mapping_table_,
         args_->dump_raw_gc_map_,
         args_->dump_vmap_,
+        args_->dump_code_info_stack_maps_,
         args_->disassemble_code_,
         absolute_addresses,
         args_->class_filter_,
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 b38f9bc..7f103a4 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -45,6 +45,7 @@
   dex_file_verifier.cc \
   dex_instruction.cc \
   elf_file.cc \
+  gc/allocation_record.cc \
   gc/allocator/dlmalloc.cc \
   gc/allocator/rosalloc.cc \
   gc/accounting/bitmap.cc \
@@ -368,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)
@@ -382,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,
@@ -402,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)
@@ -430,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))))
@@ -451,6 +462,7 @@
     endif
     LOCAL_CFLAGS += $$(ART_HOST_CFLAGS)
     LOCAL_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES="$(LIBART_HOST_DEFAULT_INSTRUCTION_SET_FEATURES)"
+    LOCAL_ASFLAGS += $$(ART_HOST_ASFLAGS)
 
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $$(ART_HOST_DEBUG_CFLAGS)
@@ -465,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.
@@ -476,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
-    # 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
@@ -497,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.
@@ -506,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/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S
index 2af636e..665d2a3 100644
--- a/runtime/arch/arm/asm_support_arm.S
+++ b/runtime/arch/arm/asm_support_arm.S
@@ -123,4 +123,18 @@
     END \name
 .endm
 
+// Macros to poison (negate) the reference for heap poisoning.
+.macro POISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    rsb \rRef, \rRef, #0
+#endif  // USE_HEAP_POISONING
+.endm
+
+// Macros to unpoison (negate) the reference for heap poisoning.
+.macro UNPOISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    rsb \rRef, \rRef, #0
+#endif  // USE_HEAP_POISONING
+.endm
+
 #endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index cafc868..2f2654d 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -127,11 +127,13 @@
     qpoints->pFmodf = fmodf;
     qpoints->pD2l = art_d2l;
     qpoints->pF2l = art_f2l;
+    qpoints->pL2f = art_l2f;
   } else {
     qpoints->pFmod = art_quick_fmod;
     qpoints->pFmodf = art_quick_fmodf;
     qpoints->pD2l = art_quick_d2l;
     qpoints->pF2l = art_quick_f2l;
+    qpoints->pL2f = art_quick_l2f;
   }
 
   // Intrinsics
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 90b0d53..d81e0a9 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -70,7 +70,7 @@
   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->arm_sp);
-  VLOG(signals) << "sp: " << *out_sp;
+  VLOG(signals) << "sp: " << std::hex << *out_sp;
   if (*out_sp == 0) {
     return;
   }
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index d02ab14..ca3ca1d 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -313,8 +313,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
      *
      * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
@@ -330,13 +329,10 @@
     .extern \cxx_name
 ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case allocation triggers GC
-    ldr    r2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE]  @ pass caller Method*
-    mov    r3, r9                         @ pass Thread::Current
-    mov    r12, sp
-    str    r12, [sp, #-16]!               @ expand the frame and pass SP
+    mov    r2, r9                         @ pass Thread::Current
+    mov    r3, sp
     .cfi_adjust_cfa_offset 16
     bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
-    add    sp, #16                        @ strip the extra frame
     .cfi_adjust_cfa_offset -16
     mov    r12, r1                        @ save Method*->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
@@ -620,12 +616,16 @@
 ENTRY art_quick_aput_obj
     cbz r2, .Ldo_aput_null
     ldr r3, [r0, #MIRROR_OBJECT_CLASS_OFFSET]
+    UNPOISON_HEAP_REF r3
     ldr ip, [r2, #MIRROR_OBJECT_CLASS_OFFSET]
+    UNPOISON_HEAP_REF ip
     ldr r3, [r3, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]
+    UNPOISON_HEAP_REF r3
     cmp r3, ip  @ value's type == array's component type - trivial assignability
     bne .Lcheck_assignability
 .Ldo_aput:
     add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
+    POISON_HEAP_REF r2
     str r2, [r3, r1, lsl #2]
     ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
     lsr r0, r0, #7
@@ -653,6 +653,7 @@
     .cfi_restore lr
     .cfi_adjust_cfa_offset -16
     add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
+    POISON_HEAP_REF r2
     str r2, [r3, r1, lsl #2]
     ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
     lsr r0, r0, #7
@@ -894,10 +895,7 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    ldr    r0, [sp, #0]            @ load caller Method*
-    ldr    r0, [r0, #ART_METHOD_DEX_CACHE_METHODS_OFFSET]  @ load dex_cache_resolved_methods
-    add    r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET  @ get starting address of data
-    ldr    r0, [r0, r12, lsl 2]    @ load the target method
+    mov    r0, r12
     b art_quick_invoke_interface_trampoline
 END art_quick_imt_conflict_trampoline
 
@@ -1480,3 +1478,18 @@
     vmov  r0, s0
     b     art_f2l
 END art_quick_f2l
+
+    /* float art_l2f(int64_t l) */
+    .extern art_l2f
+ENTRY art_quick_l2f
+    push  {lr}
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset lr, 0
+    sub   sp, #4
+    .cfi_adjust_cfa_offset 4
+    bl    art_l2f
+    vmov  s0, r0
+    add   sp, #4
+    .cfi_adjust_cfa_offset -4
+    pop   {pc}
+END art_quick_l2f
diff --git a/runtime/arch/arm64/asm_support_arm64.S b/runtime/arch/arm64/asm_support_arm64.S
index 39a8aa5..bcf55e3 100644
--- a/runtime/arch/arm64/asm_support_arm64.S
+++ b/runtime/arch/arm64/asm_support_arm64.S
@@ -22,9 +22,7 @@
 // Define special registers.
 
 // Register holding Thread::Current().
-#define xSELF x18
-// x18 is not preserved by aapcs64, save it on xETR(External Thread reg) for restore and later use.
-#define xETR x21
+#define xSELF x19
 // Frame Pointer
 #define xFP   x29
 // Link Register
@@ -57,4 +55,18 @@
     END \name
 .endm
 
+// Macros to poison (negate) the reference for heap poisoning.
+.macro POISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    neg \rRef, \rRef
+#endif  // USE_HEAP_POISONING
+.endm
+
+// Macros to unpoison (negate) the reference for heap poisoning.
+.macro UNPOISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    neg \rRef, \rRef
+#endif  // USE_HEAP_POISONING
+.endm
+
 #endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
diff --git a/runtime/arch/arm64/asm_support_arm64.h b/runtime/arch/arm64/asm_support_arm64.h
index 998f567..989ecc6 100644
--- a/runtime/arch/arm64/asm_support_arm64.h
+++ b/runtime/arch/arm64/asm_support_arm64.h
@@ -20,7 +20,7 @@
 #include "asm_support.h"
 
 #define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 176
-#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 112
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 96
 #define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 224
 
 #endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc
index 91c0fc9..60becc6 100644
--- a/runtime/arch/arm64/context_arm64.cc
+++ b/runtime/arch/arm64/context_arm64.cc
@@ -90,6 +90,7 @@
   gprs_[X13] = nullptr;
   gprs_[X14] = nullptr;
   gprs_[X15] = nullptr;
+  gprs_[X18] = nullptr;
 
   // d0-d7, d16-d31 are caller-saved; d8-d15 are callee-saved.
 
diff --git a/runtime/arch/arm64/entrypoints_init_arm64.cc b/runtime/arch/arm64/entrypoints_init_arm64.cc
index 8c8f8d5..2ce2a29 100644
--- a/runtime/arch/arm64/entrypoints_init_arm64.cc
+++ b/runtime/arch/arm64/entrypoints_init_arm64.cc
@@ -27,16 +27,9 @@
 namespace art {
 
 // Cast entrypoints.
-extern "C" uint32_t art_quick_assignable_from_code(const mirror::Class* klass,
+extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
                                             const mirror::Class* ref_class);
 
-// Single-precision FP arithmetics.
-extern "C" float art_quick_fmodf(float a, float b);          // REM_FLOAT[_2ADDR]
-
-// Double-precision FP arithmetics.
-extern "C" double art_quick_fmod(double a, double b);        // REM_DOUBLE[_2ADDR]
-
-
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
                      QuickEntryPoints* qpoints) {
   // Interpreter
@@ -50,7 +43,7 @@
   ResetQuickAllocEntryPoints(qpoints);
 
   // Cast
-  qpoints->pInstanceofNonTrivial = art_quick_assignable_from_code;
+  qpoints->pInstanceofNonTrivial = artIsAssignableFromCode;
   qpoints->pCheckCast = art_quick_check_cast;
 
   // DexCache
@@ -110,9 +103,9 @@
   qpoints->pCmpgFloat = nullptr;
   qpoints->pCmplDouble = nullptr;
   qpoints->pCmplFloat = nullptr;
-  qpoints->pFmod = art_quick_fmod;
+  qpoints->pFmod = fmod;
   qpoints->pL2d = nullptr;
-  qpoints->pFmodf = art_quick_fmodf;
+  qpoints->pFmodf = fmodf;
   qpoints->pL2f = nullptr;
   qpoints->pD2iz = nullptr;
   qpoints->pF2iz = nullptr;
@@ -129,7 +122,7 @@
   // Intrinsics
   qpoints->pIndexOf = art_quick_indexof;
   qpoints->pStringCompareTo = art_quick_string_compareto;
-  qpoints->pMemcpy = art_quick_memcpy;
+  qpoints->pMemcpy = memcpy;
 
   // Invocation
   qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline;
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index fce5f23..614936b 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -32,6 +32,7 @@
 
     // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs]  .
     THIS_LOAD_REQUIRES_READ_BARRIER
+
     // Loads appropriate callee-save-method.
     ldr xIP0, [xIP0, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET ]
 
@@ -43,43 +44,40 @@
 #error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM64) size not as expected."
 #endif
 
-    // FP callee-saves
-    stp d8, d9,   [sp, #8]
-    stp d10, d11, [sp, #24]
-    stp d12, d13, [sp, #40]
-    stp d14, d15, [sp, #56]
+    // Stack alignment filler [sp, #8].
+    // FP callee-saves.
+    stp d8, d9,   [sp, #16]
+    stp d10, d11, [sp, #32]
+    stp d12, d13, [sp, #48]
+    stp d14, d15, [sp, #64]
 
-    // Thread register and x19 (callee-save)
-    stp xSELF, x19, [sp, #72]
-    .cfi_rel_offset x18, 72
+    // GP callee-saves
+    stp x19, x20, [sp, #80]
     .cfi_rel_offset x19, 80
-
-    // callee-saves
-    stp x20, x21, [sp, #88]
     .cfi_rel_offset x20, 88
+
+    stp x21, x22, [sp, #96]
     .cfi_rel_offset x21, 96
-
-    stp x22, x23, [sp, #104]
     .cfi_rel_offset x22, 104
+
+    stp x23, x24, [sp, #112]
     .cfi_rel_offset x23, 112
-
-    stp x24, x25, [sp, #120]
     .cfi_rel_offset x24, 120
+
+    stp x25, x26, [sp, #128]
     .cfi_rel_offset x25, 128
-
-    stp x26, x27, [sp, #136]
     .cfi_rel_offset x26, 136
+
+    stp x27, x28, [sp, #144]
     .cfi_rel_offset x27, 144
-
-    stp x28, x29, [sp, #152]
     .cfi_rel_offset x28, 152
-    .cfi_rel_offset x29, 160
 
-    str xLR, [sp, #168]
+    stp x29, xLR, [sp, #160]
+    .cfi_rel_offset x29, 160
     .cfi_rel_offset x30, 168
 
-    // Loads appropriate callee-save-method
-    str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
+    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs].
+    str xIP0, [sp]
     // Place sp in Thread::Current()->top_quick_frame.
     mov xIP0, sp
     str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
@@ -96,50 +94,46 @@
     // Our registers aren't intermixed - just spill in order.
     ldr xIP0, [xIP0]  // xIP0 = & (art::Runtime * art::Runtime.instance_) .
 
-    // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs]  .
+    // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefOnly]  .
     THIS_LOAD_REQUIRES_READ_BARRIER
+
     // Loads appropriate callee-save-method.
     ldr xIP0, [xIP0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET ]
 
-    sub sp, sp, #112
-    .cfi_adjust_cfa_offset 112
+    sub sp, sp, #96
+    .cfi_adjust_cfa_offset 96
 
     // Ugly compile-time check, but we only have the preprocessor.
-#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 112)
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 96)
 #error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM64) size not as expected."
 #endif
 
-    // Callee-saves
-    stp x19, x20,  [sp, #16]
-    .cfi_rel_offset x19, 16
-    .cfi_rel_offset x20, 24
+    // GP callee-saves.
+    // x20 paired with ArtMethod* - see below.
+    stp x21, x22, [sp, #16]
+    .cfi_rel_offset x21, 16
+    .cfi_rel_offset x22, 24
 
-    stp x21, x22, [sp, #32]
-    .cfi_rel_offset x21, 32
-    .cfi_rel_offset x22, 40
+    stp x23, x24, [sp, #32]
+    .cfi_rel_offset x23, 32
+    .cfi_rel_offset x24, 40
 
-    stp x23, x24, [sp, #48]
-    .cfi_rel_offset x23, 48
-    .cfi_rel_offset x24, 56
+    stp x25, x26, [sp, #48]
+    .cfi_rel_offset x25, 48
+    .cfi_rel_offset x26, 56
 
-    stp x25, x26, [sp, #64]
-    .cfi_rel_offset x25, 64
-    .cfi_rel_offset x26, 72
+    stp x27, x28, [sp, #64]
+    .cfi_rel_offset x27, 64
+    .cfi_rel_offset x28, 72
 
-    stp x27, x28, [sp, #80]
-    .cfi_rel_offset x27, 80
-    .cfi_rel_offset x28, 88
+    stp x29, xLR, [sp, #80]
+    .cfi_rel_offset x29, 80
+    .cfi_rel_offset x30, 88
 
-    // x29(callee-save) and LR
-    stp x29, xLR, [sp, #96]
-    .cfi_rel_offset x29, 96
-    .cfi_rel_offset x30, 104
+    // Store ArtMethod* Runtime::callee_save_methods_[kRefsOnly].
+    stp xIP0, x20, [sp]
+    .cfi_rel_offset x20, 8
 
-    // Save xSELF to xETR.
-    mov xETR, xSELF
-
-    // Loads appropriate callee-save-method
-    str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsOnly]
     // Place sp in Thread::Current()->top_quick_frame.
     mov xIP0, sp
     str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
@@ -147,48 +141,37 @@
 
 // TODO: Probably no need to restore registers preserved by aapcs64.
 .macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
-    // Restore xSELF.
-    mov xSELF, xETR
-
-    // Callee-saves
-    ldp x19, x20,  [sp, #16]
-    .cfi_restore x19
+    // Callee-saves.
+    ldr x20, [sp, #8]
     .cfi_restore x20
 
-    ldp x21, x22, [sp, #32]
+    ldp x21, x22, [sp, #16]
     .cfi_restore x21
     .cfi_restore x22
 
-    ldp x23, x24, [sp, #48]
+    ldp x23, x24, [sp, #32]
     .cfi_restore x23
     .cfi_restore x24
 
-    ldp x25, x26, [sp, #64]
+    ldp x25, x26, [sp, #48]
     .cfi_restore x25
     .cfi_restore x26
 
-    ldp x27, x28, [sp, #80]
+    ldp x27, x28, [sp, #64]
     .cfi_restore x27
     .cfi_restore x28
 
-    // x29(callee-save) and LR
-    ldp x29, xLR, [sp, #96]
+    ldp x29, xLR, [sp, #80]
     .cfi_restore x29
     .cfi_restore x30
 
-    add sp, sp, #112
-    .cfi_adjust_cfa_offset -112
+    add sp, sp, #96
+    .cfi_adjust_cfa_offset -96
 .endm
 
 .macro POP_REFS_ONLY_CALLEE_SAVE_FRAME
-    // Restore xSELF as it might be scratched.
-    mov xSELF, xETR
-    // ETR
-    ldr xETR, [sp, #32]
-    .cfi_restore x21
-
-    add sp, sp, #112
-    .cfi_adjust_cfa_offset -112
+    add sp, sp, #96
+    .cfi_adjust_cfa_offset - 96
 .endm
 
 .macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
@@ -206,31 +189,29 @@
 #error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected."
 #endif
 
+    // Stack alignment filler [sp, #8].
     // FP args.
-    stp d0, d1, [sp, #8]
-    stp d2, d3, [sp, #24]
-    stp d4, d5, [sp, #40]
-    stp d6, d7, [sp, #56]
+    stp d0, d1, [sp, #16]
+    stp d2, d3, [sp, #32]
+    stp d4, d5, [sp, #48]
+    stp d6, d7, [sp, #64]
 
     // Core args.
-    str x1, [sp, 72]
-    .cfi_rel_offset x1, 72
+    stp x1, x2, [sp, #80]
+    .cfi_rel_offset x1, 80
+    .cfi_rel_offset x2, 88
 
-    stp x2,  x3, [sp, #80]
-    .cfi_rel_offset x2, 80
-    .cfi_rel_offset x3, 88
+    stp x3, x4, [sp, #96]
+    .cfi_rel_offset x3, 96
+    .cfi_rel_offset x4, 104
 
-    stp x4,  x5, [sp, #96]
-    .cfi_rel_offset x4, 96
-    .cfi_rel_offset x5, 104
+    stp x5, x6, [sp, #112]
+    .cfi_rel_offset x5, 112
+    .cfi_rel_offset x6, 120
 
-    stp x6,  x7, [sp, #112]
-    .cfi_rel_offset x6, 112
-    .cfi_rel_offset x7, 120
-
-    // Callee-saves.
-    stp x19, x20, [sp, #128]
-    .cfi_rel_offset x19, 128
+    // x7, Callee-saves.
+    stp x7, x20, [sp, #128]
+    .cfi_rel_offset x7, 128
     .cfi_rel_offset x20, 136
 
     stp x21, x22, [sp, #144]
@@ -249,13 +230,11 @@
     .cfi_rel_offset x27, 192
     .cfi_rel_offset x28, 200
 
-    // x29(callee-save) and LR
+    // x29(callee-save) and LR.
     stp x29, xLR, [sp, #208]
     .cfi_rel_offset x29, 208
     .cfi_rel_offset x30, 216
 
-    // Save xSELF to xETR.
-    mov xETR, xSELF
 .endm
 
     /*
@@ -293,34 +272,28 @@
 
 // TODO: Probably no need to restore registers preserved by aapcs64.
 .macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
-    // Restore xSELF.
-    mov xSELF, xETR
-
     // FP args.
-    ldp d0, d1, [sp, #8]
-    ldp d2, d3, [sp, #24]
-    ldp d4, d5, [sp, #40]
-    ldp d6, d7, [sp, #56]
+    ldp d0, d1, [sp, #16]
+    ldp d2, d3, [sp, #32]
+    ldp d4, d5, [sp, #48]
+    ldp d6, d7, [sp, #64]
 
     // Core args.
-    ldr x1, [sp, 72]
+    ldp x1, x2, [sp, #80]
     .cfi_restore x1
-
-    ldp x2,  x3, [sp, #80]
     .cfi_restore x2
+
+    ldp x3, x4, [sp, #96]
     .cfi_restore x3
-
-    ldp x4,  x5, [sp, #96]
     .cfi_restore x4
+
+    ldp x5, x6, [sp, #112]
     .cfi_restore x5
-
-    ldp x6,  x7, [sp, #112]
     .cfi_restore x6
-    .cfi_restore x7
 
-    // Callee-saves.
-    ldp x19, x20, [sp, #128]
-    .cfi_restore x19
+    // x7, Callee-saves.
+    ldp x7, x20, [sp, #128]
+    .cfi_restore x7
     .cfi_restore x20
 
     ldp x21, x22, [sp, #144]
@@ -339,7 +312,7 @@
     .cfi_restore x27
     .cfi_restore x28
 
-    // x29(callee-save) and LR
+    // x29(callee-save) and LR.
     ldp x29, xLR, [sp, #208]
     .cfi_restore x29
     .cfi_restore x30
@@ -461,8 +434,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/x0 with the target Method*, arg0/x0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/x1.
      *
      * The helper will attempt to locate the target and return a 128-bit result in x0/x1 consisting
@@ -485,10 +457,9 @@
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
 
-    ldr    x2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE]  // pass caller Method*
-    mov    x3, xSELF                      // pass Thread::Current
-    mov    x4, sp
-    bl     \cxx_name                      // (method_idx, this, caller, Thread*, SP)
+    mov    x2, xSELF                      // pass Thread::Current
+    mov    x3, sp
+    bl     \cxx_name                      // (method_idx, this, Thread*, SP)
     mov    xIP0, x1                       // save Method*->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     cbz    x0, 1f                         // did we find the target? if not go to exception delivery
@@ -1106,13 +1077,12 @@
     .extern artThrowClassCastException
 ENTRY art_quick_check_cast
     // Store arguments and link register
-    sub sp, sp, #32                     // Stack needs to be 16b aligned on calls
+    // Stack needs to be 16B aligned on calls.
+    stp x0, x1, [sp,#-32]!
     .cfi_adjust_cfa_offset 32
-    stp x0, x1, [sp]
     .cfi_rel_offset x0, 0
     .cfi_rel_offset x1, 8
-    stp xSELF, xLR, [sp, #16]
-    .cfi_rel_offset x18, 16
+    str xLR, [sp, #24]
     .cfi_rel_offset x30, 24
 
     // Call runtime code
@@ -1122,25 +1092,23 @@
     cbz x0, .Lthrow_class_cast_exception
 
     // Restore and return
-    ldp x0, x1, [sp]
+    ldr xLR, [sp, #24]
+    .cfi_restore x30
+    ldp x0, x1, [sp], #32
     .cfi_restore x0
     .cfi_restore x1
-    ldp xSELF, xLR, [sp, #16]
-    .cfi_restore x18
-    .cfi_restore x30
-    add sp, sp, #32
     .cfi_adjust_cfa_offset -32
     ret
 
+    .cfi_adjust_cfa_offset 32         // Reset unwind info so following code unwinds.
+
 .Lthrow_class_cast_exception:
     // Restore
-    ldp x0, x1, [sp]
+    ldr xLR, [sp, #24]
+    .cfi_restore x30
+    ldp x0, x1, [sp], #32
     .cfi_restore x0
     .cfi_restore x1
-    ldp xSELF, xLR, [sp, #16]
-    .cfi_restore x18
-    .cfi_restore x30
-    add sp, sp, #32
     .cfi_adjust_cfa_offset -32
 
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
@@ -1180,15 +1148,19 @@
     cbz x2, .Ldo_aput_null
     ldr w3, [x0, #MIRROR_OBJECT_CLASS_OFFSET]            // Heap reference = 32b
                                                          // This also zero-extends to x3
+    UNPOISON_HEAP_REF w3
     ldr w4, [x2, #MIRROR_OBJECT_CLASS_OFFSET]            // Heap reference = 32b
                                                          // This also zero-extends to x4
+    UNPOISON_HEAP_REF w4
     ldr w3, [x3, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]    // Heap reference = 32b
                                                          // This also zero-extends to x3
+    UNPOISON_HEAP_REF w3
     cmp w3, w4  // value's type == array's component type - trivial assignability
     bne .Lcheck_assignability
 .Ldo_aput:
     add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
                                                          // "Compress" = do nothing
+    POISON_HEAP_REF w2
     str w2, [x3, x1, lsl #2]                             // Heap reference = 32b
     ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
     lsr x0, x0, #7
@@ -1201,16 +1173,13 @@
     ret
 .Lcheck_assignability:
     // Store arguments and link register
-    sub sp, sp, #48                     // Stack needs to be 16b aligned on calls
-    .cfi_adjust_cfa_offset 48
-    stp x0, x1, [sp]
+    stp x0, x1, [sp,#-32]!
+    .cfi_adjust_cfa_offset 32
     .cfi_rel_offset x0, 0
     .cfi_rel_offset x1, 8
-    stp x2, xSELF, [sp, #16]
+    stp x2, xLR, [sp, #16]
     .cfi_rel_offset x2, 16
-    .cfi_rel_offset x18, 24
-    str xLR, [sp, #32]
-    .cfi_rel_offset x30, 32
+    .cfi_rel_offset x30, 24
 
     // Call runtime code
     mov x0, x3              // Heap reference, 32b, "uncompress" = do nothing, already zero-extended
@@ -1221,19 +1190,17 @@
     cbz x0, .Lthrow_array_store_exception
 
     // Restore
-    ldp x0, x1, [sp]
+    ldp x2, x30, [sp, #16]
+    .cfi_restore x2
+    .cfi_restore x30
+    ldp x0, x1, [sp], #32
     .cfi_restore x0
     .cfi_restore x1
-    ldp x2, xSELF, [sp, #16]
-    .cfi_restore x2
-    .cfi_restore x18
-    ldr xLR, [sp, #32]
-    .cfi_restore x30
-    add sp, sp, #48
-    .cfi_adjust_cfa_offset -48
+    .cfi_adjust_cfa_offset -32
 
     add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
                                                           // "Compress" = do nothing
+    POISON_HEAP_REF w2
     str w2, [x3, x1, lsl #2]                              // Heap reference = 32b
     ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
     lsr x0, x0, #7
@@ -1241,16 +1208,13 @@
     ret
     .cfi_adjust_cfa_offset 32  // 4 restores after cbz for unwinding.
 .Lthrow_array_store_exception:
-    ldp x0, x1, [sp]
+    ldp x2, x30, [sp, #16]
+    .cfi_restore x2
+    .cfi_restore x30
+    ldp x0, x1, [sp], #32
     .cfi_restore x0
     .cfi_restore x1
-    ldp x2, xSELF, [sp, #16]
-    .cfi_restore x2
-    .cfi_restore x18
-    ldr xLR, [sp, #32]
-    .cfi_restore x30
-    add sp, sp, #48
-    .cfi_adjust_cfa_offset -48
+    .cfi_adjust_cfa_offset -32
 
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     mov x1, x2                    // Pass value.
@@ -1451,8 +1415,7 @@
     mov     x2, xSELF                   // pass Thread::Current
     mov     x3, sp                      // pass SP
     bl      artQuickProxyInvokeHandler  // (Method* proxy method, receiver, Thread*, SP)
-    // Use xETR as xSELF might be scratched by native function above.
-    ldr     x2, [xETR, THREAD_EXCEPTION_OFFSET]
+    ldr     x2, [xSELF, THREAD_EXCEPTION_OFFSET]
     cbnz    x2, .Lexception_in_proxy    // success if no exception is pending
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME // Restore frame
     fmov    d0, x0                      // Store result in d0 in case it was float or double
@@ -1467,10 +1430,7 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    ldr    x0, [sp, #0]                                // load caller Method*
-    ldr    w0, [x0, #ART_METHOD_DEX_CACHE_METHODS_OFFSET]  // load dex_cache_resolved_methods
-    add    x0, x0, #MIRROR_LONG_ARRAY_DATA_OFFSET      // get starting address of data
-    ldr    x0, [x0, xIP1, lsl 3]                       // load the target method
+    mov    x0, xIP1
     b art_quick_invoke_interface_trampoline
 END art_quick_imt_conflict_trampoline
 
@@ -1602,15 +1562,14 @@
     // prepare for artQuickGenericJniEndTrampoline call
     // (Thread*, result, result_f)
     //    x0       x1       x2        <= C calling convention
-    mov x1, x0      // Result (from saved)
-    mov x0, xETR    // Thread register, original xSELF might be scratched by native code.
+    mov x1, x0      // Result (from saved).
+    mov x0, xSELF   // Thread register.
     fmov x2, d0     // d0 will contain floating point result, but needs to go into x2
 
     bl artQuickGenericJniEndTrampoline
 
     // Pending exceptions possible.
-    // Use xETR as xSELF might be scratched by native code
-    ldr x2, [xETR, THREAD_EXCEPTION_OFFSET]
+    ldr x2, [xSELF, THREAD_EXCEPTION_OFFSET]
     cbnz x2, .Lexception_in_native
 
     // Tear down the alloca.
@@ -1625,8 +1584,6 @@
     ret
 
 .Lexception_in_native:
-    // Restore xSELF. It might have been scratched by native code.
-    mov xSELF, xETR
     // Move to x1 then sp to please assembler.
     ldr x1, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
     mov sp, x1
@@ -1922,21 +1879,3 @@
     csel x0, x0, x14, ne         // x0 := x0 != 0 ? x14(prev x0=length diff) : x1.
     ret
 END art_quick_string_compareto
-
-// Macro to facilitate adding new entrypoints which call to native function directly.
-// Currently, xSELF is the only thing we need to take care of between managed code and AAPCS.
-// But we might introduce more differences.
-.macro NATIVE_DOWNCALL name, entrypoint
-    .extern \entrypoint
-ENTRY \name
-    stp    xSELF, xLR, [sp, #-16]!
-    bl     \entrypoint
-    ldp    xSELF, xLR, [sp], #16
-    ret
-END \name
-.endm
-
-NATIVE_DOWNCALL art_quick_fmod fmod
-NATIVE_DOWNCALL art_quick_fmodf fmodf
-NATIVE_DOWNCALL art_quick_memcpy memcpy
-NATIVE_DOWNCALL art_quick_assignable_from_code artIsAssignableFromCode
diff --git a/runtime/arch/arm64/quick_method_frame_info_arm64.h b/runtime/arch/arm64/quick_method_frame_info_arm64.h
index dfb3f99..b525309 100644
--- a/runtime/arch/arm64/quick_method_frame_info_arm64.h
+++ b/runtime/arch/arm64/quick_method_frame_info_arm64.h
@@ -33,18 +33,17 @@
     (1 << art::arm64::LR);
 // Callee saved registers
 static constexpr uint32_t kArm64CalleeSaveRefSpills =
-    (1 << art::arm64::X19) | (1 << art::arm64::X20) | (1 << art::arm64::X21) |
-    (1 << art::arm64::X22) | (1 << art::arm64::X23) | (1 << art::arm64::X24) |
-    (1 << art::arm64::X25) | (1 << art::arm64::X26) | (1 << art::arm64::X27) |
-    (1 << art::arm64::X28) | (1 << art::arm64::X29);
+    (1 << art::arm64::X20) | (1 << art::arm64::X21) | (1 << art::arm64::X22) |
+    (1 << art::arm64::X23) | (1 << art::arm64::X24) | (1 << art::arm64::X25) |
+    (1 << art::arm64::X26) | (1 << art::arm64::X27) | (1 << art::arm64::X28) |
+    (1 << art::arm64::X29);
 // X0 is the method pointer. Not saved.
 static constexpr uint32_t kArm64CalleeSaveArgSpills =
     (1 << art::arm64::X1) | (1 << art::arm64::X2) | (1 << art::arm64::X3) |
     (1 << art::arm64::X4) | (1 << art::arm64::X5) | (1 << art::arm64::X6) |
     (1 << art::arm64::X7);
 static constexpr uint32_t kArm64CalleeSaveAllSpills =
-    // Thread register.
-    (1 << art::arm64::X18);
+    (1 << art::arm64::X19);
 
 static constexpr uint32_t kArm64CalleeSaveFpAlwaysSpills = 0;
 static constexpr uint32_t kArm64CalleeSaveFpRefSpills = 0;
diff --git a/runtime/arch/arm64/registers_arm64.h b/runtime/arch/arm64/registers_arm64.h
index 51ae184..4683fc3 100644
--- a/runtime/arch/arm64/registers_arm64.h
+++ b/runtime/arch/arm64/registers_arm64.h
@@ -60,8 +60,7 @@
                  // different enum value to distinguish between the two.
   kNumberOfXRegisters = 33,
   // Aliases.
-  TR  = X18,     // ART Thread Register - Managed Runtime (Caller Saved Reg)
-  ETR = X21,     // ART Thread Register - External Calls  (Callee Saved Reg)
+  TR  = X19,     // ART Thread Register - Managed Runtime (Callee Saved Reg)
   IP0 = X16,     // Used as scratch by VIXL.
   IP1 = X17,     // Used as scratch by ART JNI Assembler.
   FP  = X29,
diff --git a/runtime/arch/memcmp16_test.cc b/runtime/arch/memcmp16_test.cc
index 5ba06f8..9ba7de1 100644
--- a/runtime/arch/memcmp16_test.cc
+++ b/runtime/arch/memcmp16_test.cc
@@ -144,10 +144,10 @@
     ASSERT_EQ(expected, computed) << "Run " << round << ", c1=" << count1 << " c2=" << count2;
 
     if (count1 > 0U) {
-      delete s1;
+      delete[] s1;
     }
     if (count2 > 0U) {
-      delete s2;
+      delete[] s2;
     }
   }
 }
diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S
index eea6537..51e224c 100644
--- a/runtime/arch/mips/asm_support_mips.S
+++ b/runtime/arch/mips/asm_support_mips.S
@@ -115,5 +115,18 @@
 
 #endif  /* mips_isa_rev */
 
+// Macros to poison (negate) the reference for heap poisoning.
+.macro POISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    subu \rRef, $zero, \rRef
+#endif  // USE_HEAP_POISONING
+.endm
+
+// Macros to unpoison (negate) the reference for heap poisoning.
+.macro UNPOISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    subu \rRef, $zero, \rRef
+#endif  // USE_HEAP_POISONING
+.endm
 
 #endif  // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_S_
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index d148747..cc1de43 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -447,8 +447,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
      *
      * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
@@ -464,15 +463,13 @@
     .extern \cxx_name
 ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
-    lw    $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE+ARG_SLOT_SIZE($sp)    # pass caller Method*
-    addiu $t0, $sp, ARG_SLOT_SIZE         # save $sp (remove arg slots)
-    move  $a3, rSELF                      # pass Thread::Current
-    jal   \cxx_name                       # (method_idx, this, caller, Thread*, $sp)
-    sw    $t0, 16($sp)                    # pass $sp
-    move  $a0, $v0                        # save target Method*
+    move  $a2, rSELF                       # pass Thread::Current
+    jal   \cxx_name                        # (method_idx, this, Thread*, $sp)
+    addiu $a3, $sp, ARG_SLOT_SIZE          # pass $sp (remove arg slots)
+    move  $a0, $v0                         # save target Method*
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
     beqz  $v0, 1f
-    move  $t9, $v1                        # save $v0->code_
+    move  $t9, $v1                         # save $v0->code_
     jalr  $zero, $t9
     nop
 1:
@@ -653,13 +650,17 @@
     beqz $a2, .Ldo_aput_null
     nop
     lw $t0, MIRROR_OBJECT_CLASS_OFFSET($a0)
+    UNPOISON_HEAP_REF $t0
     lw $t1, MIRROR_OBJECT_CLASS_OFFSET($a2)
+    UNPOISON_HEAP_REF $t1
     lw $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($t0)
+    UNPOISON_HEAP_REF $t0
     bne $t1, $t0, .Lcheck_assignability  # value's type == array's component type - trivial assignability
     nop
 .Ldo_aput:
     sll $a1, $a1, 2
     add $t0, $a0, $a1
+    POISON_HEAP_REF $a2
     sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
     lw  $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
     srl $t1, $a0, 7
@@ -1102,13 +1103,9 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    lw      $a0, 0($sp)            # load caller Method*
-    lw      $a0, ART_METHOD_DEX_CACHE_METHODS_OFFSET($a0)  # load dex_cache_resolved_methods
-    sll     $t0, 2                 # convert target method offset to bytes
-    add     $a0, $t0               # get address of target method
-    lw      $a0, MIRROR_OBJECT_ARRAY_DATA_OFFSET($a0)  # load the target method
     la      $t9, art_quick_invoke_interface_trampoline
     jalr    $zero, $t9
+    move    $a0, $t0
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
diff --git a/runtime/arch/mips64/asm_support_mips64.S b/runtime/arch/mips64/asm_support_mips64.S
index 2613777..b859c70 100644
--- a/runtime/arch/mips64/asm_support_mips64.S
+++ b/runtime/arch/mips64/asm_support_mips64.S
@@ -69,5 +69,18 @@
     END \name
 .endm
 
+// Macros to poison (negate) the reference for heap poisoning.
+.macro POISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    subu \rRef, $zero, \rRef
+#endif  // USE_HEAP_POISONING
+.endm
+
+// Macros to unpoison (negate) the reference for heap poisoning.
+.macro UNPOISON_HEAP_REF rRef
+#ifdef USE_HEAP_POISONING
+    subu \rRef, $zero, \rRef
+#endif  // USE_HEAP_POISONING
+.endm
 
 #endif  // ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_S_
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index b662821..37c6c5b 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -529,10 +529,9 @@
     .extern \cxx_name
 ENTRY \c_name
     SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
-    ld    $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE($sp)  # pass caller Method*
-    move  $a3, rSELF                       # pass Thread::Current
-    jal   \cxx_name                        # (method_idx, this, caller, Thread*, $sp)
-    move  $a4, $sp                         # pass $sp
+    move  $a2, rSELF                       # pass Thread::Current
+    jal   \cxx_name                        # (method_idx, this, Thread*, $sp)
+    move  $a3, $sp                         # pass $sp
     move  $a0, $v0                         # save target Method*
     move  $t9, $v1                         # save $v0->code_
     RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
@@ -913,13 +912,17 @@
     beq  $a2, $zero, .Ldo_aput_null
     nop
     lwu $t0, MIRROR_OBJECT_CLASS_OFFSET($a0)
+    UNPOISON_HEAP_REF $t0
     lwu $t1, MIRROR_OBJECT_CLASS_OFFSET($a2)
+    UNPOISON_HEAP_REF $t1
     lwu $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($t0)
+    UNPOISON_HEAP_REF $t0
     bne $t1, $t0, .Lcheck_assignability  # value's type == array's component type - trivial assignability
     nop
 .Ldo_aput:
     dsll  $a1, $a1, 2
     daddu $t0, $a0, $a1
+    POISON_HEAP_REF $a2
     sw   $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
     ld   $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
     dsrl  $t1, $a0, 7
@@ -1366,14 +1369,10 @@
      * dex method index.
      */
 ENTRY art_quick_imt_conflict_trampoline
-    ld      $a0, 0($sp)            # load caller Method*
-    lwu     $a0, ART_METHOD_DEX_CACHE_METHODS_OFFSET($a0)  # load dex_cache_resolved_methods
-    dsll    $t0, 3                 # convert target method offset to bytes
-    daddu   $a0, $t0               # get address of target method
     dla     $t9, art_quick_invoke_interface_trampoline
     .cpreturn
     jalr    $zero, $t9
-    ld      $a0, MIRROR_LONG_ARRAY_DATA_OFFSET($a0)  # load the target method
+    move    $a0, $t0
 END art_quick_imt_conflict_trampoline
 
     .extern artQuickResolutionTrampoline
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 13acaa7..05b42f5 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -173,7 +173,7 @@
         // Load call params into the right registers.
         "ldp x0, x1, [sp]\n\t"
         "ldp x2, x3, [sp, #16]\n\t"
-        "ldr x18, [sp, #32]\n\t"
+        "ldr x19, [sp, #32]\n\t"
         "add sp, sp, #48\n\t"
         ".cfi_adjust_cfa_offset -48\n\t"
 
@@ -526,7 +526,7 @@
         // Load call params into the right registers.
         "ldp x0, x1, [sp]\n\t"
         "ldp x2, x3, [sp, #16]\n\t"
-        "ldp x18, x17, [sp, #32]\n\t"
+        "ldp x19, x17, [sp, #32]\n\t"
         "add sp, sp, #48\n\t"
         ".cfi_adjust_cfa_offset -48\n\t"
 
@@ -1124,7 +1124,7 @@
 
 
 TEST_F(StubTest, APutObj) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
     (defined(__x86_64__) && !defined(__APPLE__))
@@ -1258,7 +1258,7 @@
 }
 
 TEST_F(StubTest, AllocObject) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
     (defined(__x86_64__) && !defined(__APPLE__))
@@ -1385,7 +1385,7 @@
 }
 
 TEST_F(StubTest, AllocObjectArray) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
     (defined(__x86_64__) && !defined(__APPLE__))
@@ -1474,7 +1474,7 @@
 
 
 TEST_F(StubTest, StringCompareTo) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   // TODO: Check the "Unresolved" allocation stubs
@@ -2152,7 +2152,7 @@
 }
 
 TEST_F(StubTest, Fields8) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
 
@@ -2166,7 +2166,7 @@
 }
 
 TEST_F(StubTest, Fields16) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
 
@@ -2180,7 +2180,7 @@
 }
 
 TEST_F(StubTest, Fields32) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
 
@@ -2193,7 +2193,7 @@
 }
 
 TEST_F(StubTest, FieldsObj) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
 
@@ -2206,7 +2206,7 @@
 }
 
 TEST_F(StubTest, Fields64) {
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
 
@@ -2221,7 +2221,7 @@
 TEST_F(StubTest, IMT) {
 #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
     (defined(__x86_64__) && !defined(__APPLE__))
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
 
@@ -2342,7 +2342,7 @@
 
 TEST_F(StubTest, StringIndexOf) {
 #if defined(__arm__) || defined(__aarch64__)
-  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
+  TEST_DISABLED_FOR_READ_BARRIER();
 
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index 122428b..2159f0e 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -179,4 +179,18 @@
 #endif
 END_MACRO
 
+// Macros to poison (negate) the reference for heap poisoning.
+MACRO1(POISON_HEAP_REF, rRef)
+#ifdef USE_HEAP_POISONING
+    neg REG_VAR(rRef, 0)
+#endif  // USE_HEAP_POISONING
+END_MACRO
+
+// Macros to unpoison (negate) the reference for heap poisoning.
+MACRO1(UNPOISON_HEAP_REF, rRef)
+#ifdef USE_HEAP_POISONING
+    neg REG_VAR(rRef, 0)
+#endif  // USE_HEAP_POISONING
+END_MACRO
+
 #endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 870a747..c9bc977 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -33,6 +33,7 @@
     movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg, 0)), REG_VAR(temp_reg, 1)
     movl (REG_VAR(temp_reg, 1)), REG_VAR(temp_reg, 1)
     // Push save all callee-save method.
+    THIS_LOAD_REQUIRES_READ_BARRIER
     pushl RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg, 1))
     CFI_ADJUST_CFA_OFFSET(4)
     // Store esp as the top quick frame.
@@ -59,6 +60,7 @@
     movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg, 0)), REG_VAR(temp_reg, 1)
     movl (REG_VAR(temp_reg, 1)), REG_VAR(temp_reg, 1)
     // Push save all callee-save method.
+    THIS_LOAD_REQUIRES_READ_BARRIER
     pushl RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg, 1))
     CFI_ADJUST_CFA_OFFSET(4)
     // Store esp as the top quick frame.
@@ -104,6 +106,7 @@
     movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg, 0)), REG_VAR(temp_reg, 1)
     movl (REG_VAR(temp_reg, 1)), REG_VAR(temp_reg, 1)
     // Push save all callee-save method.
+    THIS_LOAD_REQUIRES_READ_BARRIER
     pushl RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET(REG_VAR(temp_reg, 1))
     CFI_ADJUST_CFA_OFFSET(4)
     // Store esp as the stop quick frame.
@@ -278,8 +281,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3 and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
      *
      * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
@@ -297,19 +299,15 @@
     movl %esp, %edx  // remember SP
 
     // Outgoing argument set up
-    subl MACRO_LITERAL(12), %esp  // alignment padding
-    CFI_ADJUST_CFA_OFFSET(12)
     PUSH edx                      // pass SP
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     CFI_ADJUST_CFA_OFFSET(4)
-    pushl 32+32(%edx)             // pass caller Method*
-    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)
     movl %edx, %edi               // save code pointer in EDI
-    addl MACRO_LITERAL(36), %esp  // Pop arguments skip eax
-    CFI_ADJUST_CFA_OFFSET(-36)
+    addl MACRO_LITERAL(20), %esp  // Pop arguments skip eax
+    CFI_ADJUST_CFA_OFFSET(-20)
 
     // Restore FPRs.
     movsd 0(%esp), %xmm0
@@ -1107,6 +1105,8 @@
     addl LITERAL(12), %esp        // pop arguments
     CFI_ADJUST_CFA_OFFSET(-12)
     ret
+
+    CFI_ADJUST_CFA_OFFSET(12)     // Reset unwind info so following code unwinds.
 1:
     POP eax                       // pop arguments
     POP ecx
@@ -1147,11 +1147,22 @@
     test %edx, %edx              // store of null
     jz .Ldo_aput_null
     movl MIRROR_OBJECT_CLASS_OFFSET(%eax), %ebx
+    UNPOISON_HEAP_REF ebx
     movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%ebx), %ebx
+    UNPOISON_HEAP_REF ebx
     // value's type == array's component type - trivial assignability
+#ifdef USE_HEAP_POISONING
+    PUSH eax  // save eax
+    movl MIRROR_OBJECT_CLASS_OFFSET(%edx), %eax
+    UNPOISON_HEAP_REF eax
+    cmpl %eax, %ebx
+    POP  eax  // restore eax
+#else
     cmpl MIRROR_OBJECT_CLASS_OFFSET(%edx), %ebx
+#endif
     jne .Lcheck_assignability
 .Ldo_aput:
+    POISON_HEAP_REF edx
     movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)
     movl %fs:THREAD_CARD_TABLE_OFFSET, %edx
     shrl LITERAL(7), %eax
@@ -1166,7 +1177,13 @@
     PUSH edx
     subl LITERAL(8), %esp        // alignment padding
     CFI_ADJUST_CFA_OFFSET(8)
+#ifdef USE_HEAP_POISONING
+    movl MIRROR_OBJECT_CLASS_OFFSET(%edx), %eax  // pass arg2 - type of the value to be stored
+    UNPOISON_HEAP_REF eax
+    PUSH eax
+#else
     pushl MIRROR_OBJECT_CLASS_OFFSET(%edx)  // pass arg2 - type of the value to be stored
+#endif
     CFI_ADJUST_CFA_OFFSET(4)
     PUSH ebx                      // pass arg1 - component type of the array
     call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
@@ -1177,6 +1194,7 @@
     POP  edx
     POP  ecx
     POP  eax
+    POISON_HEAP_REF edx
     movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4)  // do the aput
     movl %fs:THREAD_CARD_TABLE_OFFSET, %edx
     shrl LITERAL(7), %eax
@@ -1392,16 +1410,11 @@
 END_FUNCTION art_quick_proxy_invoke_handler
 
     /*
-     * Called to resolve an imt conflict. xmm0 is a hidden argument that holds the target method's
+     * Called to resolve an imt conflict. xmm7 is a hidden argument that holds the target method's
      * dex method index.
      */
 DEFINE_FUNCTION art_quick_imt_conflict_trampoline
-    PUSH ecx
-    movl 8(%esp), %eax            // load caller Method*
-    movl ART_METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax  // load dex_cache_resolved_methods
-    movd %xmm7, %ecx              // get target method index stored in xmm0
-    movl MIRROR_OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax  // load the target method
-    POP ecx
+    movd %xmm7, %eax              // get target method index stored in xmm7
     jmp SYMBOL(art_quick_invoke_interface_trampoline)
 END_FUNCTION art_quick_imt_conflict_trampoline
 
diff --git a/runtime/arch/x86/thread_x86.cc b/runtime/arch/x86/thread_x86.cc
index b97c143..3d19f06 100644
--- a/runtime/arch/x86/thread_x86.cc
+++ b/runtime/arch/x86/thread_x86.cc
@@ -79,7 +79,8 @@
   }
 #else
   // Read current LDT entries.
-  CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t));
+  static_assert(static_cast<size_t>(LDT_ENTRY_SIZE) == sizeof(uint64_t),
+                "LDT_ENTRY_SIZE is different from sizeof(uint64_t).");
   std::vector<uint64_t> ldt(LDT_ENTRIES);
   size_t ldt_size(sizeof(uint64_t) * ldt.size());
   memset(&ldt[0], 0, ldt_size);
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index 5964314..b2b6c2d 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -170,4 +170,18 @@
     int3
 END_MACRO
 
+// Macros to poison (negate) the reference for heap poisoning.
+MACRO1(POISON_HEAP_REF, rRef)
+#ifdef USE_HEAP_POISONING
+    negl REG_VAR(rRef, 0)
+#endif  // USE_HEAP_POISONING
+END_MACRO
+
+// Macros to unpoison (negate) the reference for heap poisoning.
+MACRO1(UNPOISON_HEAP_REF, rRef)
+#ifdef USE_HEAP_POISONING
+    negl REG_VAR(rRef, 0)
+#endif  // USE_HEAP_POISONING
+END_MACRO
+
 #endif  // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_S_
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index f11eb06..7d86c3a 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -339,8 +339,7 @@
     /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/rdi with the target Method*, arg0/rdi will contain
-     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
-     * stack and call the appropriate C helper.
+     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/rsi.
      *
      * The helper will attempt to locate the target and return a 128-bit result in rax/rdx consisting
@@ -360,11 +359,10 @@
     // Helper signature is always
     // (method_idx, *this_object, *caller_method, *self, sp)
 
-    movq FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE(%rsp), %rdx  // pass caller Method*
-    movq %gs:THREAD_SELF_OFFSET, %rcx                      // pass Thread
-    movq %rsp, %r8                                         // pass SP
+    movq %gs:THREAD_SELF_OFFSET, %rdx                      // pass Thread
+    movq %rsp, %rcx                                        // pass SP
 
-    call VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, caller method*, Thread*, SP)
+    call VAR(cxx_name, 1)                   // cxx_name(arg1, arg2, Thread*, SP)
                                                            // save the code pointer
     movq %rax, %rdi
     movq %rdx, %rax
@@ -921,8 +919,10 @@
     // RDI: uint32_t type_idx, RSI: ArtMethod*
     // RDX, RCX, R8, R9: free. RAX: return val.
     movl ART_METHOD_DEX_CACHE_TYPES_OFFSET(%rsi), %edx  // Load dex cache resolved types array
+    UNPOISON_HEAP_REF edx
                                                                // Load the class
     movl MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdx, %rdi, MIRROR_OBJECT_ARRAY_COMPONENT_SIZE), %edx
+    UNPOISON_HEAP_REF edx
     testl %edx, %edx                                           // Check null class
     jz   .Lart_quick_alloc_object_tlab_slow_path
                                                                // Check class status.
@@ -1134,6 +1134,8 @@
     CFI_ADJUST_CFA_OFFSET(-16)
 
     ret
+
+    CFI_ADJUST_CFA_OFFSET(16 + 4 * 8)  // Reset unwind info so following code unwinds.
 1:
     RESTORE_FP_CALLEE_SAVE_FRAME
     POP rsi                           // Pop arguments
@@ -1191,12 +1193,21 @@
     jz .Ldo_aput_null
     movl MIRROR_OBJECT_CLASS_OFFSET(%edi), %ecx
 //  movq MIRROR_OBJECT_CLASS_OFFSET(%rdi), %rcx
+    UNPOISON_HEAP_REF ecx
     movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%ecx), %ecx
 //  movq MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rcx), %rcx
+    UNPOISON_HEAP_REF ecx
+#ifdef USE_HEAP_POISONING
+    movl MIRROR_OBJECT_CLASS_OFFSET(%edx), %eax  // rax is free.
+    UNPOISON_HEAP_REF eax
+    cmpl %eax, %ecx  // value's type == array's component type - trivial assignability
+#else
     cmpl MIRROR_OBJECT_CLASS_OFFSET(%edx), %ecx // value's type == array's component type - trivial assignability
 //  cmpq MIRROR_CLASS_OFFSET(%rdx), %rcx
+#endif
     jne .Lcheck_assignability
 .Ldo_aput:
+    POISON_HEAP_REF edx
     movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
 //  movq %rdx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
     movq %gs:THREAD_CARD_TABLE_OFFSET, %rdx
@@ -1219,6 +1230,7 @@
 
                                   // "Uncompress" = do nothing, as already zero-extended on load.
     movl MIRROR_OBJECT_CLASS_OFFSET(%edx), %esi // Pass arg2 = value's class.
+    UNPOISON_HEAP_REF esi
     movq %rcx, %rdi               // Pass arg1 = array's component type.
 
     call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b)
@@ -1235,6 +1247,7 @@
     POP  rsi
     POP  rdi
 
+    POISON_HEAP_REF edx
     movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%edi, %esi, 4)
 //  movq %rdx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
     movq %gs:THREAD_CARD_TABLE_OFFSET, %rdx
@@ -1338,9 +1351,7 @@
     int3
     int3
 #else
-    movq 8(%rsp), %rdi            // load caller Method*
-    movl ART_METHOD_DEX_CACHE_METHODS_OFFSET(%rdi), %edi     // load dex_cache_resolved_methods
-    movq MIRROR_LONG_ARRAY_DATA_OFFSET(%rdi, %rax, 8), %rdi  // load the target method
+    movq %rax, %rdi
     jmp art_quick_invoke_interface_trampoline
 #endif  // __APPLE__
 END_FUNCTION art_quick_imt_conflict_trampoline
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index ee51ec9..73beb1f 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -34,7 +34,8 @@
 namespace art {
 
 inline mirror::Class* ArtField::GetDeclaringClass() {
-  mirror::Class* result = declaring_class_.Read();
+  GcRootSource gc_root_source(this);
+  mirror::Class* result = declaring_class_.Read(&gc_root_source);
   DCHECK(result != nullptr);
   DCHECK(result->IsLoaded() || result->IsErroneous());
   return result;
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 5cfce41..8712bdb 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -36,7 +36,8 @@
 namespace art {
 
 inline mirror::Class* ArtMethod::GetDeclaringClassUnchecked() {
-  return declaring_class_.Read();
+  GcRootSource gc_root_source(this);
+  return declaring_class_.Read(&gc_root_source);
 }
 
 inline mirror::Class* ArtMethod::GetDeclaringClassNoBarrier() {
@@ -84,7 +85,8 @@
 }
 
 inline mirror::PointerArray* ArtMethod::GetDexCacheResolvedMethods() {
-  return dex_cache_resolved_methods_.Read();
+  GcRootSource gc_root_source(this);
+  return dex_cache_resolved_methods_.Read(&gc_root_source);
 }
 
 inline ArtMethod* ArtMethod::GetDexCacheResolvedMethod(uint16_t method_index, size_t ptr_size) {
@@ -118,7 +120,8 @@
 }
 
 inline mirror::ObjectArray<mirror::Class>* ArtMethod::GetDexCacheResolvedTypes() {
-  return dex_cache_resolved_types_.Read();
+  GcRootSource gc_root_source(this);
+  return dex_cache_resolved_types_.Read(&gc_root_source);
 }
 
 template <bool kWithCheck>
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 16c099d..c78a851 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -182,29 +182,33 @@
   uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
   if (IsOptimized(sizeof(void*))) {
     CodeInfo code_info = GetOptimizedCodeInfo();
-    return code_info.GetStackMapForNativePcOffset(sought_offset).GetDexPc(code_info);
-  }
-
-  MappingTable table(entry_point != nullptr ?
-      GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
-  if (table.TotalSize() == 0) {
-    // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
-    // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
-    DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
-    return DexFile::kDexNoIndex;   // Special no mapping case
-  }
-  // Assume the caller wants a pc-to-dex mapping so check here first.
-  typedef MappingTable::PcToDexIterator It;
-  for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
-    if (cur.NativePcOffset() == sought_offset) {
-      return cur.DexPc();
+    StackMapEncoding encoding = code_info.ExtractEncoding();
+    StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset, encoding);
+    if (stack_map.IsValid()) {
+      return stack_map.GetDexPc(encoding);
     }
-  }
-  // Now check dex-to-pc mappings.
-  typedef MappingTable::DexToPcIterator It2;
-  for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
-    if (cur.NativePcOffset() == sought_offset) {
-      return cur.DexPc();
+  } else {
+    MappingTable table(entry_point != nullptr ?
+        GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
+    if (table.TotalSize() == 0) {
+      // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
+      // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
+      DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
+      return DexFile::kDexNoIndex;   // Special no mapping case
+    }
+    // Assume the caller wants a pc-to-dex mapping so check here first.
+    typedef MappingTable::PcToDexIterator It;
+    for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
+      if (cur.NativePcOffset() == sought_offset) {
+        return cur.DexPc();
+      }
+    }
+    // Now check dex-to-pc mappings.
+    typedef MappingTable::DexToPcIterator It2;
+    for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
+      if (cur.NativePcOffset() == sought_offset) {
+        return cur.DexPc();
+      }
     }
   }
   if (abort_on_failure) {
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..20d75f3 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -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/barrier.cc b/runtime/barrier.cc
index d21f551..0d842cc 100644
--- a/runtime/barrier.cc
+++ b/runtime/barrier.cc
@@ -16,6 +16,7 @@
 
 #include "barrier.h"
 
+#include "base/logging.h"
 #include "base/mutex.h"
 #include "base/time_utils.h"
 #include "thread.h"
@@ -87,7 +88,14 @@
 }
 
 Barrier::~Barrier() {
-  CHECK_EQ(count_, 0) << "Attempted to destroy barrier with non zero count";
+  if (gAborting == 0) {
+    // Only check when not aborting.
+    CHECK_EQ(count_, 0) << "Attempted to destroy barrier with non zero count";
+  } else {
+    if (count_ != 0) {
+      LOG(WARNING) << "Attempted to destroy barrier with non zero count " << count_;
+    }
+  }
 }
 
 }  // namespace art
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/bit_vector.h b/runtime/base/bit_vector.h
index 17835f5..afa8dc1 100644
--- a/runtime/base/bit_vector.h
+++ b/runtime/base/bit_vector.h
@@ -21,6 +21,7 @@
 #include <iterator>
 
 #include "base/bit_utils.h"
+#include "globals.h"
 
 namespace art {
 
@@ -229,6 +230,19 @@
   // Number of bits set in range [0, end) in storage. (No range check.)
   static uint32_t NumSetBits(const uint32_t* storage, uint32_t end);
 
+  // Fill given memory region with the contents of the vector and zero padding.
+  void CopyTo(void* dst, size_t len) const {
+    DCHECK_LE(static_cast<size_t>(GetHighestBitSet() + 1), len * kBitsPerByte);
+    size_t vec_len = GetSizeOf();
+    if (vec_len < len) {
+      void* dst_padding = reinterpret_cast<uint8_t*>(dst) + vec_len;
+      memcpy(dst, storage_, vec_len);
+      memset(dst_padding, 0, len - vec_len);
+    } else {
+      memcpy(dst, storage_, len);
+    }
+  }
+
   void Dump(std::ostream& os, const char* prefix) const;
 
  private:
diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc
index c51b9b0..19c01f2 100644
--- a/runtime/base/bit_vector_test.cc
+++ b/runtime/base/bit_vector_test.cc
@@ -211,4 +211,62 @@
   }
 }
 
+TEST(BitVector, CopyTo) {
+  {
+    // Test copying an empty BitVector. Padding should fill `buf` with zeroes.
+    BitVector bv(0, true, Allocator::GetMallocAllocator());
+    uint32_t buf;
+
+    bv.CopyTo(&buf, sizeof(buf));
+    EXPECT_EQ(0u, bv.GetSizeOf());
+    EXPECT_EQ(0u, buf);
+  }
+
+  {
+    // Test copying when `bv.storage_` and `buf` are of equal lengths.
+    BitVector bv(0, true, Allocator::GetMallocAllocator());
+    uint32_t buf;
+
+    bv.SetBit(0);
+    bv.SetBit(17);
+    bv.SetBit(26);
+    EXPECT_EQ(sizeof(buf), bv.GetSizeOf());
+
+    bv.CopyTo(&buf, sizeof(buf));
+    EXPECT_EQ(0x04020001u, buf);
+  }
+
+  {
+    // Test copying when the `bv.storage_` is longer than `buf`. As long as
+    // `buf` is long enough to hold all set bits, copying should succeed.
+    BitVector bv(0, true, Allocator::GetMallocAllocator());
+    uint8_t buf[5];
+
+    bv.SetBit(18);
+    bv.SetBit(39);
+    EXPECT_LT(sizeof(buf), bv.GetSizeOf());
+
+    bv.CopyTo(buf, sizeof(buf));
+    EXPECT_EQ(0x00u, buf[0]);
+    EXPECT_EQ(0x00u, buf[1]);
+    EXPECT_EQ(0x04u, buf[2]);
+    EXPECT_EQ(0x00u, buf[3]);
+    EXPECT_EQ(0x80u, buf[4]);
+  }
+
+  {
+    // Test zero padding when `bv.storage_` is shorter than `buf`.
+    BitVector bv(0, true, Allocator::GetMallocAllocator());
+    uint32_t buf[2];
+
+    bv.SetBit(18);
+    bv.SetBit(31);
+    EXPECT_GT(sizeof(buf), bv.GetSizeOf());
+
+    bv.CopyTo(buf, sizeof(buf));
+    EXPECT_EQ(0x80040000U, buf[0]);
+    EXPECT_EQ(0x00000000U, buf[1]);
+  }
+}
+
 }  // namespace art
diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h
index 8daf6d4..f2c8355 100644
--- a/runtime/base/hash_set.h
+++ b/runtime/base/hash_set.h
@@ -469,8 +469,6 @@
     }
     // Resize based on the minimum load factor.
     Resize(min_index);
-    // When we hit elements_until_expand_, we are at the max load factor and must expand again.
-    elements_until_expand_ = NumBuckets() * max_load_factor_;
   }
 
   // Expand / shrink the table to the new specified size.
@@ -493,11 +491,18 @@
     if (owned_data) {
       allocfn_.deallocate(old_data, old_num_buckets);
     }
+
+    // When we hit elements_until_expand_, we are at the max load factor and must expand again.
+    elements_until_expand_ = NumBuckets() * max_load_factor_;
   }
 
   ALWAYS_INLINE size_t FirstAvailableSlot(size_t index) const {
+    DCHECK_LT(index, NumBuckets());  // Don't try to get a slot out of range.
+    size_t non_empty_count = 0;
     while (!emptyfn_.IsEmpty(data_[index])) {
       index = NextIndex(index);
+      non_empty_count++;
+      DCHECK_LE(non_empty_count, NumBuckets());  // Don't loop forever.
     }
     return index;
   }
@@ -526,7 +531,7 @@
   Pred pred_;  // Equals function.
   size_t num_elements_;  // Number of inserted elements.
   size_t num_buckets_;  // Number of hash table buckets.
-  size_t elements_until_expand_;  // Maxmimum number of elements until we expand the table.
+  size_t elements_until_expand_;  // Maximum number of elements until we expand the table.
   bool owns_data_;  // If we own data_ and are responsible for freeing it.
   T* data_;  // Backing storage.
   double min_load_factor_;
diff --git a/runtime/base/hash_set_test.cc b/runtime/base/hash_set_test.cc
index e88637f..fd9eb45 100644
--- a/runtime/base/hash_set_test.cc
+++ b/runtime/base/hash_set_test.cc
@@ -156,6 +156,38 @@
   }
 }
 
+TEST_F(HashSetTest, TestShrink) {
+  HashSet<std::string, IsEmptyFnString> hash_set;
+  std::vector<std::string> strings = {"a", "b", "c", "d", "e", "f", "g"};
+  for (size_t i = 0; i < strings.size(); ++i) {
+    // Insert some strings into the beginning of our hash set to establish an initial size
+    hash_set.Insert(strings[i]);
+  }
+
+  hash_set.ShrinkToMaximumLoad();
+  const double initial_load = hash_set.CalculateLoadFactor();
+
+  // Insert a bunch of random strings to guarantee that we grow the capacity.
+  std::vector<std::string> random_strings;
+  static constexpr size_t count = 1000;
+  for (size_t i = 0; i < count; ++i) {
+    random_strings.push_back(RandomString(10));
+    hash_set.Insert(random_strings[i]);
+  }
+
+  // Erase all the extra strings which guarantees that our load factor will be really bad.
+  for (size_t i = 0; i < count; ++i) {
+    hash_set.Erase(hash_set.Find(random_strings[i]));
+  }
+
+  const double bad_load = hash_set.CalculateLoadFactor();
+  EXPECT_GT(initial_load, bad_load);
+
+  // Shrink again, the load factor should be good again.
+  hash_set.ShrinkToMaximumLoad();
+  EXPECT_DOUBLE_EQ(initial_load, hash_set.CalculateLoadFactor());
+}
+
 TEST_F(HashSetTest, TestStress) {
   HashSet<std::string, IsEmptyFnString> hash_set;
   std::unordered_multiset<std::string> std_set;
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 0ae7863..859de4b 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -289,17 +289,17 @@
   CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
 
   const char* program_name = ProgramInvocationShortName();
-  write(STDERR_FILENO, program_name, strlen(program_name));
-  write(STDERR_FILENO, " ", 1);
-  write(STDERR_FILENO, &log_characters[log_severity], 1);
-  write(STDERR_FILENO, " ", 1);
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, program_name, strlen(program_name)));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, &log_characters[log_severity], 1));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, " ", 1));
   // TODO: pid and tid.
-  write(STDERR_FILENO, file, strlen(file));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, file, strlen(file)));
   // TODO: line.
   UNUSED(line);
-  write(STDERR_FILENO, "] ", 2);
-  write(STDERR_FILENO, message, strlen(message));
-  write(STDERR_FILENO, "\n", 1);
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, "] ", 2));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, message, strlen(message)));
+  TEMP_FAILURE_RETRY(write(STDERR_FILENO, "\n", 1));
 #endif
 }
 
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 8b34374..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"
@@ -39,6 +38,7 @@
 struct LogVerbosity {
   bool class_linker;  // Enabled with "-verbose:class".
   bool compiler;
+  bool deopt;
   bool gc;
   bool heap;
   bool jdwp;
diff --git a/runtime/base/unix_file/random_access_file_test.h b/runtime/base/unix_file/random_access_file_test.h
index e7ace4c..91858c2 100644
--- a/runtime/base/unix_file/random_access_file_test.h
+++ b/runtime/base/unix_file/random_access_file_test.h
@@ -82,7 +82,7 @@
 
   void TestReadContent(const std::string& content, RandomAccessFile* file) {
     const int buf_size = content.size() + 10;
-    std::unique_ptr<char> buf(new char[buf_size]);
+    std::unique_ptr<char[]> buf(new char[buf_size]);
     // Can't read from a negative offset.
     ASSERT_EQ(-EINVAL, file->Read(buf.get(), 0, -123));
 
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index d323379..504b753 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -65,17 +65,18 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ArtMethod* m = GetMethod();
     CodeInfo code_info = m->GetOptimizedCodeInfo();
-    StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+    StackMapEncoding encoding = code_info.ExtractEncoding();
+    StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
     uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
     DexRegisterMap dex_register_map =
-        code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-    MemoryRegion stack_mask = stack_map.GetStackMask(code_info);
-    uint32_t register_mask = stack_map.GetRegisterMask(code_info);
+        code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
+    MemoryRegion stack_mask = stack_map.GetStackMask(encoding);
+    uint32_t register_mask = stack_map.GetRegisterMask(encoding);
     for (int i = 0; i < number_of_references; ++i) {
       int reg = registers[i];
       CHECK(reg < m->GetCodeItem()->registers_size_);
-      DexRegisterLocation location =
-          dex_register_map.GetDexRegisterLocation(reg, number_of_dex_registers, code_info);
+      DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(
+          reg, number_of_dex_registers, code_info, encoding);
       switch (location.GetKind()) {
         case DexRegisterLocation::Kind::kNone:
           // Not set, should not be a reference.
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index df6703c..21b63c6 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -41,7 +41,6 @@
       return array_class;
     }
   }
-  DCHECK(!(*element_class)->IsPrimitiveVoid());
   std::string descriptor = "[";
   std::string temp;
   descriptor += (*element_class)->GetDescriptor(&temp);
@@ -49,10 +48,15 @@
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle((*element_class)->GetClassLoader()));
   HandleWrapper<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class));
   mirror::Class* array_class = FindClass(self, descriptor.c_str(), class_loader);
-  // Benign races in storing array class and incrementing index.
-  size_t victim_index = find_array_class_cache_next_victim_;
-  find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
-  find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
+  if (array_class != nullptr) {
+    // Benign races in storing array class and incrementing index.
+    size_t victim_index = find_array_class_cache_next_victim_;
+    find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
+    find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
+  } else {
+    // We should have a NoClassDefFoundError.
+    self->AssertPendingException();
+  }
   return array_class;
 }
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9ca6492..0694227 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1195,13 +1195,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 +2202,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());
@@ -2314,22 +2305,47 @@
     // Class::VisitFieldRoots may miss some fields or methods.
     ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
     // Load static fields.
+    // We allow duplicate definitions of the same field in a class_data_item
+    // but ignore the repeated indexes here, b/21868015.
     ClassDataItemIterator it(dex_file, class_data);
-    const size_t num_sfields = it.NumStaticFields();
-    ArtField* sfields = num_sfields != 0 ? AllocArtFieldArray(self, num_sfields) : nullptr;
-    for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) {
-      CHECK_LT(i, num_sfields);
-      LoadField(it, klass, &sfields[i]);
+    ArtField* sfields =
+        it.NumStaticFields() != 0 ? AllocArtFieldArray(self, it.NumStaticFields()) : nullptr;
+    size_t num_sfields = 0;
+    uint32_t last_field_idx = 0u;
+    for (; it.HasNextStaticField(); it.Next()) {
+      uint32_t field_idx = it.GetMemberIndex();
+      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
+      if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
+        DCHECK_LT(num_sfields, it.NumStaticFields());
+        LoadField(it, klass, &sfields[num_sfields]);
+        ++num_sfields;
+        last_field_idx = field_idx;
+      }
     }
     klass->SetSFields(sfields);
     klass->SetNumStaticFields(num_sfields);
     DCHECK_EQ(klass->NumStaticFields(), num_sfields);
     // Load instance fields.
-    const size_t num_ifields = it.NumInstanceFields();
-    ArtField* ifields = num_ifields != 0 ? AllocArtFieldArray(self, num_ifields) : nullptr;
-    for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) {
-      CHECK_LT(i, num_ifields);
-      LoadField(it, klass, &ifields[i]);
+    ArtField* ifields =
+        it.NumInstanceFields() != 0 ? AllocArtFieldArray(self, it.NumInstanceFields()) : nullptr;
+    size_t num_ifields = 0u;
+    last_field_idx = 0u;
+    for (; it.HasNextInstanceField(); it.Next()) {
+      uint32_t field_idx = it.GetMemberIndex();
+      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
+      if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
+        DCHECK_LT(num_ifields, it.NumInstanceFields());
+        LoadField(it, klass, &ifields[num_ifields]);
+        ++num_ifields;
+        last_field_idx = field_idx;
+      }
+    }
+    if (UNLIKELY(num_sfields != it.NumStaticFields()) ||
+        UNLIKELY(num_ifields != it.NumInstanceFields())) {
+      LOG(WARNING) << "Duplicate fields in class " << PrettyDescriptor(klass.Get())
+          << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields()
+          << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")";
+      // NOTE: Not shrinking the over-allocated sfields/ifields.
     }
     klass->SetIFields(ifields);
     klass->SetNumInstanceFields(num_ifields);
@@ -3491,7 +3507,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 {
@@ -4811,11 +4826,11 @@
           }
           ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
           uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
-          auto*& imt_ref = out_imt[imt_index];
-          if (imt_ref == unimplemented_method) {
-            imt_ref = method;
-          } else if (imt_ref != conflict_method) {
-            imt_ref = conflict_method;
+          auto** imt_ref = &out_imt[imt_index];
+          if (*imt_ref == unimplemented_method) {
+            *imt_ref = method;
+          } else if (*imt_ref != conflict_method) {
+            *imt_ref = conflict_method;
           }
         }
       }
@@ -5017,6 +5032,7 @@
         vtable->SetElementPtrSize(i, new_m, image_pointer_size_);
       }
     }
+
     klass->SetVTable(vtable.Get());
     // Go fix up all the stale miranda pointers.
     for (size_t i = 0; i < ifcount; ++i) {
@@ -5216,7 +5232,7 @@
       ArtField* field = &fields[i];
       VLOG(class_linker) << "LinkFields: " << (is_static ? "static" : "instance")
           << " class=" << PrettyClass(klass.Get()) << " field=" << PrettyField(field) << " offset="
-          << field->GetOffset();
+          << field->GetOffsetDuringLinking();
       if (i != 0) {
         ArtField* const prev_field = &fields[i - 1];
         // NOTE: The field names can be the same. This is not possible in the Java language
@@ -5621,18 +5637,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);
   }
 }
 
@@ -5872,7 +5885,7 @@
   ArtField* const parent_field =
       mirror::Class::FindField(self, hs.NewHandle(h_path_class_loader->GetClass()), "parent",
                                "Ljava/lang/ClassLoader;");
-  DCHECK(parent_field!= nullptr);
+  DCHECK(parent_field != nullptr);
   mirror::Object* boot_cl =
       soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
   parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl);
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/common_runtime_test.h b/runtime/common_runtime_test.h
index 34fdd8d..2332f97 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -174,10 +174,10 @@
   DISALLOW_COPY_AND_ASSIGN(CheckJniAbortCatcher);
 };
 
-// TODO: When heap reference poisoning works with the compiler, get rid of this.
-#define TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING() \
-  if (kPoisonHeapReferences) { \
-    printf("WARNING: TEST DISABLED FOR HEAP REFERENCE POISONING\n"); \
+// TODO: When read barrier works with the compiler, get rid of this.
+#define TEST_DISABLED_FOR_READ_BARRIER() \
+  if (kUseReadBarrier) { \
+    printf("WARNING: TEST DISABLED FOR READ BARRIER\n"); \
     return; \
   }
 
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 546a1fb..97d170e 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -29,6 +29,7 @@
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
 #include "gc/accounting/card_table-inl.h"
+#include "gc/allocation_record.h"
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
 #include "handle_scope.h"
@@ -53,136 +54,20 @@
 #include "verifier/method_verifier-inl.h"
 #include "well_known_classes.h"
 
-#ifdef HAVE_ANDROID_OS
-#include "cutils/properties.h"
-#endif
-
 namespace art {
 
 // The key identifying the debugger to update instrumentation.
 static constexpr const char* kDbgInstrumentationKey = "Debugger";
 
-static const size_t kMaxAllocRecordStackDepth = 16;  // Max 255.
-static const size_t kDefaultNumAllocRecords = 64*1024;  // Must be a power of 2. 2BE can hold 64k-1.
-
-// Limit alloc_record_count to the 2BE value that is the limit of the current protocol.
+// Limit alloc_record_count to the 2BE value (64k-1) that is the limit of the current protocol.
 static uint16_t CappedAllocRecordCount(size_t alloc_record_count) {
-  if (alloc_record_count > 0xffff) {
-    return 0xffff;
+  const size_t cap = 0xffff;
+  if (alloc_record_count > cap) {
+    return cap;
   }
   return alloc_record_count;
 }
 
-class AllocRecordStackTraceElement {
- public:
-  AllocRecordStackTraceElement() : method_(nullptr), dex_pc_(0) {
-  }
-
-  int32_t LineNumber() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ArtMethod* method = Method();
-    DCHECK(method != nullptr);
-    return method->GetLineNumFromDexPC(DexPc());
-  }
-
-  ArtMethod* Method() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ScopedObjectAccessUnchecked soa(Thread::Current());
-    return soa.DecodeMethod(method_);
-  }
-
-  void SetMethod(ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ScopedObjectAccessUnchecked soa(Thread::Current());
-    method_ = soa.EncodeMethod(m);
-  }
-
-  uint32_t DexPc() const {
-    return dex_pc_;
-  }
-
-  void SetDexPc(uint32_t pc) {
-    dex_pc_ = pc;
-  }
-
- private:
-  jmethodID method_;
-  uint32_t dex_pc_;
-};
-
-jobject Dbg::TypeCache::Add(mirror::Class* t) {
-  ScopedObjectAccessUnchecked soa(Thread::Current());
-  JNIEnv* const env = soa.Env();
-  ScopedLocalRef<jobject> local_ref(soa.Env(), soa.AddLocalReference<jobject>(t));
-  const int32_t hash_code = soa.Decode<mirror::Class*>(local_ref.get())->IdentityHashCode();
-  auto range = objects_.equal_range(hash_code);
-  for (auto it = range.first; it != range.second; ++it) {
-    if (soa.Decode<mirror::Class*>(it->second) == soa.Decode<mirror::Class*>(local_ref.get())) {
-      // Found a matching weak global, return it.
-      return it->second;
-    }
-  }
-  const jobject weak_global = env->NewWeakGlobalRef(local_ref.get());
-  objects_.insert(std::make_pair(hash_code, weak_global));
-  return weak_global;
-}
-
-void Dbg::TypeCache::Clear() {
-  JavaVMExt* vm = Runtime::Current()->GetJavaVM();
-  Thread* self = Thread::Current();
-  for (const auto& p : objects_) {
-    vm->DeleteWeakGlobalRef(self, p.second);
-  }
-  objects_.clear();
-}
-
-class AllocRecord {
- public:
-  AllocRecord() : type_(nullptr), byte_count_(0), thin_lock_id_(0) {}
-
-  mirror::Class* Type() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return down_cast<mirror::Class*>(Thread::Current()->DecodeJObject(type_));
-  }
-
-  void SetType(mirror::Class* t) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
-                                                       Locks::alloc_tracker_lock_) {
-    type_ = Dbg::type_cache_.Add(t);
-  }
-
-  size_t GetDepth() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    size_t depth = 0;
-    while (depth < kMaxAllocRecordStackDepth && stack_[depth].Method() != nullptr) {
-      ++depth;
-    }
-    return depth;
-  }
-
-  size_t ByteCount() const {
-    return byte_count_;
-  }
-
-  void SetByteCount(size_t count) {
-    byte_count_ = count;
-  }
-
-  uint16_t ThinLockId() const {
-    return thin_lock_id_;
-  }
-
-  void SetThinLockId(uint16_t id) {
-    thin_lock_id_ = id;
-  }
-
-  AllocRecordStackTraceElement* StackElement(size_t index) {
-    DCHECK_LT(index, kMaxAllocRecordStackDepth);
-    return &stack_[index];
-  }
-
- private:
-  jobject type_;  // This is a weak global.
-  size_t byte_count_;
-  uint16_t thin_lock_id_;
-  // Unused entries have null method.
-  AllocRecordStackTraceElement stack_[kMaxAllocRecordStackDepth];
-};
-
 class Breakpoint {
  public:
   Breakpoint(ArtMethod* method, uint32_t dex_pc,
@@ -383,13 +268,6 @@
 bool Dbg::gDisposed = false;
 ObjectRegistry* Dbg::gRegistry = nullptr;
 
-// Recent allocation tracking.
-AllocRecord* Dbg::recent_allocation_records_ = nullptr;  // TODO: CircularBuffer<AllocRecord>
-size_t Dbg::alloc_record_max_ = 0;
-size_t Dbg::alloc_record_head_ = 0;
-size_t Dbg::alloc_record_count_ = 0;
-Dbg::TypeCache Dbg::type_cache_;
-
 // Deoptimization support.
 std::vector<DeoptimizationRequest> Dbg::deoptimization_requests_;
 size_t Dbg::full_deoptimization_event_count_ = 0;
@@ -4045,7 +3923,7 @@
              << " arg_count=" << pReq->arg_count;
   CHECK(m != nullptr);
 
-  CHECK_EQ(sizeof(jvalue), sizeof(uint64_t));
+  static_assert(sizeof(jvalue) == sizeof(uint64_t), "jvalue and uint64_t have different sizes.");
 
   // Invoke the method.
   ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(pReq->receiver.Read()));
@@ -4814,177 +4692,41 @@
   Dbg::DdmSendChunk(native ? CHUNK_TYPE("NHEN") : CHUNK_TYPE("HPEN"), sizeof(heap_id), heap_id);
 }
 
-static size_t GetAllocTrackerMax() {
-#ifdef HAVE_ANDROID_OS
-  // Check whether there's a system property overriding the number of records.
-  const char* propertyName = "dalvik.vm.allocTrackerMax";
-  char allocRecordMaxString[PROPERTY_VALUE_MAX];
-  if (property_get(propertyName, allocRecordMaxString, "") > 0) {
-    char* end;
-    size_t value = strtoul(allocRecordMaxString, &end, 10);
-    if (*end != '\0') {
-      LOG(ERROR) << "Ignoring  " << propertyName << " '" << allocRecordMaxString
-                 << "' --- invalid";
-      return kDefaultNumAllocRecords;
-    }
-    if (!IsPowerOfTwo(value)) {
-      LOG(ERROR) << "Ignoring  " << propertyName << " '" << allocRecordMaxString
-                 << "' --- not power of two";
-      return kDefaultNumAllocRecords;
-    }
-    return value;
-  }
-#endif
-  return kDefaultNumAllocRecords;
-}
-
 void Dbg::SetAllocTrackingEnabled(bool enable) {
-  Thread* self = Thread::Current();
-  if (enable) {
-    {
-      MutexLock mu(self, *Locks::alloc_tracker_lock_);
-      if (recent_allocation_records_ != nullptr) {
-        return;  // Already enabled, bail.
-      }
-      alloc_record_max_ = GetAllocTrackerMax();
-      LOG(INFO) << "Enabling alloc tracker (" << alloc_record_max_ << " entries of "
-                << kMaxAllocRecordStackDepth << " frames, taking "
-                << PrettySize(sizeof(AllocRecord) * alloc_record_max_) << ")";
-      DCHECK_EQ(alloc_record_head_, 0U);
-      DCHECK_EQ(alloc_record_count_, 0U);
-      recent_allocation_records_ = new AllocRecord[alloc_record_max_];
-      CHECK(recent_allocation_records_ != nullptr);
-    }
-    Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
-  } else {
-    {
-      ScopedObjectAccess soa(self);  // For type_cache_.Clear();
-      MutexLock mu(self, *Locks::alloc_tracker_lock_);
-      if (recent_allocation_records_ == nullptr) {
-        return;  // Already disabled, bail.
-      }
-      LOG(INFO) << "Disabling alloc tracker";
-      delete[] recent_allocation_records_;
-      recent_allocation_records_ = nullptr;
-      alloc_record_head_ = 0;
-      alloc_record_count_ = 0;
-      type_cache_.Clear();
-    }
-    // If an allocation comes in before we uninstrument, we will safely drop it on the floor.
-    Runtime::Current()->GetInstrumentation()->UninstrumentQuickAllocEntryPoints();
-  }
-}
-
-struct AllocRecordStackVisitor : public StackVisitor {
-  AllocRecordStackVisitor(Thread* thread, AllocRecord* record_in)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
-        record(record_in),
-        depth(0) {}
-
-  // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
-  // annotalysis.
-  bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
-    if (depth >= kMaxAllocRecordStackDepth) {
-      return false;
-    }
-    ArtMethod* m = GetMethod();
-    if (!m->IsRuntimeMethod()) {
-      record->StackElement(depth)->SetMethod(m);
-      record->StackElement(depth)->SetDexPc(GetDexPc());
-      ++depth;
-    }
-    return true;
-  }
-
-  ~AllocRecordStackVisitor() {
-    // Clear out any unused stack trace elements.
-    for (; depth < kMaxAllocRecordStackDepth; ++depth) {
-      record->StackElement(depth)->SetMethod(nullptr);
-      record->StackElement(depth)->SetDexPc(0);
-    }
-  }
-
-  AllocRecord* record;
-  size_t depth;
-};
-
-void Dbg::RecordAllocation(Thread* self, mirror::Class* type, size_t byte_count) {
-  MutexLock mu(self, *Locks::alloc_tracker_lock_);
-  if (recent_allocation_records_ == nullptr) {
-    // In the process of shutting down recording, bail.
-    return;
-  }
-
-  // Advance and clip.
-  if (++alloc_record_head_ == alloc_record_max_) {
-    alloc_record_head_ = 0;
-  }
-
-  // Fill in the basics.
-  AllocRecord* record = &recent_allocation_records_[alloc_record_head_];
-  record->SetType(type);
-  record->SetByteCount(byte_count);
-  record->SetThinLockId(self->GetThreadId());
-
-  // Fill in the stack trace.
-  AllocRecordStackVisitor visitor(self, record);
-  visitor.WalkStack();
-
-  if (alloc_record_count_ < alloc_record_max_) {
-    ++alloc_record_count_;
-  }
-}
-
-// Returns the index of the head element.
-//
-// We point at the most-recently-written record, so if alloc_record_count_ is 1
-// we want to use the current element.  Take "head+1" and subtract count
-// from it.
-//
-// We need to handle underflow in our circular buffer, so we add
-// alloc_record_max_ and then mask it back down.
-size_t Dbg::HeadIndex() {
-  return (Dbg::alloc_record_head_ + 1 + Dbg::alloc_record_max_ - Dbg::alloc_record_count_) &
-      (Dbg::alloc_record_max_ - 1);
+  gc::AllocRecordObjectMap::SetAllocTrackingEnabled(enable);
 }
 
 void Dbg::DumpRecentAllocations() {
   ScopedObjectAccess soa(Thread::Current());
   MutexLock mu(soa.Self(), *Locks::alloc_tracker_lock_);
-  if (recent_allocation_records_ == nullptr) {
+  if (!Runtime::Current()->GetHeap()->IsAllocTrackingEnabled()) {
     LOG(INFO) << "Not recording tracked allocations";
     return;
   }
+  gc::AllocRecordObjectMap* records = Runtime::Current()->GetHeap()->GetAllocationRecords();
+  CHECK(records != nullptr);
 
-  // "i" is the head of the list.  We want to start at the end of the
-  // list and move forward to the tail.
-  size_t i = HeadIndex();
-  const uint16_t capped_count = CappedAllocRecordCount(Dbg::alloc_record_count_);
+  const uint16_t capped_count = CappedAllocRecordCount(records->GetRecentAllocationSize());
   uint16_t count = capped_count;
 
-  LOG(INFO) << "Tracked allocations, (head=" << alloc_record_head_ << " count=" << count << ")";
-  while (count--) {
-    AllocRecord* record = &recent_allocation_records_[i];
+  LOG(INFO) << "Tracked allocations, (count=" << count << ")";
+  for (auto it = records->RBegin(), end = records->REnd();
+      count > 0 && it != end; count--, it++) {
+    const gc::AllocRecord* record = it->second;
 
-    LOG(INFO) << StringPrintf(" Thread %-2d %6zd bytes ", record->ThinLockId(), record->ByteCount())
-              << PrettyClass(record->Type());
+    LOG(INFO) << StringPrintf(" Thread %-2d %6zd bytes ", record->GetTid(), record->ByteCount())
+              << PrettyClass(record->GetClass());
 
-    for (size_t stack_frame = 0; stack_frame < kMaxAllocRecordStackDepth; ++stack_frame) {
-      AllocRecordStackTraceElement* stack_element = record->StackElement(stack_frame);
-      ArtMethod* m = stack_element->Method();
-      if (m == nullptr) {
-        break;
-      }
-      LOG(INFO) << "    " << PrettyMethod(m) << " line " << stack_element->LineNumber();
+    for (size_t stack_frame = 0, depth = record->GetDepth(); stack_frame < depth; ++stack_frame) {
+      const gc::AllocRecordStackTraceElement& stack_element = record->StackElement(stack_frame);
+      ArtMethod* m = stack_element.GetMethod();
+      LOG(INFO) << "    " << PrettyMethod(m) << " line " << stack_element.ComputeLineNumber();
     }
 
     // pause periodically to help logcat catch up
     if ((count % 5) == 0) {
       usleep(40000);
     }
-
-    i = (i + 1) & (alloc_record_max_ - 1);
   }
 }
 
@@ -5086,6 +4828,18 @@
   std::vector<uint8_t> bytes;
   {
     MutexLock mu(self, *Locks::alloc_tracker_lock_);
+    gc::AllocRecordObjectMap* records = Runtime::Current()->GetHeap()->GetAllocationRecords();
+    // In case this method is called when allocation tracker is disabled,
+    // we should still send some data back.
+    gc::AllocRecordObjectMap dummy;
+    if (records == nullptr) {
+      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.
     //
@@ -5093,26 +4847,23 @@
     StringTable method_names;
     StringTable filenames;
 
-    const uint16_t capped_count = CappedAllocRecordCount(Dbg::alloc_record_count_);
+    const uint16_t capped_count = CappedAllocRecordCount(records->GetRecentAllocationSize());
     uint16_t count = capped_count;
-    size_t idx = HeadIndex();
-    while (count--) {
-      AllocRecord* record = &recent_allocation_records_[idx];
+    for (auto it = records->RBegin(), end = records->REnd();
+         count > 0 && it != end; count--, it++) {
+      const gc::AllocRecord* record = it->second;
       std::string temp;
-      class_names.Add(record->Type()->GetDescriptor(&temp));
-      for (size_t i = 0; i < kMaxAllocRecordStackDepth; i++) {
-        ArtMethod* m = record->StackElement(i)->Method();
-        if (m != nullptr) {
-          class_names.Add(m->GetDeclaringClassDescriptor());
-          method_names.Add(m->GetName());
-          filenames.Add(GetMethodSourceFile(m));
-        }
+      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());
+        method_names.Add(m->GetName());
+        filenames.Add(GetMethodSourceFile(m));
       }
-
-      idx = (idx + 1) & (alloc_record_max_ - 1);
     }
 
-    LOG(INFO) << "allocation records: " << capped_count;
+    LOG(INFO) << "recent allocation records: " << capped_count;
+    LOG(INFO) << "allocation records all objects: " << records->Size();
 
     //
     // Part 2: Generate the output and store it in the buffer.
@@ -5140,20 +4891,23 @@
     JDWP::Append2BE(bytes, method_names.Size());
     JDWP::Append2BE(bytes, filenames.Size());
 
-    idx = HeadIndex();
     std::string temp;
-    for (count = capped_count; count != 0; --count) {
+    count = capped_count;
+    // The last "count" number of allocation records in "records" are the most recent "count" number
+    // of allocations. Reverse iterate to get them. The most recent allocation is sent first.
+    for (auto it = records->RBegin(), end = records->REnd();
+         count > 0 && it != end; count--, it++) {
       // For each entry:
       // (4b) total allocation size
       // (2b) thread id
       // (2b) allocated object's class name index
       // (1b) stack depth
-      AllocRecord* record = &recent_allocation_records_[idx];
+      const gc::AllocRecord* record = it->second;
       size_t stack_depth = record->GetDepth();
       size_t allocated_object_class_name_index =
-          class_names.IndexOf(record->Type()->GetDescriptor(&temp));
+          class_names.IndexOf(record->GetClassDescriptor(&temp));
       JDWP::Append4BE(bytes, record->ByteCount());
-      JDWP::Append2BE(bytes, record->ThinLockId());
+      JDWP::Append2BE(bytes, static_cast<uint16_t>(record->GetTid()));
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
       JDWP::Append1BE(bytes, stack_depth);
 
@@ -5163,16 +4917,15 @@
         // (2b) method name
         // (2b) method source file
         // (2b) line number, clipped to 32767; -2 if native; -1 if no source
-        ArtMethod* m = record->StackElement(stack_frame)->Method();
+        ArtMethod* m = record->StackElement(stack_frame).GetMethod();
         size_t class_name_index = class_names.IndexOf(m->GetDeclaringClassDescriptor());
         size_t method_name_index = method_names.IndexOf(m->GetName());
         size_t file_name_index = filenames.IndexOf(GetMethodSourceFile(m));
         JDWP::Append2BE(bytes, class_name_index);
         JDWP::Append2BE(bytes, method_name_index);
         JDWP::Append2BE(bytes, file_name_index);
-        JDWP::Append2BE(bytes, record->StackElement(stack_frame)->LineNumber());
+        JDWP::Append2BE(bytes, record->StackElement(stack_frame).ComputeLineNumber());
       }
-      idx = (idx + 1) & (alloc_record_max_ - 1);
     }
 
     // (xb) class name strings
diff --git a/runtime/debugger.h b/runtime/debugger.h
index e40f10f..fd7d46c 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -23,7 +23,6 @@
 
 #include <pthread.h>
 
-#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -32,7 +31,6 @@
 #include "jdwp/jdwp.h"
 #include "jni.h"
 #include "jvalue.h"
-#include "object_callbacks.h"
 #include "thread_state.h"
 
 namespace art {
@@ -41,7 +39,6 @@
 class Object;
 class Throwable;
 }  // namespace mirror
-class AllocRecord;
 class ArtField;
 class ArtMethod;
 class ObjectRegistry;
@@ -202,19 +199,6 @@
 
 class Dbg {
  public:
-  class TypeCache {
-   public:
-    // Returns a weak global for the input type. Deduplicates.
-    jobject Add(mirror::Class* t) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
-                                                        Locks::alloc_tracker_lock_);
-    // Clears the type cache and deletes all the weak global refs.
-    void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
-                                       Locks::alloc_tracker_lock_);
-
-   private:
-    std::multimap<int32_t, jobject> objects_;
-  };
-
   static void SetJdwpAllowed(bool allowed);
 
   static void StartJdwp();
@@ -675,19 +659,12 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   /*
-   * Recent allocation tracking support.
+   * Allocation tracking support.
    */
-  static void RecordAllocation(Thread* self, mirror::Class* type, size_t byte_count)
-      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void SetAllocTrackingEnabled(bool enabled) LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
-  static bool IsAllocTrackingEnabled() {
-    return recent_allocation_records_ != nullptr;
-  }
   static jbyteArray GetRecentAllocations()
       LOCKS_EXCLUDED(Locks::alloc_tracker_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static size_t HeadIndex() EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
   static void DumpRecentAllocations() LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
 
   enum HpifWhen {
@@ -783,11 +760,6 @@
   static bool IsForcedInterpreterNeededForUpcallImpl(Thread* thread, ArtMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static AllocRecord* recent_allocation_records_ PT_GUARDED_BY(Locks::alloc_tracker_lock_);
-  static size_t alloc_record_max_ GUARDED_BY(Locks::alloc_tracker_lock_);
-  static size_t alloc_record_head_ GUARDED_BY(Locks::alloc_tracker_lock_);
-  static size_t alloc_record_count_ GUARDED_BY(Locks::alloc_tracker_lock_);
-
   // Indicates whether the debugger is making requests.
   static bool gDebuggerActive;
 
@@ -812,9 +784,6 @@
 
   static size_t* GetReferenceCounterForEvent(uint32_t instrumentation_event);
 
-  // Weak global type cache, TODO improve this.
-  static TypeCache type_cache_ GUARDED_BY(Locks::alloc_tracker_lock_);
-
   // Instrumentation event reference counters.
   // TODO we could use an array instead of having all these dedicated counters. Instrumentation
   // events are bits of a mask so we could convert them to array index.
@@ -826,7 +795,6 @@
   static size_t exception_catch_event_ref_count_ GUARDED_BY(Locks::deoptimization_lock_);
   static uint32_t instrumentation_events_ GUARDED_BY(Locks::mutator_lock_);
 
-  friend class AllocRecord;  // For type_cache_ with proper annotalysis.
   DISALLOW_COPY_AND_ASSIGN(Dbg);
 };
 
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 25d5ef4..d30fac4 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -906,9 +906,9 @@
 
           local_in_reg[reg].name_ = StringDataByIdx(name_idx);
           local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx);
-          if (opcode == DBG_START_LOCAL_EXTENDED) {
-            local_in_reg[reg].signature_ = StringDataByIdx(signature_idx);
-          }
+          local_in_reg[reg].signature_ =
+              (opcode == DBG_START_LOCAL_EXTENDED) ? StringDataByIdx(signature_idx)
+                                                   : nullptr;
           local_in_reg[reg].start_address_ = address;
           local_in_reg[reg].is_live_ = true;
         }
@@ -1113,9 +1113,8 @@
 void ClassDataItemIterator::ReadClassDataField() {
   field_.field_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_);
   field_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
-  if (last_idx_ != 0 && field_.field_idx_delta_ == 0) {
-    LOG(WARNING) << "Duplicate field in " << dex_file_.GetLocation();
-  }
+  // The user of the iterator is responsible for checking if there
+  // are unordered or duplicate indexes.
 }
 
 void ClassDataItemIterator::ReadClassDataMethod() {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index d017601..3a15f1a 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -264,13 +264,18 @@
 
   // Raw code_item.
   struct CodeItem {
-    uint16_t registers_size_;
-    uint16_t ins_size_;
-    uint16_t outs_size_;
-    uint16_t tries_size_;
-    uint32_t debug_info_off_;  // file offset to debug info stream
+    uint16_t registers_size_;            // the number of registers used by this code
+                                         //   (locals + parameters)
+    uint16_t ins_size_;                  // the number of words of incoming arguments to the method
+                                         //   that this code is for
+    uint16_t outs_size_;                 // the number of words of outgoing argument space required
+                                         //   by this code for method invocation
+    uint16_t tries_size_;                // the number of try_items for this instance. If non-zero,
+                                         //   then these appear as the tries array just after the
+                                         //   insns in this instance.
+    uint32_t debug_info_off_;            // file offset to debug info stream
     uint32_t insns_size_in_code_units_;  // size of the insns array, in 2 byte code units
-    uint16_t insns_[1];
+    uint16_t insns_[1];                  // actual array of bytecode.
 
    private:
     DISALLOW_COPY_AND_ASSIGN(CodeItem);
@@ -781,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 5d5a7da..90b8fdb 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -465,7 +465,9 @@
 }
 
 bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags,
-                                               uint32_t code_offset, bool expect_direct) {
+                                               uint32_t code_offset,
+                                               std::unordered_set<uint32_t>& direct_method_indexes,
+                                               bool expect_direct) {
   if (!CheckIndex(idx, header_->method_ids_size_, "class_data_item method_idx")) {
     return false;
   }
@@ -480,6 +482,13 @@
     return false;
   }
 
+  if (expect_direct) {
+    direct_method_indexes.insert(idx);
+  } else if (direct_method_indexes.find(idx) != direct_method_indexes.end()) {
+    ErrorStringPrintf("Found virtual method with same index as direct method: %d", idx);
+    return false;
+  }
+
   constexpr uint32_t access_method_mask = kAccJavaFlagsMask | kAccConstructor |
       kAccDeclaredSynchronized;
   if (UNLIKELY(((access_flags & ~access_method_mask) != 0) ||
@@ -682,6 +691,7 @@
 
 bool DexFileVerifier::CheckIntraClassDataItem() {
   ClassDataItemIterator it(*dex_file_, ptr_);
+  std::unordered_set<uint32_t> direct_method_indexes;
 
   // These calls use the raw access flags to check whether the whole dex field is valid.
   uint32_t prev_index = 0;
@@ -717,7 +727,7 @@
     }
     prev_index = curr_index;
     if (!CheckClassDataItemMethod(curr_index, it.GetRawMemberAccessFlags(),
-        it.GetMethodCodeItemOffset(), true)) {
+        it.GetMethodCodeItemOffset(), direct_method_indexes, true)) {
       return false;
     }
   }
@@ -730,7 +740,7 @@
     }
     prev_index = curr_index;
     if (!CheckClassDataItemMethod(curr_index, it.GetRawMemberAccessFlags(),
-        it.GetMethodCodeItemOffset(), false)) {
+        it.GetMethodCodeItemOffset(), direct_method_indexes, false)) {
       return false;
     }
   }
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 877dfc2..ccc40d4 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -59,6 +59,7 @@
                                  uint32_t* handler_offsets, uint32_t handlers_size);
   bool CheckClassDataItemField(uint32_t idx, uint32_t access_flags, bool expect_static);
   bool CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags, uint32_t code_offset,
+                                std::unordered_set<uint32_t>& direct_method_indexes,
                                 bool expect_direct);
   bool CheckPadding(size_t offset, uint32_t aligned_offset);
   bool CheckEncodedValue();
diff --git a/runtime/dex_instruction-inl.h b/runtime/dex_instruction-inl.h
index dd65f2c..7344d13 100644
--- a/runtime/dex_instruction-inl.h
+++ b/runtime/dex_instruction-inl.h
@@ -223,6 +223,7 @@
     case k22t: return true;
     case k22x: return true;
     case k23x: return true;
+    case k25x: return true;
     case k31c: return true;
     case k31i: return true;
     case k31t: return true;
@@ -252,6 +253,7 @@
     case k22t: return VRegB_22t();
     case k22x: return VRegB_22x();
     case k23x: return VRegB_23x();
+    case k25x: return VRegB_25x();
     case k31c: return VRegB_31c();
     case k31i: return VRegB_31i();
     case k31t: return VRegB_31t();
@@ -329,6 +331,12 @@
   return static_cast<uint8_t>(Fetch16(1) & 0xff);
 }
 
+// Number of additional registers in this instruction. # of var arg registers = this value + 1.
+inline uint4_t Instruction::VRegB_25x() const {
+  DCHECK_EQ(FormatOf(Opcode()), k25x);
+  return InstB(Fetch16(0));
+}
+
 inline uint32_t Instruction::VRegB_31c() const {
   DCHECK_EQ(FormatOf(Opcode()), k31c);
   return Fetch32(1);
@@ -375,6 +383,7 @@
     case k22s: return true;
     case k22t: return true;
     case k23x: return true;
+    case k25x: return true;
     case k35c: return true;
     case k3rc: return true;
     default: return false;
@@ -388,6 +397,7 @@
     case k22s: return VRegC_22s();
     case k22t: return VRegC_22t();
     case k23x: return VRegC_23x();
+    case k25x: return VRegC_25x();
     case k35c: return VRegC_35c();
     case k3rc: return VRegC_3rc();
     default:
@@ -421,6 +431,11 @@
   return static_cast<uint8_t>(Fetch16(1) >> 8);
 }
 
+inline uint4_t Instruction::VRegC_25x() const {
+  DCHECK_EQ(FormatOf(Opcode()), k25x);
+  return static_cast<uint4_t>(Fetch16(1) & 0xf);
+}
+
 inline uint4_t Instruction::VRegC_35c() const {
   DCHECK_EQ(FormatOf(Opcode()), k35c);
   return static_cast<uint4_t>(Fetch16(2) & 0x0f);
@@ -431,11 +446,78 @@
   return Fetch16(2);
 }
 
-inline bool Instruction::HasVarArgs() const {
+inline bool Instruction::HasVarArgs35c() const {
   return FormatOf(Opcode()) == k35c;
 }
 
-inline void Instruction::GetVarArgs(uint32_t arg[5], uint16_t inst_data) const {
+inline bool Instruction::HasVarArgs25x() const {
+  return FormatOf(Opcode()) == k25x;
+}
+
+// Copies all of the parameter registers into the arg array. Check the length with VRegB_25x()+1.
+inline void Instruction::GetAllArgs25x(uint32_t arg[kMaxVarArgRegs]) const {
+  DCHECK_EQ(FormatOf(Opcode()), k25x);
+
+  /*
+   * The opcode looks like this:
+   *   op vC, {vD, vE, vF, vG}
+   *
+   *  and vB is the (implicit) register count (0-4) which denotes how far from vD to vG to read.
+   *
+   *  vC is always present, so with "op vC, {}" the register count will be 0 even though vC
+   *  is valid.
+   *
+   *  The exact semantic meanings of vC:vG is up to the instruction using the format.
+   *
+   *  Encoding drawing as a bit stream:
+   *  (Note that each uint16 is little endian, and each register takes up 4 bits)
+   *
+   *       uint16  |||   uint16
+   *   7-0     15-8    7-0   15-8
+   *  |------|-----|||-----|-----|
+   *  |opcode|vB|vG|||vD|vC|vF|vE|
+   *  |------|-----|||-----|-----|
+   */
+  uint16_t reg_list = Fetch16(1);
+  uint4_t count = VRegB_25x();
+  DCHECK_LE(count, 4U) << "Invalid arg count in 25x (" << count << ")";
+
+  /*
+   * TODO(iam): Change instruction encoding to one of:
+   *
+   * - (X) vA = args count, vB = closure register, {vC..vG} = args (25x)
+   * - (Y) vA = args count, vB = method index, {vC..vG} = args (35x)
+   *
+   * (do this in conjunction with adding verifier support for invoke-lambda)
+   */
+
+  /*
+   * Copy the argument registers into the arg[] array, and
+   * also copy the first argument into vC. (The
+   * DecodedInstruction structure doesn't have separate
+   * fields for {vD, vE, vF, vG}, so there's no need to make
+   * copies of those.) Note that all cases fall-through.
+   */
+  switch (count) {
+    case 4:
+      arg[4] = (Fetch16(0) >> 8) & 0x0f;  // vG
+      FALLTHROUGH_INTENDED;
+    case 3:
+      arg[3] = (reg_list >> 12) & 0x0f;  // vF
+      FALLTHROUGH_INTENDED;
+    case 2:
+      arg[2] = (reg_list >> 8) & 0x0f;  // vE
+      FALLTHROUGH_INTENDED;
+    case 1:
+      arg[1] = (reg_list >> 4) & 0x0f;  // vD
+      FALLTHROUGH_INTENDED;
+    default:  // case 0
+      arg[0] = VRegC_25x();  // vC
+      break;
+  }
+}
+
+inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const {
   DCHECK_EQ(FormatOf(Opcode()), k35c);
 
   /*
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index 69fe874..fc4df14 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -43,6 +43,14 @@
 #undef INSTRUCTION_FORMAT
 };
 
+Instruction::IndexType const Instruction::kInstructionIndexTypes[] = {
+#define INSTRUCTION_INDEX_TYPE(o, c, p, f, r, index, a, v) index,
+#include "dex_instruction_list.h"
+  DEX_INSTRUCTION_LIST(INSTRUCTION_INDEX_TYPE)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_FLAGS
+};
+
 int const Instruction::kInstructionFlags[] = {
 #define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags,
 #include "dex_instruction_list.h"
@@ -63,7 +71,7 @@
 #define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \
     ((opcode == NOP)                        ? -1 : \
      ((format >= k10x) && (format <= k10t)) ?  1 : \
-     ((format >= k20t) && (format <= k22c)) ?  2 : \
+     ((format >= k20t) && (format <= k25x)) ?  2 : \
      ((format >= k32x) && (format <= k3rc)) ?  3 : \
       (format == k51l)                      ?  5 : -1),
 #include "dex_instruction_list.h"
@@ -224,6 +232,14 @@
             break;
           }
           FALLTHROUGH_INTENDED;
+        case CREATE_LAMBDA:
+          if (file != nullptr) {
+            uint32_t method_idx = VRegB_21c();
+            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyMethod(method_idx, *file, true)
+               << " // method@" << method_idx;
+            break;
+          }
+          FALLTHROUGH_INTENDED;
         default:
           os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
           break;
@@ -304,6 +320,26 @@
       }
       break;
     }
+    case k25x: {
+      if (Opcode() == INVOKE_LAMBDA) {
+        uint32_t arg[kMaxVarArgRegs];
+        GetAllArgs25x(arg);
+        const size_t num_extra_var_args = VRegB_25x();
+        DCHECK_LE(num_extra_var_args + 1, kMaxVarArgRegs);
+
+        // invoke-lambda vC, {vD, vE, vF, vG}
+        os << opcode << " v" << arg[0] << ", {";
+        for (size_t i = 0; i < num_extra_var_args; ++i) {
+          if (i != 0) {
+            os << ", ";
+          }
+          os << "v" << arg[i+1];
+        }
+        os << "}";
+        break;
+      }
+      FALLTHROUGH_INTENDED;
+    }
     case k32x:  os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
     case k30t:  os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
     case k31t:  os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index c64c21e..0ddbf7c 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -105,6 +105,7 @@
     k22t,  // op vA, vB, +CCCC
     k22s,  // op vA, vB, #+CCCC
     k22c,  // op vA, vB, thing@CCCC
+    k25x,  // op vC, {vD, vE, vF, vG} (B: count)
     k32x,  // op vAAAA, vBBBB
     k30t,  // op +AAAAAAAA
     k31t,  // op vAA, +BBBBBBBB
@@ -115,31 +116,43 @@
     k51l,  // op vAA, #+BBBBBBBBBBBBBBBB
   };
 
+  enum IndexType {
+    kIndexUnknown = 0,
+    kIndexNone,          // has no index
+    kIndexTypeRef,       // type reference index
+    kIndexStringRef,     // string reference index
+    kIndexMethodRef,     // method reference index
+    kIndexFieldRef,      // field reference index
+    kIndexFieldOffset,   // field offset (for static linked fields)
+    kIndexVtableOffset   // vtable offset (for static linked methods)
+  };
+
   enum Flags {
-    kBranch              = 0x000001,  // conditional or unconditional branch
-    kContinue            = 0x000002,  // flow can continue to next statement
-    kSwitch              = 0x000004,  // switch statement
-    kThrow               = 0x000008,  // could cause an exception to be thrown
-    kReturn              = 0x000010,  // returns, no additional statements
-    kInvoke              = 0x000020,  // a flavor of invoke
-    kUnconditional       = 0x000040,  // unconditional branch
-    kAdd                 = 0x000080,  // addition
-    kSubtract            = 0x000100,  // subtract
-    kMultiply            = 0x000200,  // multiply
-    kDivide              = 0x000400,  // division
-    kRemainder           = 0x000800,  // remainder
-    kAnd                 = 0x001000,  // and
-    kOr                  = 0x002000,  // or
-    kXor                 = 0x004000,  // xor
-    kShl                 = 0x008000,  // shl
-    kShr                 = 0x010000,  // shr
-    kUshr                = 0x020000,  // ushr
-    kCast                = 0x040000,  // cast
-    kStore               = 0x080000,  // store opcode
-    kLoad                = 0x100000,  // load opcode
-    kClobber             = 0x200000,  // clobbers memory in a big way (not just a write)
-    kRegCFieldOrConstant = 0x400000,  // is the third virtual register a field or literal constant (vC)
-    kRegBFieldOrConstant = 0x800000,  // is the second virtual register a field or literal constant (vB)
+    kBranch              = 0x0000001,  // conditional or unconditional branch
+    kContinue            = 0x0000002,  // flow can continue to next statement
+    kSwitch              = 0x0000004,  // switch statement
+    kThrow               = 0x0000008,  // could cause an exception to be thrown
+    kReturn              = 0x0000010,  // returns, no additional statements
+    kInvoke              = 0x0000020,  // a flavor of invoke
+    kUnconditional       = 0x0000040,  // unconditional branch
+    kAdd                 = 0x0000080,  // addition
+    kSubtract            = 0x0000100,  // subtract
+    kMultiply            = 0x0000200,  // multiply
+    kDivide              = 0x0000400,  // division
+    kRemainder           = 0x0000800,  // remainder
+    kAnd                 = 0x0001000,  // and
+    kOr                  = 0x0002000,  // or
+    kXor                 = 0x0004000,  // xor
+    kShl                 = 0x0008000,  // shl
+    kShr                 = 0x0010000,  // shr
+    kUshr                = 0x0020000,  // ushr
+    kCast                = 0x0040000,  // cast
+    kStore               = 0x0080000,  // store opcode
+    kLoad                = 0x0100000,  // load opcode
+    kClobber             = 0x0200000,  // clobbers memory in a big way (not just a write)
+    kRegCFieldOrConstant = 0x0400000,  // is the third virtual register a field or literal constant (vC)
+    kRegBFieldOrConstant = 0x0800000,  // is the second virtual register a field or literal constant (vB)
+    kExperimental        = 0x1000000,  // is an experimental opcode
   };
 
   enum VerifyFlag {
@@ -205,7 +218,7 @@
 
   // Returns a pointer to the instruction after this 2xx instruction in the stream.
   const Instruction* Next_2xx() const {
-    DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c);
+    DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k25x);
     return RelativeAt(2);
   }
 
@@ -355,6 +368,7 @@
   }
   uint16_t VRegB_22x() const;
   uint8_t VRegB_23x() const;
+  uint4_t VRegB_25x() const;
   uint32_t VRegB_31c() const;
   int32_t VRegB_31i() const;
   int32_t VRegB_31t() const;
@@ -381,15 +395,20 @@
   int16_t VRegC_22s() const;
   int16_t VRegC_22t() const;
   uint8_t VRegC_23x() const;
+  uint4_t VRegC_25x() const;
   uint4_t VRegC_35c() const;
   uint16_t VRegC_3rc() const;
 
   // Fills the given array with the 'arg' array of the instruction.
-  bool HasVarArgs() const;
+  bool HasVarArgs35c() const;
+  bool HasVarArgs25x() const;
+
+  // TODO(iam): Make this name more consistent with GetAllArgs25x by including the opcode format.
   void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
   void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const {
     return GetVarArgs(args, Fetch16(0));
   }
+  void GetAllArgs25x(uint32_t args[kMaxVarArgRegs]) const;
 
   // Returns the opcode field of the instruction. The given "inst_data" parameter must be the first
   // 16 bits of instruction.
@@ -438,6 +457,11 @@
     return kInstructionFormats[opcode];
   }
 
+  // Returns the index type of the given opcode.
+  static IndexType IndexTypeOf(Code opcode) {
+    return kInstructionIndexTypes[opcode];
+  }
+
   // Returns the flags for the given opcode.
   static int FlagsOf(Code opcode) {
     return kInstructionFlags[opcode];
@@ -489,6 +513,11 @@
     return (kInstructionFlags[Opcode()] & kInvoke) != 0;
   }
 
+  // Determine if this instruction is experimental.
+  bool IsExperimental() const {
+    return (kInstructionFlags[Opcode()] & kExperimental) != 0;
+  }
+
   int GetVerifyTypeArgumentA() const {
     return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide));
   }
@@ -570,6 +599,7 @@
 
   static const char* const kInstructionNames[];
   static Format const kInstructionFormats[];
+  static IndexType const kInstructionIndexTypes[];
   static int const kInstructionFlags[];
   static int const kInstructionVerifyFlags[];
   static int const kInstructionSizeInCodeUnits[];
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index f8f85f9..a176772 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -18,262 +18,263 @@
 #define ART_RUNTIME_DEX_INSTRUCTION_LIST_H_
 
 #define DEX_INSTRUCTION_LIST(V) \
-  V(0x00, NOP, "nop", k10x, false, kNone, kContinue, kVerifyNone) \
-  V(0x01, MOVE, "move", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x02, MOVE_FROM16, "move/from16", k22x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x03, MOVE_16, "move/16", k32x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x04, MOVE_WIDE, "move-wide", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x07, MOVE_OBJECT, "move-object", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x0A, MOVE_RESULT, "move-result", k11x, true, kNone, kContinue, kVerifyRegA) \
-  V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, true, kNone, kContinue, kVerifyRegAWide) \
-  V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, true, kNone, kContinue, kVerifyRegA) \
-  V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, true, kNone, kContinue, kVerifyRegA) \
-  V(0x0E, RETURN_VOID, "return-void", k10x, false, kNone, kReturn, kVerifyNone) \
-  V(0x0F, RETURN, "return", k11x, false, kNone, kReturn, kVerifyRegA) \
-  V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn, kVerifyRegAWide) \
-  V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn, kVerifyRegA) \
-  V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
-  V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
-  V(0x14, CONST, "const", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
-  V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
-  V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
-  V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
-  V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
-  V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
-  V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
-  V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
-  V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
-  V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \
-  V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \
-  V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
-  V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \
-  V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
-  V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegBNewInstance) \
-  V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \
-  V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArg) \
-  V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArgRange) \
-  V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyArrayData) \
-  V(0x27, THROW, "throw", k11x, false, kNone, kThrow, kVerifyRegA) \
-  V(0x28, GOTO, "goto", k10t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \
-  V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \
-  V(0x2A, GOTO_32, "goto/32", k30t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \
-  V(0x2B, PACKED_SWITCH, "packed-switch", k31t, false, kNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \
-  V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, false, kNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \
-  V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x31, CMP_LONG, "cmp-long", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x32, IF_EQ, "if-eq", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
-  V(0x33, IF_NE, "if-ne", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
-  V(0x34, IF_LT, "if-lt", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
-  V(0x35, IF_GE, "if-ge", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
-  V(0x36, IF_GT, "if-gt", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
-  V(0x37, IF_LE, "if-le", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
-  V(0x38, IF_EQZ, "if-eqz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
-  V(0x39, IF_NEZ, "if-nez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
-  V(0x3A, IF_LTZ, "if-ltz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
-  V(0x3B, IF_GEZ, "if-gez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
-  V(0x3C, IF_GTZ, "if-gtz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
-  V(0x3D, IF_LEZ, "if-lez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
-  V(0x3E, UNUSED_3E, "unused-3e", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x3F, UNUSED_3F, "unused-3f", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x40, UNUSED_40, "unused-40", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
-  V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
-  V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
-  V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
-  V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
-  V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
-  V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
-  V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
-  V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
-  V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
-  V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
-  V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
-  V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
-  V(0x73, RETURN_VOID_NO_BARRIER, "return-void-no-barrier", k10x, false, kNone, kReturn, kVerifyNone) \
-  V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
-  V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
-  V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
-  V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
-  V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
-  V(0x79, UNUSED_79, "unused-79", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x7A, UNUSED_7A, "unused-7a", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0x7B, NEG_INT, "neg-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x7C, NOT_INT, "not-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x7D, NEG_LONG, "neg-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
-  V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
-  V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
-  V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
-  V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
-  V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
-  V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
-  V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
-  V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
-  V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
-  V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
-  V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
-  V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
-  V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
-  V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
-  V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
-  V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
-  V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
-  V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
-  V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \
-  V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \
-  V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \
-  V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB) \
-  V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB) \
-  V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB) \
-  V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB) \
-  V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB) \
-  V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB) \
-  V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB) \
-  V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB) \
-  V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegB) \
-  V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegB) \
-  V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegB) \
-  V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \
-  V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \
-  V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \
-  V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB) \
-  V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB) \
-  V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
-  V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
-  V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgNonZero | kVerifyRuntimeOnly) \
-  V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRangeNonZero | kVerifyRuntimeOnly) \
-  V(0xEB, IPUT_BOOLEAN_QUICK, "iput-boolean-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xEF, IGET_BOOLEAN_QUICK, "iget-boolean-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xF0, IGET_BYTE_QUICK, "iget-byte-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xF1, IGET_CHAR_QUICK, "iget-char-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xF2, IGET_SHORT_QUICK, "iget-short-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xF3, UNUSED_F3, "unused-f3", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF6, UNUSED_F6, "unused-f6", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF7, UNUSED_F7, "unused-f7", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF8, UNUSED_F8, "unused-f8", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xF9, UNUSED_F9, "unused-f9", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xFA, UNUSED_FA, "unused-fa", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xFB, UNUSED_FB, "unused-fb", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xFC, UNUSED_FC, "unused-fc", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xFD, UNUSED_FD, "unused-fd", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xFE, UNUSED_FE, "unused-fe", k10x, false, kUnknown, 0, kVerifyError) \
-  V(0xFF, UNUSED_FF, "unused-ff", k10x, false, kUnknown, 0, kVerifyError)
+  V(0x00, NOP, "nop", k10x, false, kIndexNone, kContinue, kVerifyNone) \
+  V(0x01, MOVE, "move", k12x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x02, MOVE_FROM16, "move/from16", k22x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x03, MOVE_16, "move/16", k32x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x04, MOVE_WIDE, "move-wide", k12x, true, kIndexNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, true, kIndexNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, true, kIndexNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x07, MOVE_OBJECT, "move-object", k12x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x0A, MOVE_RESULT, "move-result", k11x, true, kIndexNone, kContinue, kVerifyRegA) \
+  V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, true, kIndexNone, kContinue, kVerifyRegAWide) \
+  V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, true, kIndexNone, kContinue, kVerifyRegA) \
+  V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, true, kIndexNone, kContinue, kVerifyRegA) \
+  V(0x0E, RETURN_VOID, "return-void", k10x, false, kIndexNone, kReturn, kVerifyNone) \
+  V(0x0F, RETURN, "return", k11x, false, kIndexNone, kReturn, kVerifyRegA) \
+  V(0x10, RETURN_WIDE, "return-wide", k11x, false, kIndexNone, kReturn, kVerifyRegAWide) \
+  V(0x11, RETURN_OBJECT, "return-object", k11x, false, kIndexNone, kReturn, kVerifyRegA) \
+  V(0x12, CONST_4, "const/4", k11n, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+  V(0x13, CONST_16, "const/16", k21s, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+  V(0x14, CONST, "const", k31i, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+  V(0x15, CONST_HIGH16, "const/high16", k21h, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+  V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+  V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+  V(0x18, CONST_WIDE, "const-wide", k51l, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+  V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kIndexNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+  V(0x1A, CONST_STRING, "const-string", k21c, true, kIndexStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
+  V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kIndexStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
+  V(0x1C, CONST_CLASS, "const-class", k21c, true, kIndexTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
+  V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kIndexNone, kContinue | kThrow | kClobber, kVerifyRegA) \
+  V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kIndexNone, kContinue | kThrow | kClobber, kVerifyRegA) \
+  V(0x1F, CHECK_CAST, "check-cast", k21c, true, kIndexTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
+  V(0x20, INSTANCE_OF, "instance-of", k22c, true, kIndexTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \
+  V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kIndexNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+  V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kIndexTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegBNewInstance) \
+  V(0x23, NEW_ARRAY, "new-array", k22c, true, kIndexTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \
+  V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kIndexTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArg) \
+  V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kIndexTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArgRange) \
+  V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kIndexNone, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyArrayData) \
+  V(0x27, THROW, "throw", k11x, false, kIndexNone, kThrow, kVerifyRegA) \
+  V(0x28, GOTO, "goto", k10t, false, kIndexNone, kBranch | kUnconditional, kVerifyBranchTarget) \
+  V(0x29, GOTO_16, "goto/16", k20t, false, kIndexNone, kBranch | kUnconditional, kVerifyBranchTarget) \
+  V(0x2A, GOTO_32, "goto/32", k30t, false, kIndexNone, kBranch | kUnconditional, kVerifyBranchTarget) \
+  V(0x2B, PACKED_SWITCH, "packed-switch", k31t, false, kIndexNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \
+  V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, false, kIndexNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \
+  V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x31, CMP_LONG, "cmp-long", k23x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x32, IF_EQ, "if-eq", k22t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x33, IF_NE, "if-ne", k22t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x34, IF_LT, "if-lt", k22t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x35, IF_GE, "if-ge", k22t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x36, IF_GT, "if-gt", k22t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x37, IF_LE, "if-le", k22t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
+  V(0x38, IF_EQZ, "if-eqz", k21t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x39, IF_NEZ, "if-nez", k21t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3A, IF_LTZ, "if-ltz", k21t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3B, IF_GEZ, "if-gez", k21t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3C, IF_GTZ, "if-gtz", k21t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3D, IF_LEZ, "if-lez", k21t, false, kIndexNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \
+  V(0x3E, UNUSED_3E, "unused-3e", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x3F, UNUSED_3F, "unused-3f", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x40, UNUSED_40, "unused-40", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x41, UNUSED_41, "unused-41", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x42, UNUSED_42, "unused-42", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x43, UNUSED_43, "unused-43", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x44, AGET, "aget", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x45, AGET_WIDE, "aget-wide", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
+  V(0x46, AGET_OBJECT, "aget-object", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x48, AGET_BYTE, "aget-byte", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x49, AGET_CHAR, "aget-char", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4A, AGET_SHORT, "aget-short", k23x, true, kIndexNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4B, APUT, "aput", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
+  V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x50, APUT_CHAR, "aput-char", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x51, APUT_SHORT, "aput-short", k23x, false, kIndexNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x52, IGET, "iget", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x53, IGET_WIDE, "iget-wide", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
+  V(0x54, IGET_OBJECT, "iget-object", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x56, IGET_BYTE, "iget-byte", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x57, IGET_CHAR, "iget-char", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x58, IGET_SHORT, "iget-short", k22c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x59, IPUT, "iput", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
+  V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+  V(0x60, SGET, "sget", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x61, SGET_WIDE, "sget-wide", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
+  V(0x62, SGET_OBJECT, "sget-object", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x64, SGET_BYTE, "sget-byte", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x65, SGET_CHAR, "sget-char", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x66, SGET_SHORT, "sget-short", k21c, true, kIndexFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x67, SPUT, "sput", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
+  V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kIndexFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+  V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
+  V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
+  V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
+  V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
+  V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \
+  V(0x73, RETURN_VOID_NO_BARRIER, "return-void-no-barrier", k10x, false, kIndexNone, kReturn, kVerifyNone) \
+  V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
+  V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
+  V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
+  V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \
+  V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, false, kIndexMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
+  V(0x79, UNUSED_79, "unused-79", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x7A, UNUSED_7A, "unused-7a", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0x7B, NEG_INT, "neg-int", k12x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x7C, NOT_INT, "not-int", k12x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x7D, NEG_LONG, "neg-long", k12x, true, kIndexNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x7E, NOT_LONG, "not-long", k12x, true, kIndexNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kIndexNone, kContinue, kVerifyRegA | kVerifyRegB) \
+  V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kIndexNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+  V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+  V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+  V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+  V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+  V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+  V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+  V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+  V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+  V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+  V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+  V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+  V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kIndexNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+  V(0x90, ADD_INT, "add-int", k23x, true, kIndexNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x91, SUB_INT, "sub-int", k23x, true, kIndexNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x92, MUL_INT, "mul-int", k23x, true, kIndexNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x93, DIV_INT, "div-int", k23x, true, kIndexNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x94, REM_INT, "rem-int", k23x, true, kIndexNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x95, AND_INT, "and-int", k23x, true, kIndexNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x96, OR_INT, "or-int", k23x, true, kIndexNone, kContinue | kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x97, XOR_INT, "xor-int", k23x, true, kIndexNone, kContinue | kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x98, SHL_INT, "shl-int", k23x, true, kIndexNone, kContinue | kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x99, SHR_INT, "shr-int", k23x, true, kIndexNone, kContinue | kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x9A, USHR_INT, "ushr-int", k23x, true, kIndexNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0x9B, ADD_LONG, "add-long", k23x, true, kIndexNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9C, SUB_LONG, "sub-long", k23x, true, kIndexNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9D, MUL_LONG, "mul-long", k23x, true, kIndexNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9E, DIV_LONG, "div-long", k23x, true, kIndexNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0x9F, REM_LONG, "rem-long", k23x, true, kIndexNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA0, AND_LONG, "and-long", k23x, true, kIndexNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA1, OR_LONG, "or-long", k23x, true, kIndexNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA2, XOR_LONG, "xor-long", k23x, true, kIndexNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xA3, SHL_LONG, "shl-long", k23x, true, kIndexNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+  V(0xA4, SHR_LONG, "shr-long", k23x, true, kIndexNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+  V(0xA5, USHR_LONG, "ushr-long", k23x, true, kIndexNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+  V(0xA6, ADD_FLOAT, "add-float", k23x, true, kIndexNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kIndexNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kIndexNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xA9, DIV_FLOAT, "div-float", k23x, true, kIndexNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xAA, REM_FLOAT, "rem-float", k23x, true, kIndexNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+  V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kIndexNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kIndexNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kIndexNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kIndexNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kIndexNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+  V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kIndexNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \
+  V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kIndexNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \
+  V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kIndexNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \
+  V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kIndexNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB) \
+  V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kIndexNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB) \
+  V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kIndexNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB) \
+  V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kIndexNone, kContinue | kOr, kVerifyRegA | kVerifyRegB) \
+  V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kIndexNone, kContinue | kXor, kVerifyRegA | kVerifyRegB) \
+  V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kIndexNone, kContinue | kShl, kVerifyRegA | kVerifyRegB) \
+  V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kIndexNone, kContinue | kShr, kVerifyRegA | kVerifyRegB) \
+  V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kIndexNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB) \
+  V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kIndexNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kIndexNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kIndexNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kIndexNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kIndexNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kIndexNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kIndexNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kIndexNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kIndexNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegB) \
+  V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kIndexNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegB) \
+  V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kIndexNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegB) \
+  V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kIndexNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \
+  V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kIndexNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \
+  V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kIndexNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \
+  V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kIndexNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB) \
+  V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kIndexNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB) \
+  V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kIndexNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kIndexNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kIndexNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kIndexNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kIndexNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
+  V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kIndexNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD1, RSUB_INT, "rsub-int", k22s, true, kIndexNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kIndexNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kIndexNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kIndexNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kIndexNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kIndexNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kIndexNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kIndexNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kIndexNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kIndexNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kIndexNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kIndexNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kIndexNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kIndexNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kIndexNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kIndexNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kIndexNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kIndexNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+  V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kIndexVtableOffset, kContinue | kThrow | kInvoke, kVerifyVarArgNonZero | kVerifyRuntimeOnly) \
+  V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kIndexVtableOffset, kContinue | kThrow | kInvoke, kVerifyVarArgRangeNonZero | kVerifyRuntimeOnly) \
+  V(0xEB, IPUT_BOOLEAN_QUICK, "iput-boolean-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, false, kIndexFieldOffset, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xEF, IGET_BOOLEAN_QUICK, "iget-boolean-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF0, IGET_BYTE_QUICK, "iget-byte-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF1, IGET_CHAR_QUICK, "iget-char-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF2, IGET_SHORT_QUICK, "iget-short-quick", k22c, true, kIndexFieldOffset, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xF3, INVOKE_LAMBDA, "invoke-lambda", k25x, false, kIndexNone, kContinue | kThrow | kInvoke | kExperimental, kVerifyRegC /*TODO: | kVerifyVarArg*/) \
+  V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  /* TODO(iam): get rid of the unused 'false' column */ \
+  V(0xF6, CREATE_LAMBDA, "create-lambda", k21c, false_UNUSED, kIndexMethodRef, kContinue | kThrow | kExperimental, kVerifyRegA | kVerifyRegBMethod) \
+  V(0xF7, UNUSED_F7, "unused-f7", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xF8, BOX_LAMBDA, "box-lambda", k22x, true, kIndexNone, kContinue | kExperimental, kVerifyRegA | kVerifyRegB) \
+  V(0xF9, UNBOX_LAMBDA, "unbox-lambda", k22c, true, kIndexTypeRef, kContinue | kThrow | kExperimental, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \
+  V(0xFA, UNUSED_FA, "unused-fa", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xFB, UNUSED_FB, "unused-fb", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xFC, UNUSED_FC, "unused-fc", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xFD, UNUSED_FD, "unused-fd", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xFE, UNUSED_FE, "unused-fe", k10x, false, kIndexUnknown, 0, kVerifyError) \
+  V(0xFF, UNUSED_FF, "unused-ff", k10x, false, kIndexUnknown, 0, kVerifyError)
 
 #define DEX_INSTRUCTION_FORMAT_LIST(V) \
   V(k10x) \
@@ -292,6 +293,7 @@
   V(k22t) \
   V(k22s) \
   V(k22c) \
+  V(k25x) \
   V(k32x) \
   V(k30t) \
   V(k31t) \
diff --git a/runtime/dex_instruction_test.cc b/runtime/dex_instruction_test.cc
new file mode 100644
index 0000000..671ac0e
--- /dev/null
+++ b/runtime/dex_instruction_test.cc
@@ -0,0 +1,31 @@
+/*
+ * 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 "dex_instruction-inl.h"
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(StaticGetters, PropertiesOfNopTest) {
+  Instruction::Code nop = Instruction::NOP;
+  EXPECT_STREQ("nop", Instruction::Name(nop));
+  EXPECT_EQ(Instruction::k10x, Instruction::FormatOf(nop));
+  EXPECT_EQ(Instruction::kIndexNone, Instruction::IndexTypeOf(nop));
+  EXPECT_EQ(Instruction::kContinue, Instruction::FlagsOf(nop));
+  EXPECT_EQ(Instruction::kVerifyNone, Instruction::VerifyFlagsOf(nop));
+}
+
+}  // namespace art
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index a4dd55c..de925b7 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -38,25 +38,83 @@
 
 namespace art {
 
-inline ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
+                                    const InlineInfo& inline_info,
+                                    uint8_t inlining_depth)
+  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  uint32_t method_index = inline_info.GetMethodIndexAtDepth(inlining_depth);
+  InvokeType invoke_type = static_cast<InvokeType>(
+        inline_info.GetInvokeTypeAtDepth(inlining_depth));
+  ArtMethod* caller = outer_method->GetDexCacheResolvedMethod(method_index, sizeof(void*));
+  if (!caller->IsRuntimeMethod()) {
+    return caller;
+  }
+
+  // The method in the dex cache can be the runtime method responsible for invoking
+  // the stub that will then update the dex cache. Therefore, we need to do the
+  // resolution ourselves.
+
+  // We first find the class loader of our caller. If it is the outer method, we can directly
+  // use its class loader. Otherwise, we also need to resolve our caller.
+  StackHandleScope<2> hs(Thread::Current());
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  MutableHandle<mirror::ClassLoader> class_loader(hs.NewHandle<mirror::Class>(nullptr));
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(outer_method->GetDexCache()));
+  if (inlining_depth == 0) {
+    class_loader.Assign(outer_method->GetClassLoader());
+  } else {
+    caller = GetResolvedMethod(outer_method, inline_info, inlining_depth - 1);
+    class_loader.Assign(caller->GetClassLoader());
+  }
+
+  return class_linker->ResolveMethod(
+      *outer_method->GetDexFile(), method_index, dex_cache, class_loader, nullptr, invoke_type);
+}
+
+inline ArtMethod* GetCalleeSaveMethodCaller(ArtMethod** sp,
+                                            Runtime::CalleeSaveType type,
+                                            bool do_caller_check = false)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  auto** refs_only_sp = self->GetManagedStack()->GetTopQuickFrame();
-  DCHECK_EQ(*refs_only_sp, Runtime::Current()->GetCalleeSaveMethod(type));
+  DCHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(type));
 
   const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type);
   auto** caller_sp = reinterpret_cast<ArtMethod**>(
-      reinterpret_cast<uintptr_t>(refs_only_sp) + callee_frame_size);
-  auto* caller = *caller_sp;
+      reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
+  ArtMethod* outer_method = *caller_sp;
+  ArtMethod* caller = outer_method;
 
-  if (kIsDebugBuild) {
-    NthCallerVisitor visitor(self, 1, true);
+  if ((outer_method != nullptr) && outer_method->IsOptimized(sizeof(void*))) {
+    const size_t callee_return_pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, type);
+    uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(
+        (reinterpret_cast<uint8_t*>(sp) + callee_return_pc_offset));
+    uintptr_t native_pc_offset = outer_method->NativeQuickPcOffset(caller_pc);
+    CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+    StackMapEncoding encoding = code_info.ExtractEncoding();
+    StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+    DCHECK(stack_map.IsValid());
+    if (stack_map.HasInlineInfo(encoding)) {
+      InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
+      caller = GetResolvedMethod(outer_method, inline_info, inline_info.GetDepth() - 1);
+    }
+  }
+
+  if (kIsDebugBuild && do_caller_check) {
+    // Note that do_caller_check is optional, as this method can be called by
+    // stubs, and tests without a proper call stack.
+    NthCallerVisitor visitor(Thread::Current(), 1, true);
     visitor.WalkStack();
-    CHECK(caller == visitor.caller);
+    CHECK_EQ(caller, visitor.caller);
   }
 
   return caller;
 }
 
+inline ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return GetCalleeSaveMethodCaller(
+      self->GetManagedStack()->GetTopQuickFrame(), type, true /* do_caller_check */);
+}
+
 template <const bool kAccessCheck>
 ALWAYS_INLINE
 inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index 521c549..7a44158 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -36,22 +36,24 @@
 
 class ScopedQuickEntrypointChecks {
  public:
-  explicit ScopedQuickEntrypointChecks(Thread *self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : self_(self) {
-    if (kIsDebugBuild) {
+  explicit ScopedQuickEntrypointChecks(Thread *self,
+                                       bool entry_check = kIsDebugBuild,
+                                       bool exit_check = kIsDebugBuild)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : self_(self), exit_check_(exit_check) {
+    if (entry_check) {
       TestsOnEntry();
     }
   }
 
-  explicit ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : self_(kIsDebugBuild ? Thread::Current() : nullptr) {
+  ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : self_(kIsDebugBuild ? Thread::Current() : nullptr), exit_check_(kIsDebugBuild) {
     if (kIsDebugBuild) {
       TestsOnEntry();
     }
   }
 
   ~ScopedQuickEntrypointChecks() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (kIsDebugBuild) {
+    if (exit_check_) {
       TestsOnExit();
     }
   }
@@ -68,6 +70,7 @@
   }
 
   Thread* const self_;
+  bool exit_check_;
 };
 
 static constexpr size_t GetCalleeSaveFrameSize(InstructionSet isa, Runtime::CalleeSaveType type) {
diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h
index c7aaa20..fbf028d 100644
--- a/runtime/entrypoints/quick/quick_default_externs.h
+++ b/runtime/entrypoints/quick/quick_default_externs.h
@@ -80,6 +80,7 @@
 // Math entrypoints.
 extern "C" int64_t art_quick_d2l(double);
 extern "C" int64_t art_quick_f2l(float);
+extern "C" float art_quick_l2f(int64_t);
 extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
 extern "C" int64_t art_quick_lmod(int64_t, int64_t);
 extern "C" int64_t art_quick_lmul(int64_t, int64_t);
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 9860fb0..f1b5445 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "art_method-inl.h"
+#include "base/logging.h"
 #include "callee_save_frame.h"
 #include "dex_file-inl.h"
 #include "interpreter/interpreter.h"
@@ -28,6 +30,12 @@
 
 extern "C" NO_RETURN void artDeoptimize(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
+
+  if (VLOG_IS_ON(deopt)) {
+    LOG(INFO) << "Deopting:";
+    self->Dump(LOG(INFO));
+  }
+
   self->PushAndClearDeoptimizationReturnValue();
   self->SetException(Thread::GetDeoptimizationException());
   self->QuickDeliverException();
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 67649d4..3cefc47 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -25,8 +25,7 @@
 
 namespace art {
 
-extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx,
-                                                             Thread* self)
+extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called to ensure static storage base is initialized for direct static field reads and writes.
   // A class may be accessing another class' fields when it doesn't have access, as access has been
@@ -36,8 +35,7 @@
   return ResolveVerifyAndClinit(type_idx, caller, self, true, false);
 }
 
-extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx,
-                                                    Thread* self)
+extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when method->dex_cache_resolved_types_[] misses.
   ScopedQuickEntrypointChecks sqec(self);
@@ -45,8 +43,7 @@
   return ResolveVerifyAndClinit(type_idx, caller, self, false, false);
 }
 
-extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx,
-                                                                   Thread* self)
+extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Called when caller isn't guaranteed to have access to a type and the dex cache may be
   // unpopulated.
@@ -55,8 +52,7 @@
   return ResolveVerifyAndClinit(type_idx, caller, self, false, true);
 }
 
-extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx,
-                                                    Thread* self)
+extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kRefsOnly);
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 7eb73c3..2b5c15b 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -29,7 +29,9 @@
                                                              Thread* self,
                                                              uintptr_t lr)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ScopedQuickEntrypointChecks sqec(self);
+  // Instrumentation changes the stack. Thus, when exiting, the stack cannot be verified, so skip
+  // that part.
+  ScopedQuickEntrypointChecks sqec(self, kIsDebugBuild, false);
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   const void* result;
   if (instrumentation->IsDeoptimized(method)) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 2ea5cb0..4f76ebd 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -89,7 +89,7 @@
   // | LR         |
   // | X29        |
   // |  :         |
-  // | X19        |
+  // | X20        |
   // | X7         |
   // | :          |
   // | X1         |
@@ -291,14 +291,43 @@
     return reinterpret_cast<StackReference<mirror::Object>*>(this_arg_address)->AsMirrorPtr();
   }
 
-  static ArtMethod* GetCallingMethod(ArtMethod** sp)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  static ArtMethod* GetCallingMethod(ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK((*sp)->IsCalleeSaveMethod());
-    uint8_t* previous_sp = reinterpret_cast<uint8_t*>(sp) +
-        kQuickCalleeSaveFrame_RefAndArgs_FrameSize;
+    return GetCalleeSaveMethodCaller(sp, Runtime::kRefsAndArgs);
+  }
+
+  static ArtMethod* GetOuterMethod(ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK((*sp)->IsCalleeSaveMethod());
+    uint8_t* previous_sp =
+        reinterpret_cast<uint8_t*>(sp) + kQuickCalleeSaveFrame_RefAndArgs_FrameSize;
     return *reinterpret_cast<ArtMethod**>(previous_sp);
   }
 
+  static uint32_t GetCallingDexPc(ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK((*sp)->IsCalleeSaveMethod());
+    const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, Runtime::kRefsAndArgs);
+    ArtMethod** caller_sp = reinterpret_cast<ArtMethod**>(
+        reinterpret_cast<uintptr_t>(sp) + callee_frame_size);
+    ArtMethod* outer_method = *caller_sp;
+    uintptr_t outer_pc = QuickArgumentVisitor::GetCallingPc(sp);
+    uintptr_t outer_pc_offset = outer_method->NativeQuickPcOffset(outer_pc);
+
+    if (outer_method->IsOptimized(sizeof(void*))) {
+      CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+      StackMapEncoding encoding = code_info.ExtractEncoding();
+      StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset, encoding);
+      DCHECK(stack_map.IsValid());
+      if (stack_map.HasInlineInfo(encoding)) {
+        InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
+        return inline_info.GetDexPcAtDepth(inline_info.GetDepth() - 1);
+      } else {
+        return stack_map.GetDexPc(encoding);
+      }
+    } else {
+      return outer_method->ToDexPc(outer_pc);
+    }
+  }
+
   // For the given quick ref and args quick frame, return the caller's PC.
   static uintptr_t GetCallingPc(ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK((*sp)->IsCalleeSaveMethod());
@@ -814,7 +843,10 @@
 extern "C" const void* artQuickResolutionTrampoline(
     ArtMethod* called, mirror::Object* receiver, Thread* self, ArtMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ScopedQuickEntrypointChecks sqec(self);
+  // The resolution trampoline stashes the resolved method into the callee-save frame to transport
+  // it. Thus, when exiting, the stack cannot be verified (as the resolved method most likely
+  // does not have the same stack layout as the callee-save method).
+  ScopedQuickEntrypointChecks sqec(self, kIsDebugBuild, false);
   // Start new JNI local reference state
   JNIEnvExt* env = self->GetJniEnv();
   ScopedObjectAccessUnchecked soa(env);
@@ -823,12 +855,13 @@
 
   // Compute details about the called method (avoid GCs)
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  ArtMethod* caller = QuickArgumentVisitor::GetCallingMethod(sp);
   InvokeType invoke_type;
   MethodReference called_method(nullptr, 0);
   const bool called_method_known_on_entry = !called->IsRuntimeMethod();
+  ArtMethod* caller = nullptr;
   if (!called_method_known_on_entry) {
-    uint32_t dex_pc = caller->ToDexPc(QuickArgumentVisitor::GetCallingPc(sp));
+    caller = QuickArgumentVisitor::GetCallingMethod(sp);
+    uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
     const DexFile::CodeItem* code;
     called_method.dex_file = caller->GetDexFile();
     code = caller->GetCodeItem();
@@ -1941,14 +1974,11 @@
 // to hold the mutator lock (see SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) annotations).
 
 template<InvokeType type, bool access_check>
-static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
-                                     ArtMethod* caller_method, Thread* self, ArtMethod** sp);
-
-template<InvokeType type, bool access_check>
-static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
-                                     ArtMethod* caller_method, Thread* self, ArtMethod** sp) {
+static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_object, Thread* self,
+                                     ArtMethod** sp) {
   ScopedQuickEntrypointChecks sqec(self);
   DCHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
+  ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
   ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
   if (UNLIKELY(method == nullptr)) {
     const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
@@ -1984,11 +2014,8 @@
 // Explicit artInvokeCommon template function declarations to please analysis tool.
 #define EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(type, access_check)                                \
   template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                          \
-  TwoWordReturn artInvokeCommon<type, access_check>(uint32_t method_idx,                        \
-                                                    mirror::Object* this_object,                \
-                                                    ArtMethod* caller_method,                   \
-                                                    Thread* self,                               \
-                                                    ArtMethod** sp)      \
+  TwoWordReturn artInvokeCommon<type, access_check>(                                            \
+      uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
 
 EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kVirtual, false);
 EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kVirtual, true);
@@ -2004,53 +2031,49 @@
 
 // See comments in runtime_support_asm.S
 extern "C" TwoWordReturn artInvokeInterfaceTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    ArtMethod* caller_method, Thread* self, ArtMethod** sp)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kInterface, true>(method_idx, this_object,
-                                           caller_method, self, sp);
+    uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kInterface, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeDirectTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    ArtMethod* caller_method, Thread* self, ArtMethod** sp)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kDirect, true>(method_idx, this_object, caller_method,
-                                        self, sp);
+    uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kDirect, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeStaticTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    ArtMethod* caller_method, Thread* self, ArtMethod** sp)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kStatic, true>(method_idx, this_object, caller_method,
-                                        self, sp);
+    uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kStatic, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeSuperTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    ArtMethod* caller_method, Thread* self, ArtMethod** sp)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kSuper, true>(method_idx, this_object, caller_method,
-                                       self, sp);
+    uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kSuper, true>(method_idx, this_object, self, sp);
 }
 
 extern "C" TwoWordReturn artInvokeVirtualTrampolineWithAccessCheck(
-    uint32_t method_idx, mirror::Object* this_object,
-    ArtMethod* caller_method, Thread* self, ArtMethod** sp)
-        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return artInvokeCommon<kVirtual, true>(method_idx, this_object, caller_method,
-                                         self, sp);
+    uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return artInvokeCommon<kVirtual, true>(method_idx, this_object, self, sp);
 }
 
 // Determine target of interface dispatch. This object is known non-null.
-extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_method,
+extern "C" TwoWordReturn artInvokeInterfaceTrampoline(uint32_t dex_method_idx,
                                                       mirror::Object* this_object,
-                                                      ArtMethod* caller_method,
-                                                      Thread* self,
-                                                      ArtMethod** sp)
+                                                      Thread* self, ArtMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
+  // The optimizing compiler currently does not inline methods that have an interface
+  // invocation. We use the outer method directly to avoid fetching a stack map, which is
+  // more expensive.
+  ArtMethod* caller_method = QuickArgumentVisitor::GetOuterMethod(sp);
+  DCHECK_EQ(caller_method, QuickArgumentVisitor::GetCallingMethod(sp));
+  ArtMethod* interface_method = caller_method->GetDexCacheResolvedMethod(
+      dex_method_idx, sizeof(void*));
+  DCHECK(interface_method != nullptr) << dex_method_idx << " " << PrettyMethod(caller_method);
   ArtMethod* method;
   if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
     method = this_object->GetClass()->FindVirtualMethodForInterface(
@@ -2062,26 +2085,21 @@
     }
   } else {
     DCHECK_EQ(interface_method, Runtime::Current()->GetResolutionMethod());
-
-    // Find the caller PC.
-    constexpr size_t pc_offset = GetCalleeSaveReturnPcOffset(kRuntimeISA, Runtime::kRefsAndArgs);
-    uintptr_t caller_pc = *reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(sp) + pc_offset);
-
-    // Map the caller PC to a dex PC.
-    uint32_t dex_pc = caller_method->ToDexPc(caller_pc);
-    const DexFile::CodeItem* code = caller_method->GetCodeItem();
-    CHECK_LT(dex_pc, code->insns_size_in_code_units_);
-    const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
-    Instruction::Code instr_code = instr->Opcode();
-    CHECK(instr_code == Instruction::INVOKE_INTERFACE ||
-          instr_code == Instruction::INVOKE_INTERFACE_RANGE)
-        << "Unexpected call into interface trampoline: " << instr->DumpString(nullptr);
-    uint32_t dex_method_idx;
-    if (instr_code == Instruction::INVOKE_INTERFACE) {
-      dex_method_idx = instr->VRegB_35c();
-    } else {
-      DCHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE);
-      dex_method_idx = instr->VRegB_3rc();
+    if (kIsDebugBuild) {
+      uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
+      const DexFile::CodeItem* code = caller_method->GetCodeItem();
+      CHECK_LT(dex_pc, code->insns_size_in_code_units_);
+      const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+      Instruction::Code instr_code = instr->Opcode();
+      CHECK(instr_code == Instruction::INVOKE_INTERFACE ||
+            instr_code == Instruction::INVOKE_INTERFACE_RANGE)
+          << "Unexpected call into interface trampoline: " << instr->DumpString(nullptr);
+      if (instr_code == Instruction::INVOKE_INTERFACE) {
+        CHECK_EQ(dex_method_idx, instr->VRegB_35c());
+      } else {
+        CHECK_EQ(instr_code, Instruction::INVOKE_INTERFACE_RANGE);
+        CHECK_EQ(dex_method_idx, instr->VRegB_3rc());
+      }
     }
 
     const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 762f061..5f91566 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(IsAligned<sizeof(void*)>(ArtMethod::ObjectSize(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/allocation_record.cc b/runtime/gc/allocation_record.cc
new file mode 100644
index 0000000..6537ed2
--- /dev/null
+++ b/runtime/gc/allocation_record.cc
@@ -0,0 +1,291 @@
+/*
+ * 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 "allocation_record.h"
+
+#include "art_method-inl.h"
+#include "base/stl_util.h"
+#include "stack.h"
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+#endif
+
+namespace art {
+namespace gc {
+
+int32_t AllocRecordStackTraceElement::ComputeLineNumber() const {
+  DCHECK(method_ != nullptr);
+  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.
+  const char* propertyName = "dalvik.vm.allocTrackerMax";
+  char allocMaxString[PROPERTY_VALUE_MAX];
+  if (property_get(propertyName, allocMaxString, "") > 0) {
+    char* end;
+    size_t value = strtoul(allocMaxString, &end, 10);
+    if (*end != '\0') {
+      LOG(ERROR) << "Ignoring  " << propertyName << " '" << allocMaxString
+                 << "' --- invalid";
+    } else {
+      alloc_record_max_ = value;
+      if (recent_record_max_ > value) {
+        recent_record_max_ = value;
+      }
+    }
+  }
+  // Check whether there's a system property overriding the number of recent records.
+  propertyName = "dalvik.vm.recentAllocMax";
+  char recentAllocMaxString[PROPERTY_VALUE_MAX];
+  if (property_get(propertyName, recentAllocMaxString, "") > 0) {
+    char* end;
+    size_t value = strtoul(recentAllocMaxString, &end, 10);
+    if (*end != '\0') {
+      LOG(ERROR) << "Ignoring  " << propertyName << " '" << recentAllocMaxString
+                 << "' --- invalid";
+    } else if (value > alloc_record_max_) {
+      LOG(ERROR) << "Ignoring  " << propertyName << " '" << recentAllocMaxString
+                 << "' --- should be less than " << alloc_record_max_;
+    } else {
+      recent_record_max_ = value;
+    }
+  }
+  // Check whether there's a system property overriding the max depth of stack trace.
+  propertyName = "debug.allocTracker.stackDepth";
+  char stackDepthString[PROPERTY_VALUE_MAX];
+  if (property_get(propertyName, stackDepthString, "") > 0) {
+    char* end;
+    size_t value = strtoul(stackDepthString, &end, 10);
+    if (*end != '\0') {
+      LOG(ERROR) << "Ignoring  " << propertyName << " '" << stackDepthString
+                 << "' --- invalid";
+    } else if (value > kMaxSupportedStackDepth) {
+      LOG(WARNING) << propertyName << " '" << stackDepthString << "' too large, using "
+                   << kMaxSupportedStackDepth;
+      max_stack_depth_ = kMaxSupportedStackDepth;
+    } else {
+      max_stack_depth_ = value;
+    }
+  }
+#endif
+}
+
+AllocRecordObjectMap::~AllocRecordObjectMap() {
+  STLDeleteValues(&entries_);
+}
+
+void AllocRecordObjectMap::VisitRoots(RootVisitor* visitor) {
+  CHECK_LE(recent_record_max_, alloc_record_max_);
+  BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, RootInfo(kRootDebugger));
+  size_t count = recent_record_max_;
+  // 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.VisitRootIfNonNull(it->second->GetClassGcRoot());
+  }
+}
+
+static inline void SweepClassObject(AllocRecord* record, IsMarkedCallback* callback, void* arg)
+    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>();
+  // 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 = 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);
+  }
+}
+
+void AllocRecordObjectMap::SweepAllocationRecords(IsMarkedCallback* callback, void* arg) {
+  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.
+  size_t delete_bound;
+  if (entries_.size() <= recent_record_max_) {
+    delete_bound = 0;
+  } else {
+    delete_bound = entries_.size() - recent_record_max_;
+  }
+  for (auto it = entries_.begin(), end = entries_.end(); it != end;) {
+    ++count;
+    // 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);
+    if (new_object == nullptr) {
+      if (count > delete_bound) {
+        it->first = GcRoot<mirror::Object>(nullptr);
+        SweepClassObject(record, callback, arg);
+        ++it;
+      } else {
+        delete record;
+        it = entries_.erase(it);
+        ++count_deleted;
+      }
+    } else {
+      if (old_object != new_object) {
+        it->first = GcRoot<mirror::Object>(new_object);
+        ++count_moved;
+      }
+      SweepClassObject(record, callback, arg);
+      ++it;
+    }
+  }
+  VLOG(heap) << "Deleted " << count_deleted << " allocation records";
+  VLOG(heap) << "Updated " << count_moved << " allocation records";
+}
+
+void AllocRecordObjectMap::AllowNewAllocationRecords() {
+  allow_new_record_ = true;
+  new_record_condition_.Broadcast(Thread::Current());
+}
+
+void AllocRecordObjectMap::DisallowNewAllocationRecords() {
+  allow_new_record_ = false;
+}
+
+struct AllocRecordStackVisitor : public StackVisitor {
+  AllocRecordStackVisitor(Thread* thread, AllocRecordStackTrace* trace_in, size_t max)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+        trace(trace_in),
+        depth(0),
+        max_depth(max) {}
+
+  // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
+  // annotalysis.
+  bool VisitFrame() OVERRIDE NO_THREAD_SAFETY_ANALYSIS {
+    if (depth >= max_depth) {
+      return false;
+    }
+    ArtMethod* m = GetMethod();
+    if (!m->IsRuntimeMethod()) {
+      trace->SetStackElementAt(depth, m, GetDexPc());
+      ++depth;
+    }
+    return true;
+  }
+
+  ~AllocRecordStackVisitor() {
+    trace->SetDepth(depth);
+  }
+
+  AllocRecordStackTrace* trace;
+  size_t depth;
+  const size_t max_depth;
+};
+
+void AllocRecordObjectMap::SetAllocTrackingEnabled(bool enable) {
+  Thread* self = Thread::Current();
+  Heap* heap = Runtime::Current()->GetHeap();
+  if (enable) {
+    {
+      MutexLock mu(self, *Locks::alloc_tracker_lock_);
+      if (heap->IsAllocTrackingEnabled()) {
+        return;  // Already enabled, bail.
+      }
+      AllocRecordObjectMap* records = new AllocRecordObjectMap();
+      CHECK(records != nullptr);
+      records->SetProperties();
+      std::string self_name;
+      self->GetThreadName(self_name);
+      if (self_name == "JDWP") {
+        records->alloc_ddm_thread_id_ = self->GetTid();
+      }
+      records->scratch_trace_.SetDepth(records->max_stack_depth_);
+      size_t sz = sizeof(AllocRecordStackTraceElement) * records->max_stack_depth_ +
+                  sizeof(AllocRecord) + sizeof(AllocRecordStackTrace);
+      LOG(INFO) << "Enabling alloc tracker (" << records->alloc_record_max_ << " entries of "
+                << records->max_stack_depth_ << " frames, taking up to "
+                << PrettySize(sz * records->alloc_record_max_) << ")";
+      heap->SetAllocationRecords(records);
+      heap->SetAllocTrackingEnabled(true);
+    }
+    Runtime::Current()->GetInstrumentation()->InstrumentQuickAllocEntryPoints();
+  } else {
+    {
+      MutexLock mu(self, *Locks::alloc_tracker_lock_);
+      if (!heap->IsAllocTrackingEnabled()) {
+        return;  // Already disabled, bail.
+      }
+      heap->SetAllocTrackingEnabled(false);
+      LOG(INFO) << "Disabling alloc tracker";
+      heap->SetAllocationRecords(nullptr);
+    }
+    // If an allocation comes in before we uninstrument, we will safely drop it on the floor.
+    Runtime::Current()->GetInstrumentation()->UninstrumentQuickAllocEntryPoints();
+  }
+}
+
+void AllocRecordObjectMap::RecordAllocation(Thread* self, mirror::Object* obj, mirror::Class* klass,
+                                            size_t byte_count) {
+  MutexLock mu(self, *Locks::alloc_tracker_lock_);
+  Heap* heap = Runtime::Current()->GetHeap();
+  if (!heap->IsAllocTrackingEnabled()) {
+    // In the process of shutting down recording, bail.
+    return;
+  }
+
+  AllocRecordObjectMap* records = heap->GetAllocationRecords();
+  DCHECK(records != nullptr);
+
+  // Do not record for DDM thread
+  if (records->alloc_ddm_thread_id_ == self->GetTid()) {
+    return;
+  }
+
+  // Wait for GC's sweeping to complete and allow new records
+  while (UNLIKELY(!records->allow_new_record_)) {
+    records->new_record_condition_.WaitHoldingLocks(self);
+  }
+
+  DCHECK_LE(records->Size(), records->alloc_record_max_);
+
+  // Get stack trace.
+  // add scope to make "visitor" destroyed promptly, in order to set the scratch_trace_->depth_
+  {
+    AllocRecordStackVisitor visitor(self, &records->scratch_trace_, records->max_stack_depth_);
+    visitor.WalkStack();
+  }
+  records->scratch_trace_.SetTid(self->GetTid());
+  AllocRecordStackTrace* trace = new AllocRecordStackTrace(records->scratch_trace_);
+
+  // Fill in the basics.
+  AllocRecord* record = new AllocRecord(byte_count, klass, trace);
+
+  records->Put(obj, record);
+  DCHECK_LE(records->Size(), records->alloc_record_max_);
+}
+
+}  // namespace gc
+}  // namespace art
diff --git a/runtime/gc/allocation_record.h b/runtime/gc/allocation_record.h
new file mode 100644
index 0000000..06721c8
--- /dev/null
+++ b/runtime/gc/allocation_record.h
@@ -0,0 +1,326 @@
+/*
+ * 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_GC_ALLOCATION_RECORD_H_
+#define ART_RUNTIME_GC_ALLOCATION_RECORD_H_
+
+#include <list>
+
+#include "base/mutex.h"
+#include "object_callbacks.h"
+#include "gc_root.h"
+
+namespace art {
+
+class ArtMethod;
+class Thread;
+
+namespace mirror {
+  class Class;
+  class Object;
+}
+
+namespace gc {
+
+class AllocRecordStackTraceElement {
+ public:
+  AllocRecordStackTraceElement() : method_(nullptr), dex_pc_(0) {}
+
+  int32_t ComputeLineNumber() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  ArtMethod* GetMethod() const {
+    return method_;
+  }
+
+  void SetMethod(ArtMethod* m) {
+    method_ = m;
+  }
+
+  uint32_t GetDexPc() const {
+    return dex_pc_;
+  }
+
+  void SetDexPc(uint32_t pc) {
+    dex_pc_ = pc;
+  }
+
+  bool operator==(const AllocRecordStackTraceElement& other) const {
+    if (this == &other) return true;
+    return method_ == other.method_ && dex_pc_ == other.dex_pc_;
+  }
+
+ private:
+  ArtMethod* method_;
+  uint32_t dex_pc_;
+};
+
+class AllocRecordStackTrace {
+ public:
+  static constexpr size_t kHashMultiplier = 17;
+
+  explicit AllocRecordStackTrace(size_t max_depth)
+      : tid_(0), depth_(0), stack_(new AllocRecordStackTraceElement[max_depth]) {}
+
+  AllocRecordStackTrace(const AllocRecordStackTrace& r)
+      : tid_(r.tid_), depth_(r.depth_), stack_(new AllocRecordStackTraceElement[r.depth_]) {
+    for (size_t i = 0; i < depth_; ++i) {
+      stack_[i] = r.stack_[i];
+    }
+  }
+
+  ~AllocRecordStackTrace() {
+    delete[] stack_;
+  }
+
+  pid_t GetTid() const {
+    return tid_;
+  }
+
+  void SetTid(pid_t t) {
+    tid_ = t;
+  }
+
+  size_t GetDepth() const {
+    return depth_;
+  }
+
+  void SetDepth(size_t depth) {
+    depth_ = depth;
+  }
+
+  const AllocRecordStackTraceElement& GetStackElement(size_t index) const {
+    DCHECK_LT(index, depth_);
+    return stack_[index];
+  }
+
+  void SetStackElementAt(size_t index, ArtMethod* m, uint32_t dex_pc) {
+    stack_[index].SetMethod(m);
+    stack_[index].SetDexPc(dex_pc);
+  }
+
+  bool operator==(const AllocRecordStackTrace& other) const {
+    if (this == &other) return true;
+    if (tid_ != other.tid_) return false;
+    if (depth_ != other.depth_) return false;
+    for (size_t i = 0; i < depth_; ++i) {
+      if (!(stack_[i] == other.stack_[i])) return false;
+    }
+    return true;
+  }
+
+ private:
+  pid_t tid_;
+  size_t depth_;
+  AllocRecordStackTraceElement* const stack_;
+};
+
+struct HashAllocRecordTypes {
+  size_t operator()(const AllocRecordStackTraceElement& r) const {
+    return std::hash<void*>()(reinterpret_cast<void*>(r.GetMethod())) *
+        AllocRecordStackTrace::kHashMultiplier + std::hash<uint32_t>()(r.GetDexPc());
+  }
+
+  size_t operator()(const AllocRecordStackTrace& r) const {
+    size_t depth = r.GetDepth();
+    size_t result = r.GetTid() * AllocRecordStackTrace::kHashMultiplier + depth;
+    for (size_t i = 0; i < depth; ++i) {
+      result = result * AllocRecordStackTrace::kHashMultiplier + (*this)(r.GetStackElement(i));
+    }
+    return result;
+  }
+};
+
+template <typename T> struct HashAllocRecordTypesPtr {
+  size_t operator()(const T* r) const {
+    if (r == nullptr) return 0;
+    return HashAllocRecordTypes()(*r);
+  }
+};
+
+template <typename T> struct EqAllocRecordTypesPtr {
+  bool operator()(const T* r1, const T* r2) const {
+    if (r1 == r2) return true;
+    if (r1 == nullptr || r2 == nullptr) return false;
+    return *r1 == *r2;
+  }
+};
+
+class AllocRecord {
+ public:
+  // All instances of AllocRecord should be managed by an instance of AllocRecordObjectMap.
+  AllocRecord(size_t count, mirror::Class* klass, AllocRecordStackTrace* trace)
+      : byte_count_(count), klass_(klass), trace_(trace) {}
+
+  ~AllocRecord() {
+    delete trace_;
+  }
+
+  size_t GetDepth() const {
+    return trace_->GetDepth();
+  }
+
+  const AllocRecordStackTrace* GetStackTrace() const {
+    return trace_;
+  }
+
+  size_t ByteCount() const {
+    return byte_count_;
+  }
+
+  pid_t GetTid() const {
+    return trace_->GetTid();
+  }
+
+  mirror::Class* GetClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return klass_.Read();
+  }
+
+  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_;
+  }
+
+  const AllocRecordStackTraceElement& StackElement(size_t index) const {
+    return trace_->GetStackElement(index);
+  }
+
+ private:
+  const size_t byte_count_;
+  // The klass_ could be a strong or weak root for GC
+  GcRoot<mirror::Class> klass_;
+  // TODO: Currently trace_ is like a std::unique_ptr,
+  // but in future with deduplication it could be a std::shared_ptr.
+  const AllocRecordStackTrace* const trace_;
+};
+
+class AllocRecordObjectMap {
+ public:
+  // GcRoot<mirror::Object> pointers in the list are weak roots, and the last recent_record_max_
+  // number of AllocRecord::klass_ pointers are strong roots (and the rest of klass_ pointers are
+  // weak roots). The last recent_record_max_ number of pairs in the list are always kept for DDMS's
+  // recent allocation tracking, but GcRoot<mirror::Object> pointers in these pairs can become null.
+  // Both types of pointers need read barriers, do not directly access them.
+  typedef std::list<std::pair<GcRoot<mirror::Object>, AllocRecord*>> EntryList;
+
+  // "static" because it is part of double-checked locking. It needs to check a bool first,
+  // in order to make sure the AllocRecordObjectMap object is not null.
+  static void RecordAllocation(Thread* self, mirror::Object* obj, mirror::Class* klass,
+                               size_t byte_count)
+      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  static void SetAllocTrackingEnabled(bool enabled) LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
+
+  AllocRecordObjectMap() EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_)
+      : alloc_record_max_(kDefaultNumAllocRecords),
+        recent_record_max_(kDefaultNumRecentRecords),
+        max_stack_depth_(kDefaultAllocStackDepth),
+        scratch_trace_(kMaxSupportedStackDepth),
+        alloc_ddm_thread_id_(0),
+        allow_new_record_(true),
+        new_record_condition_("New allocation record condition", *Locks::alloc_tracker_lock_) {}
+
+  ~AllocRecordObjectMap();
+
+  void Put(mirror::Object* obj, AllocRecord* record)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    if (entries_.size() == alloc_record_max_) {
+      delete entries_.front().second;
+      entries_.pop_front();
+    }
+    entries_.emplace_back(GcRoot<mirror::Object>(obj), record);
+  }
+
+  size_t Size() const SHARED_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    return entries_.size();
+  }
+
+  size_t GetRecentAllocationSize() const SHARED_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    CHECK_LE(recent_record_max_, alloc_record_max_);
+    size_t sz = entries_.size();
+    return std::min(recent_record_max_, sz);
+  }
+
+  void VisitRoots(RootVisitor* visitor)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
+
+  void SweepAllocationRecords(IsMarkedCallback* callback, void* arg)
+      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_);
+
+  // TODO: Is there a better way to hide the entries_'s type?
+  EntryList::iterator Begin()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    return entries_.begin();
+  }
+
+  EntryList::iterator End()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    return entries_.end();
+  }
+
+  EntryList::reverse_iterator RBegin()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    return entries_.rbegin();
+  }
+
+  EntryList::reverse_iterator REnd()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    return entries_.rend();
+  }
+
+ private:
+  static constexpr size_t kDefaultNumAllocRecords = 512 * 1024;
+  static constexpr size_t kDefaultNumRecentRecords = 64 * 1024 - 1;
+  static constexpr size_t kDefaultAllocStackDepth = 16;
+  static constexpr size_t kMaxSupportedStackDepth = 128;
+  size_t alloc_record_max_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  size_t recent_record_max_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  size_t max_stack_depth_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  AllocRecordStackTrace scratch_trace_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  pid_t alloc_ddm_thread_id_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  bool allow_new_record_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  ConditionVariable new_record_condition_ GUARDED_BY(Locks::alloc_tracker_lock_);
+  // see the comment in typedef of EntryList
+  EntryList entries_ GUARDED_BY(Locks::alloc_tracker_lock_);
+
+  void SetProperties() EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
+};
+
+}  // namespace gc
+}  // namespace art
+#endif  // ART_RUNTIME_GC_ALLOCATION_RECORD_H_
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 658390d..ccf5154 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -19,6 +19,7 @@
 #include "art_field-inl.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"
@@ -334,6 +335,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 +354,7 @@
     TimingLogger::ScopedTiming split5("VisitNonThreadRoots", GetTimings());
     Runtime::Current()->VisitNonThreadRoots(this);
   }
+  Runtime::Current()->GetHeap()->VisitAllocationRecords(this);
 
   // Immune spaces.
   for (auto& space : heap_->GetContinuousSpaces()) {
@@ -412,6 +416,11 @@
     // the mark stack here once again.
     ProcessMarkStack();
     CheckEmptyMarkQueue();
+    if (kVerboseMode) {
+      LOG(INFO) << "AllowNewSystemWeaks";
+    }
+    Runtime::Current()->AllowNewSystemWeaks();
+    IssueEmptyCheckpoint();
     // Disable marking.
     if (kUseTableLookupReadBarrier) {
       heap_->rb_table_->ClearAll();
@@ -419,10 +428,6 @@
     }
     is_mark_queue_push_disallowed_.StoreSequentiallyConsistent(1);
     is_marking_ = false;
-    if (kVerboseMode) {
-      LOG(INFO) << "AllowNewSystemWeaks";
-    }
-    Runtime::Current()->AllowNewSystemWeaks();
     CheckEmptyMarkQueue();
   }
 
@@ -1002,97 +1007,167 @@
     } else if (region_space_->IsInFromSpace(ref)) {
       // Not OK. Do extra logging.
       if (obj != nullptr) {
-        if (kUseBakerReadBarrier) {
-          LOG(INFO) << "holder=" << obj << " " << PrettyTypeOf(obj)
-                    << " holder rb_ptr=" << obj->GetReadBarrierPointer();
-        } else {
-          LOG(INFO) << "holder=" << obj << " " << PrettyTypeOf(obj);
-        }
-        if (region_space_->IsInFromSpace(obj)) {
-          LOG(INFO) << "holder is in the from-space.";
-        } else if (region_space_->IsInToSpace(obj)) {
-          LOG(INFO) << "holder is in the to-space.";
-        } else if (region_space_->IsInUnevacFromSpace(obj)) {
-          LOG(INFO) << "holder is in the unevac from-space.";
-          if (region_space_bitmap_->Test(obj)) {
-            LOG(INFO) << "holder is marked in the region space bitmap.";
-          } else {
-            LOG(INFO) << "holder is not marked in the region space bitmap.";
-          }
-        } else {
-          // In a non-moving space.
-          if (immune_region_.ContainsObject(obj)) {
-            LOG(INFO) << "holder is in the image or the zygote space.";
-            accounting::ContinuousSpaceBitmap* cc_bitmap =
-                cc_heap_bitmap_->GetContinuousSpaceBitmap(obj);
-            CHECK(cc_bitmap != nullptr)
-                << "An immune space object must have a bitmap.";
-            if (cc_bitmap->Test(obj)) {
-              LOG(INFO) << "holder is marked in the bit map.";
-            } else {
-              LOG(INFO) << "holder is NOT marked in the bit map.";
-            }
-          } else {
-            LOG(INFO) << "holder is in a non-moving (or main) space.";
-            accounting::ContinuousSpaceBitmap* mark_bitmap =
-                heap_mark_bitmap_->GetContinuousSpaceBitmap(obj);
-            accounting::LargeObjectBitmap* los_bitmap =
-                heap_mark_bitmap_->GetLargeObjectBitmap(obj);
-            CHECK(los_bitmap != nullptr) << "LOS bitmap covers the entire address range";
-            bool is_los = mark_bitmap == nullptr;
-            if (!is_los && mark_bitmap->Test(obj)) {
-              LOG(INFO) << "holder is marked in the mark bit map.";
-            } else if (is_los && los_bitmap->Test(obj)) {
-              LOG(INFO) << "holder is marked in the los bit map.";
-            } else {
-              // If ref is on the allocation stack, then it is considered
-              // mark/alive (but not necessarily on the live stack.)
-              if (IsOnAllocStack(obj)) {
-                LOG(INFO) << "holder is on the alloc stack.";
-              } else {
-                LOG(INFO) << "holder is not marked or on the alloc stack.";
-              }
-            }
-          }
-        }
-        LOG(INFO) << "offset=" << offset.SizeValue();
+        LogFromSpaceRefHolder(obj, offset);
       }
+      ref->GetLockWord(false).Dump(LOG(INTERNAL_FATAL));
       CHECK(false) << "Found from-space ref " << ref << " " << PrettyTypeOf(ref);
     } else {
-      // In a non-moving spaces. Check that the ref is marked.
-      if (immune_region_.ContainsObject(ref)) {
-        accounting::ContinuousSpaceBitmap* cc_bitmap =
-            cc_heap_bitmap_->GetContinuousSpaceBitmap(ref);
-        CHECK(cc_bitmap != nullptr)
-            << "An immune space ref must have a bitmap. " << ref;
-        if (kUseBakerReadBarrier) {
-          CHECK(cc_bitmap->Test(ref))
-              << "Unmarked immune space ref. obj=" << obj << " rb_ptr="
-              << obj->GetReadBarrierPointer() << " ref=" << ref;
-        } else {
-          CHECK(cc_bitmap->Test(ref))
-              << "Unmarked immune space ref. obj=" << obj << " ref=" << ref;
-        }
+      AssertToSpaceInvariantInNonMovingSpace(obj, ref);
+    }
+  }
+}
+
+class RootPrinter {
+ public:
+  RootPrinter() { }
+
+  template <class MirrorType>
+  ALWAYS_INLINE void VisitRootIfNonNull(mirror::CompressedReference<MirrorType>* root)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (!root->IsNull()) {
+      VisitRoot(root);
+    }
+  }
+
+  template <class MirrorType>
+  void VisitRoot(mirror::Object** root)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    LOG(INTERNAL_FATAL) << "root=" << root << " ref=" << *root;
+  }
+
+  template <class MirrorType>
+  void VisitRoot(mirror::CompressedReference<MirrorType>* root)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    LOG(INTERNAL_FATAL) << "root=" << root << " ref=" << root->AsMirrorPtr();
+  }
+};
+
+void ConcurrentCopying::AssertToSpaceInvariant(GcRootSource* gc_root_source,
+                                               mirror::Object* ref) {
+  CHECK(heap_->collector_type_ == kCollectorTypeCC) << static_cast<size_t>(heap_->collector_type_);
+  if (is_asserting_to_space_invariant_) {
+    if (region_space_->IsInToSpace(ref)) {
+      // OK.
+      return;
+    } else if (region_space_->IsInUnevacFromSpace(ref)) {
+      CHECK(region_space_bitmap_->Test(ref)) << ref;
+    } else if (region_space_->IsInFromSpace(ref)) {
+      // Not OK. Do extra logging.
+      if (gc_root_source == nullptr) {
+        // No info.
+      } else if (gc_root_source->HasArtField()) {
+        ArtField* field = gc_root_source->GetArtField();
+        LOG(INTERNAL_FATAL) << "gc root in field " << field << " " << PrettyField(field);
+        RootPrinter root_printer;
+        field->VisitRoots(root_printer);
+      } else if (gc_root_source->HasArtMethod()) {
+        ArtMethod* method = gc_root_source->GetArtMethod();
+        LOG(INTERNAL_FATAL) << "gc root in method " << method << " " << PrettyMethod(method);
+        RootPrinter root_printer;
+        method->VisitRoots(root_printer);
+      }
+      ref->GetLockWord(false).Dump(LOG(INTERNAL_FATAL));
+      region_space_->DumpNonFreeRegions(LOG(INTERNAL_FATAL));
+      PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
+      MemMap::DumpMaps(LOG(INTERNAL_FATAL), true);
+      CHECK(false) << "Found from-space ref " << ref << " " << PrettyTypeOf(ref);
+    } else {
+      AssertToSpaceInvariantInNonMovingSpace(nullptr, ref);
+    }
+  }
+}
+
+void ConcurrentCopying::LogFromSpaceRefHolder(mirror::Object* obj, MemberOffset offset) {
+  if (kUseBakerReadBarrier) {
+    LOG(INFO) << "holder=" << obj << " " << PrettyTypeOf(obj)
+              << " holder rb_ptr=" << obj->GetReadBarrierPointer();
+  } else {
+    LOG(INFO) << "holder=" << obj << " " << PrettyTypeOf(obj);
+  }
+  if (region_space_->IsInFromSpace(obj)) {
+    LOG(INFO) << "holder is in the from-space.";
+  } else if (region_space_->IsInToSpace(obj)) {
+    LOG(INFO) << "holder is in the to-space.";
+  } else if (region_space_->IsInUnevacFromSpace(obj)) {
+    LOG(INFO) << "holder is in the unevac from-space.";
+    if (region_space_bitmap_->Test(obj)) {
+      LOG(INFO) << "holder is marked in the region space bitmap.";
+    } else {
+      LOG(INFO) << "holder is not marked in the region space bitmap.";
+    }
+  } else {
+    // In a non-moving space.
+    if (immune_region_.ContainsObject(obj)) {
+      LOG(INFO) << "holder is in the image or the zygote space.";
+      accounting::ContinuousSpaceBitmap* cc_bitmap =
+          cc_heap_bitmap_->GetContinuousSpaceBitmap(obj);
+      CHECK(cc_bitmap != nullptr)
+          << "An immune space object must have a bitmap.";
+      if (cc_bitmap->Test(obj)) {
+        LOG(INFO) << "holder is marked in the bit map.";
       } else {
-        accounting::ContinuousSpaceBitmap* mark_bitmap =
-            heap_mark_bitmap_->GetContinuousSpaceBitmap(ref);
-        accounting::LargeObjectBitmap* los_bitmap =
-            heap_mark_bitmap_->GetLargeObjectBitmap(ref);
-        CHECK(los_bitmap != nullptr) << "LOS bitmap covers the entire address range";
-        bool is_los = mark_bitmap == nullptr;
-        if ((!is_los && mark_bitmap->Test(ref)) ||
-            (is_los && los_bitmap->Test(ref))) {
-          // OK.
+        LOG(INFO) << "holder is NOT marked in the bit map.";
+      }
+    } else {
+      LOG(INFO) << "holder is in a non-moving (or main) space.";
+      accounting::ContinuousSpaceBitmap* mark_bitmap =
+          heap_mark_bitmap_->GetContinuousSpaceBitmap(obj);
+      accounting::LargeObjectBitmap* los_bitmap =
+          heap_mark_bitmap_->GetLargeObjectBitmap(obj);
+      CHECK(los_bitmap != nullptr) << "LOS bitmap covers the entire address range";
+      bool is_los = mark_bitmap == nullptr;
+      if (!is_los && mark_bitmap->Test(obj)) {
+        LOG(INFO) << "holder is marked in the mark bit map.";
+      } else if (is_los && los_bitmap->Test(obj)) {
+        LOG(INFO) << "holder is marked in the los bit map.";
+      } else {
+        // If ref is on the allocation stack, then it is considered
+        // mark/alive (but not necessarily on the live stack.)
+        if (IsOnAllocStack(obj)) {
+          LOG(INFO) << "holder is on the alloc stack.";
         } else {
-          // If ref is on the allocation stack, then it may not be
-          // marked live, but considered marked/alive (but not
-          // necessarily on the live stack).
-          CHECK(IsOnAllocStack(ref)) << "Unmarked ref that's not on the allocation stack. "
-                                     << "obj=" << obj << " ref=" << ref;
+          LOG(INFO) << "holder is not marked or on the alloc stack.";
         }
       }
     }
   }
+  LOG(INFO) << "offset=" << offset.SizeValue();
+}
+
+void ConcurrentCopying::AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj,
+                                                               mirror::Object* ref) {
+  // In a non-moving spaces. Check that the ref is marked.
+  if (immune_region_.ContainsObject(ref)) {
+    accounting::ContinuousSpaceBitmap* cc_bitmap =
+        cc_heap_bitmap_->GetContinuousSpaceBitmap(ref);
+    CHECK(cc_bitmap != nullptr)
+        << "An immune space ref must have a bitmap. " << ref;
+    if (kUseBakerReadBarrier) {
+      CHECK(cc_bitmap->Test(ref))
+          << "Unmarked immune space ref. obj=" << obj << " rb_ptr="
+          << obj->GetReadBarrierPointer() << " ref=" << ref;
+    } else {
+      CHECK(cc_bitmap->Test(ref))
+          << "Unmarked immune space ref. obj=" << obj << " ref=" << ref;
+    }
+  } else {
+    accounting::ContinuousSpaceBitmap* mark_bitmap =
+        heap_mark_bitmap_->GetContinuousSpaceBitmap(ref);
+    accounting::LargeObjectBitmap* los_bitmap =
+        heap_mark_bitmap_->GetLargeObjectBitmap(ref);
+    CHECK(los_bitmap != nullptr) << "LOS bitmap covers the entire address range";
+    bool is_los = mark_bitmap == nullptr;
+    if ((!is_los && mark_bitmap->Test(ref)) ||
+        (is_los && los_bitmap->Test(ref))) {
+      // OK.
+    } else {
+      // If ref is on the allocation stack, then it may not be
+      // marked live, but considered marked/alive (but not
+      // necessarily on the live stack).
+      CHECK(IsOnAllocStack(ref)) << "Unmarked ref that's not on the allocation stack. "
+                                 << "obj=" << obj << " ref=" << ref;
+    }
+  }
 }
 
 // Used to scan ref fields of an object.
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 60ea6b6..b1897b8 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -169,6 +169,8 @@
   }
   void AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset, mirror::Object* ref)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void AssertToSpaceInvariant(GcRootSource* gc_root_source, mirror::Object* ref)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsInToSpace(mirror::Object* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(ref != nullptr);
     return IsMarked(ref) == ref;
@@ -236,6 +238,10 @@
   void SwapStacks(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void RecordLiveStackFreezeSize(Thread* self);
   void ComputeUnevacFromSpaceLiveRatio();
+  void LogFromSpaceRefHolder(mirror::Object* obj, MemberOffset offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj, mirror::Object* ref)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   space::RegionSpace* region_space_;      // The underlying region space.
   std::unique_ptr<Barrier> gc_barrier_;
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_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 2ec9c86..2e66160 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -22,6 +22,7 @@
 #include "base/time_utils.h"
 #include "debugger.h"
 #include "gc/accounting/card_table-inl.h"
+#include "gc/allocation_record.h"
 #include "gc/collector/semi_space.h"
 #include "gc/space/bump_pointer_space-inl.h"
 #include "gc/space/dlmalloc_space-inl.h"
@@ -168,11 +169,12 @@
     PushOnAllocationStack(self, &obj);
   }
   if (kInstrumented) {
-    if (Dbg::IsAllocTrackingEnabled()) {
-      Dbg::RecordAllocation(self, klass, bytes_allocated);
+    if (IsAllocTrackingEnabled()) {
+      // Use obj->GetClass() instead of klass, because PushOnAllocationStack() could move klass
+      AllocRecordObjectMap::RecordAllocation(self, obj, obj->GetClass(), bytes_allocated);
     }
   } else {
-    DCHECK(!Dbg::IsAllocTrackingEnabled());
+    DCHECK(!IsAllocTrackingEnabled());
   }
   if (kInstrumented) {
     if (gc_stress_mode_) {
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index d428267..26a45d3 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"
@@ -213,6 +211,7 @@
       gc_count_rate_histogram_("gc count rate histogram", 1U, kGcCountRateMaxBucketCount),
       blocking_gc_count_rate_histogram_("blocking gc count rate histogram", 1U,
                                         kGcCountRateMaxBucketCount),
+      alloc_tracking_enabled_(false),
       backtrace_lock_(nullptr),
       seen_backtrace_count_(0u),
       unique_backtrace_count_(0u) {
@@ -466,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());
@@ -1076,6 +1076,7 @@
   STLDeleteElements(&garbage_collectors_);
   // If we don't reset then the mark stack complains in its destructor.
   allocation_stack_->Reset();
+  allocation_records_.reset();
   live_stack_->Reset();
   STLDeleteValues(&mod_union_tables_);
   STLDeleteValues(&remembered_sets_);
@@ -1863,7 +1864,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);
@@ -1996,7 +1997,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);
@@ -2470,7 +2471,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);
@@ -3692,6 +3693,46 @@
   }
 }
 
+void Heap::SetAllocationRecords(AllocRecordObjectMap* records) {
+  allocation_records_.reset(records);
+}
+
+void Heap::VisitAllocationRecords(RootVisitor* visitor) const {
+  if (IsAllocTrackingEnabled()) {
+    MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
+    if (IsAllocTrackingEnabled()) {
+      GetAllocationRecords()->VisitRoots(visitor);
+    }
+  }
+}
+
+void Heap::SweepAllocationRecords(IsMarkedCallback* visitor, void* arg) const {
+  if (IsAllocTrackingEnabled()) {
+    MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
+    if (IsAllocTrackingEnabled()) {
+      GetAllocationRecords()->SweepAllocationRecords(visitor, arg);
+    }
+  }
+}
+
+void Heap::AllowNewAllocationRecords() const {
+  if (IsAllocTrackingEnabled()) {
+    MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
+    if (IsAllocTrackingEnabled()) {
+      GetAllocationRecords()->AllowNewAllocationRecords();
+    }
+  }
+}
+
+void Heap::DisallowNewAllocationRecords() const {
+  if (IsAllocTrackingEnabled()) {
+    MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
+    if (IsAllocTrackingEnabled()) {
+      GetAllocationRecords()->DisallowNewAllocationRecords();
+    }
+  }
+}
+
 // 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 81476a4..d0040f2 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 {
@@ -59,6 +55,7 @@
 
 namespace gc {
 
+class AllocRecordObjectMap;
 class ReferenceProcessor;
 class TaskProcessor;
 
@@ -630,7 +627,7 @@
   bool HasImageSpace() const;
 
   ReferenceProcessor* GetReferenceProcessor() {
-    return &reference_processor_;
+    return reference_processor_.get();
   }
   TaskProcessor* GetTaskProcessor() {
     return task_processor_.get();
@@ -686,6 +683,40 @@
   void DumpGcCountRateHistogram(std::ostream& os) const;
   void DumpBlockingGcCountRateHistogram(std::ostream& os) const;
 
+  // Allocation tracking support
+  // Callers to this function use double-checked locking to ensure safety on allocation_records_
+  bool IsAllocTrackingEnabled() const {
+    return alloc_tracking_enabled_.LoadRelaxed();
+  }
+
+  void SetAllocTrackingEnabled(bool enabled) EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    alloc_tracking_enabled_.StoreRelaxed(enabled);
+  }
+
+  AllocRecordObjectMap* GetAllocationRecords() const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_) {
+    return allocation_records_.get();
+  }
+
+  void SetAllocationRecords(AllocRecordObjectMap* records)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
+
+  void VisitAllocationRecords(RootVisitor* visitor) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
+
+  void SweepAllocationRecords(IsMarkedCallback* visitor, void* arg) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
+
+  void DisallowNewAllocationRecords() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
+
+  void AllowNewAllocationRecords() const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
+
  private:
   class ConcurrentGCTask;
   class CollectorTransitionTask;
@@ -980,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_;
@@ -1199,6 +1230,11 @@
   // The histogram of the number of blocking GC invocations per window duration.
   Histogram<uint64_t> blocking_gc_count_rate_histogram_ GUARDED_BY(gc_complete_lock_);
 
+  // Allocation tracking support
+  Atomic<bool> alloc_tracking_enabled_;
+  std::unique_ptr<AllocRecordObjectMap> allocation_records_
+      GUARDED_BY(Locks::alloc_tracker_lock_);
+
   // GC stress related data structures.
   Mutex* backtrace_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   // Debugging variables, seen backtraces vs unique backtraces.
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 52192e2..2b567fe 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"
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 5f3a1db..9495864 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -20,8 +20,6 @@
 #include "space.h"
 
 #include <ostream>
-#include <valgrind.h>
-#include <memcheck/memcheck.h>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h
index 25d4445..f94ec23 100644
--- a/runtime/gc/space/rosalloc_space-inl.h
+++ b/runtime/gc/space/rosalloc_space-inl.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 #define ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 
+#include <valgrind.h>
+
 #include "gc/allocator/rosalloc-inl.h"
 #include "gc/space/valgrind_settings.h"
 #include "rosalloc_space.h"
diff --git a/runtime/gc_root-inl.h b/runtime/gc_root-inl.h
index 57d5689..ae8a38f 100644
--- a/runtime/gc_root-inl.h
+++ b/runtime/gc_root-inl.h
@@ -27,9 +27,9 @@
 
 template<class MirrorType>
 template<ReadBarrierOption kReadBarrierOption>
-inline MirrorType* GcRoot<MirrorType>::Read() const {
+inline MirrorType* GcRoot<MirrorType>::Read(GcRootSource* gc_root_source) const {
   return down_cast<MirrorType*>(
-      ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(&root_));
+      ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(&root_, gc_root_source));
 }
 template<class MirrorType>
 inline GcRoot<MirrorType>::GcRoot(MirrorType* ref)
diff --git a/runtime/gc_root.h b/runtime/gc_root.h
index b67e9c2..bb604f0 100644
--- a/runtime/gc_root.h
+++ b/runtime/gc_root.h
@@ -22,6 +22,8 @@
 #include "mirror/object_reference.h"
 
 namespace art {
+class ArtField;
+class ArtMethod;
 
 namespace mirror {
 class Object;
@@ -44,7 +46,9 @@
   kRootMonitorUsed,
   kRootThreadObject,
   kRootInternedString,
+  kRootFinalizing,  // used for HPROF's conversion to HprofHeapTag
   kRootDebugger,
+  kRootReferenceCleanup,  // used for HPROF's conversion to HprofHeapTag
   kRootVMInternal,
   kRootJNIMonitor,
 };
@@ -129,11 +133,43 @@
   virtual void VisitRoot(mirror::Object* root, const RootInfo& info) = 0;
 };
 
+class GcRootSource {
+ public:
+  GcRootSource()
+      : field_(nullptr), method_(nullptr) {
+  }
+  explicit GcRootSource(ArtField* field)
+      : field_(field), method_(nullptr) {
+  }
+  explicit GcRootSource(ArtMethod* method)
+      : field_(nullptr), method_(method) {
+  }
+  ArtField* GetArtField() const {
+    return field_;
+  }
+  ArtMethod* GetArtMethod() const {
+    return method_;
+  }
+  bool HasArtField() const {
+    return field_ != nullptr;
+  }
+  bool HasArtMethod() const {
+    return method_ != nullptr;
+  }
+
+ private:
+  ArtField* const field_;
+  ArtMethod* const method_;
+
+  DISALLOW_COPY_AND_ASSIGN(GcRootSource);
+};
+
 template<class MirrorType>
 class GcRoot {
  public:
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  ALWAYS_INLINE MirrorType* Read() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ALWAYS_INLINE MirrorType* Read(GcRootSource* gc_root_source = nullptr) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void VisitRoot(RootVisitor* visitor, const RootInfo& info) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/globals.h b/runtime/globals.h
index fe699c6..d70f3ab 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -97,7 +97,7 @@
     kUseTableLookupReadBarrier;
 
 // If true, references within the heap are poisoned (negated).
-#ifdef ART_HEAP_POISONING
+#ifdef USE_HEAP_POISONING
 static constexpr bool kPoisonHeapReferences = true;
 #else
 static constexpr bool kPoisonHeapReferences = false;
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index a2a4f0d..71a69aa 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -48,6 +48,7 @@
 #include "dex_file-inl.h"
 #include "gc_root.h"
 #include "gc/accounting/heap_bitmap.h"
+#include "gc/allocation_record.h"
 #include "gc/heap.h"
 #include "gc/space/space.h"
 #include "globals.h"
@@ -68,14 +69,13 @@
 static constexpr bool kDirectStream = true;
 
 static constexpr uint32_t kHprofTime = 0;
-static constexpr uint32_t kHprofNullStackTrace = 0;
 static constexpr uint32_t kHprofNullThread = 0;
 
 static constexpr size_t kMaxObjectsPerSegment = 128;
 static constexpr size_t kMaxBytesPerSegment = 4096;
 
 // The static field-name for the synthetic object generated to account for class static overhead.
-static constexpr const char* kStaticOverheadName = "$staticOverhead";
+static constexpr const char* kClassOverheadName = "$classOverhead";
 
 enum HprofTag {
   HPROF_TAG_STRING = 0x01,
@@ -144,6 +144,10 @@
 
 typedef uint32_t HprofStringId;
 typedef uint32_t HprofClassObjectId;
+typedef uint32_t HprofClassSerialNumber;
+typedef uint32_t HprofStackTraceSerialNumber;
+typedef uint32_t HprofStackFrameId;
+static constexpr HprofStackTraceSerialNumber kHprofNullStackTrace = 0;
 
 class EndianOutput {
  public:
@@ -194,6 +198,10 @@
     AddU4(PointerToLowMemUInt32(value));
   }
 
+  void AddStackTraceSerialNumber(HprofStackTraceSerialNumber value) {
+    AddU4(value);
+  }
+
   // The ID for the synthetic object generated to account for class static overhead.
   void AddClassStaticsId(const mirror::Class* value) {
     AddU4(1 | PointerToLowMemUInt32(value));
@@ -415,13 +423,21 @@
         start_ns_(NanoTime()),
         current_heap_(HPROF_HEAP_DEFAULT),
         objects_in_segment_(0),
-        next_string_id_(0x400000) {
+        next_string_id_(0x400000),
+        next_class_serial_number_(1) {
     LOG(INFO) << "hprof: heap dump \"" << filename_ << "\" starting...";
   }
 
   void Dump()
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_)
-      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_) {
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_, Locks::alloc_tracker_lock_) {
+    {
+      MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
+      if (Runtime::Current()->GetHeap()->IsAllocTrackingEnabled()) {
+        PopulateAllocationTrackingTraces();
+      }
+    }
+
     // First pass to measure the size of the dump.
     size_t overall_size;
     size_t max_length;
@@ -480,11 +496,11 @@
     objects_in_segment_ = 0;
 
     if (header_first) {
-      ProcessHeader();
+      ProcessHeader(true);
       ProcessBody();
     } else {
       ProcessBody();
-      ProcessHeader();
+      ProcessHeader(false);
     }
   }
 
@@ -501,21 +517,29 @@
     output_->EndRecord();
   }
 
-  void ProcessHeader() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  void ProcessHeader(bool string_first) EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Write the header.
     WriteFixedHeader();
     // Write the string and class tables, and any stack traces, to the header.
     // (jhat requires that these appear before any of the data in the body that refers to them.)
-    WriteStringTable();
+    // jhat also requires the string table appear before class table and stack traces.
+    // However, WriteStackTraces() can modify the string table, so it's necessary to call
+    // WriteStringTable() last in the first pass, to compute the correct length of the output.
+    if (string_first) {
+      WriteStringTable();
+    }
     WriteClassTable();
     WriteStackTraces();
+    if (!string_first) {
+      WriteStringTable();
+    }
     output_->EndRecord();
   }
 
   void WriteClassTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    uint32_t nextSerialNumber = 1;
-
-    for (mirror::Class* c : classes_) {
+    for (const auto& p : classes_) {
+      mirror::Class* c = p.first;
+      HprofClassSerialNumber sn = p.second;
       CHECK(c != nullptr);
       output_->StartNewRecord(HPROF_TAG_LOAD_CLASS, kHprofTime);
       // LOAD CLASS format:
@@ -523,9 +547,9 @@
       // ID: class object ID. We use the address of the class object structure as its ID.
       // U4: stack trace serial number
       // ID: class name string ID
-      __ AddU4(nextSerialNumber++);
+      __ AddU4(sn);
       __ AddObjectId(c);
-      __ AddU4(kHprofNullStackTrace);
+      __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(c));
       __ AddStringId(LookupClassNameId(c));
     }
   }
@@ -567,15 +591,31 @@
 
   HprofClassObjectId LookupClassId(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     if (c != nullptr) {
-      auto result = classes_.insert(c);
-      const mirror::Class* present = *result.first;
-      CHECK_EQ(present, c);
-      // Make sure that we've assigned a string ID for this class' name
-      LookupClassNameId(c);
+      auto it = classes_.find(c);
+      if (it == classes_.end()) {
+        // first time to see this class
+        HprofClassSerialNumber sn = next_class_serial_number_++;
+        classes_.Put(c, sn);
+        // Make sure that we've assigned a string ID for this class' name
+        LookupClassNameId(c);
+      }
     }
     return PointerToLowMemUInt32(c);
   }
 
+  HprofStackTraceSerialNumber LookupStackTraceSerialNumber(const mirror::Object* obj)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    auto r = allocation_records_.find(obj);
+    if (r == allocation_records_.end()) {
+      return kHprofNullStackTrace;
+    } else {
+      const gc::AllocRecordStackTrace* trace = r->second;
+      auto result = traces_.find(trace);
+      CHECK(result != traces_.end());
+      return result->second;
+    }
+  }
+
   HprofStringId LookupStringId(mirror::String* string) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return LookupStringId(string->ToModifiedUtf8());
   }
@@ -622,12 +662,66 @@
     __ AddU4(static_cast<uint32_t>(nowMs & 0xFFFFFFFF));
   }
 
-  void WriteStackTraces() {
+  void WriteStackTraces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Write a dummy stack trace record so the analysis tools don't freak out.
     output_->StartNewRecord(HPROF_TAG_STACK_TRACE, kHprofTime);
-    __ AddU4(kHprofNullStackTrace);
+    __ AddStackTraceSerialNumber(kHprofNullStackTrace);
     __ AddU4(kHprofNullThread);
     __ AddU4(0);    // no frames
+
+    // TODO: jhat complains "WARNING: Stack trace not found for serial # -1", but no trace should
+    // have -1 as its serial number (as long as HprofStackTraceSerialNumber doesn't overflow).
+    for (const auto& it : traces_) {
+      const gc::AllocRecordStackTrace* trace = it.first;
+      HprofStackTraceSerialNumber trace_sn = it.second;
+      size_t depth = trace->GetDepth();
+
+      // First write stack frames of the trace
+      for (size_t i = 0; i < depth; ++i) {
+        const gc::AllocRecordStackTraceElement* frame = &trace->GetStackElement(i);
+        ArtMethod* method = frame->GetMethod();
+        CHECK(method != nullptr);
+        output_->StartNewRecord(HPROF_TAG_STACK_FRAME, kHprofTime);
+        // STACK FRAME format:
+        // ID: stack frame ID. We use the address of the AllocRecordStackTraceElement object as its ID.
+        // ID: method name string ID
+        // ID: method signature string ID
+        // ID: source file name string ID
+        // U4: class serial number
+        // U4: >0, line number; 0, no line information available; -1, unknown location
+        auto frame_result = frames_.find(frame);
+        CHECK(frame_result != frames_.end());
+        __ AddU4(frame_result->second);
+        __ AddStringId(LookupStringId(method->GetName()));
+        __ AddStringId(LookupStringId(method->GetSignature().ToString()));
+        const char* source_file = method->GetDeclaringClassSourceFile();
+        if (source_file == nullptr) {
+          source_file = "";
+        }
+        __ AddStringId(LookupStringId(source_file));
+        auto class_result = classes_.find(method->GetDeclaringClass());
+        CHECK(class_result != classes_.end());
+        __ AddU4(class_result->second);
+        __ AddU4(frame->ComputeLineNumber());
+      }
+
+      // Then write the trace itself
+      output_->StartNewRecord(HPROF_TAG_STACK_TRACE, kHprofTime);
+      // STACK TRACE format:
+      // U4: stack trace serial number. We use the address of the AllocRecordStackTrace object as its serial number.
+      // U4: thread serial number. We use Thread::GetTid().
+      // U4: number of frames
+      // [ID]*: series of stack frame ID's
+      __ AddStackTraceSerialNumber(trace_sn);
+      __ AddU4(trace->GetTid());
+      __ AddU4(depth);
+      for (size_t i = 0; i < depth; ++i) {
+        const gc::AllocRecordStackTraceElement* frame = &trace->GetStackElement(i);
+        auto frame_result = frames_.find(frame);
+        CHECK(frame_result != frames_.end());
+        __ AddU4(frame_result->second);
+      }
+    }
   }
 
   bool DumpToDdmsBuffered(size_t overall_size ATTRIBUTE_UNUSED, size_t max_length ATTRIBUTE_UNUSED)
@@ -723,6 +817,46 @@
     return true;
   }
 
+  void PopulateAllocationTrackingTraces()
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::alloc_tracker_lock_) {
+    gc::AllocRecordObjectMap* records = Runtime::Current()->GetHeap()->GetAllocationRecords();
+    CHECK(records != nullptr);
+    HprofStackTraceSerialNumber next_trace_sn = kHprofNullStackTrace + 1;
+    HprofStackFrameId next_frame_id = 0;
+    size_t count = 0;
+
+    for (auto it = records->Begin(), end = records->End(); it != end; ++it) {
+      const mirror::Object* obj = it->first.Read();
+      if (obj == nullptr) {
+        continue;
+      }
+      ++count;
+      const gc::AllocRecordStackTrace* trace = it->second->GetStackTrace();
+
+      // Copy the pair into a real hash map to speed up look up.
+      auto records_result = allocation_records_.emplace(obj, trace);
+      // The insertion should always succeed, i.e. no duplicate object pointers in "records"
+      CHECK(records_result.second);
+
+      // Generate serial numbers for traces, and IDs for frames.
+      auto traces_result = traces_.find(trace);
+      if (traces_result == traces_.end()) {
+        traces_.emplace(trace, next_trace_sn++);
+        // only check frames if the trace is newly discovered
+        for (size_t i = 0, depth = trace->GetDepth(); i < depth; ++i) {
+          const gc::AllocRecordStackTraceElement* frame = &trace->GetStackElement(i);
+          auto frames_result = frames_.find(frame);
+          if (frames_result == frames_.end()) {
+            frames_.emplace(frame, next_frame_id++);
+          }
+        }
+      }
+    }
+    CHECK_EQ(traces_.size(), next_trace_sn - kHprofNullStackTrace - 1);
+    CHECK_EQ(frames_.size(), next_frame_id);
+    VLOG(heap) << "hprof: found " << count << " objects with allocation stack traces";
+  }
+
   // If direct_to_ddms_ is set, "filename_" and "fd" will be ignored.
   // Otherwise, "filename_" must be valid, though if "fd" >= 0 it will
   // only be used for debug messages.
@@ -737,9 +871,18 @@
   HprofHeapId current_heap_;  // Which heap we're currently dumping.
   size_t objects_in_segment_;
 
-  std::set<mirror::Class*> classes_;
   HprofStringId next_string_id_;
   SafeMap<std::string, HprofStringId> strings_;
+  HprofClassSerialNumber next_class_serial_number_;
+  SafeMap<mirror::Class*, HprofClassSerialNumber> classes_;
+
+  std::unordered_map<const gc::AllocRecordStackTrace*, HprofStackTraceSerialNumber,
+                     gc::HashAllocRecordTypesPtr<gc::AllocRecordStackTrace>,
+                     gc::EqAllocRecordTypesPtr<gc::AllocRecordStackTrace>> traces_;
+  std::unordered_map<const gc::AllocRecordStackTraceElement*, HprofStackFrameId,
+                     gc::HashAllocRecordTypesPtr<gc::AllocRecordStackTraceElement>,
+                     gc::EqAllocRecordTypesPtr<gc::AllocRecordStackTraceElement>> frames_;
+  std::unordered_map<const mirror::Object*, const gc::AllocRecordStackTrace*> allocation_records_;
 
   DISALLOW_COPY_AND_ASSIGN(Hprof);
 };
@@ -881,10 +1024,6 @@
   ++objects_in_segment_;
 }
 
-static int StackTraceSerialNumber(const mirror::Object* /*obj*/) {
-  return kHprofNullStackTrace;
-}
-
 void Hprof::DumpHeapObject(mirror::Object* obj) {
   // Ignore classes that are retired.
   if (obj->IsClass() && obj->AsClass()->IsRetired()) {
@@ -959,24 +1098,30 @@
     // Class is allocated but not yet loaded: we cannot access its fields or super class.
     return;
   }
-  size_t sFieldCount = klass->NumStaticFields();
-  if (sFieldCount != 0) {
-    int byteLength = sFieldCount * sizeof(JValue);  // TODO bogus; fields are packed
+  const size_t num_static_fields = klass->NumStaticFields();
+  // Total class size including embedded IMT, embedded vtable, and static fields.
+  const size_t class_size = klass->GetClassSize();
+  // Class size excluding static fields (relies on reference fields being the first static fields).
+  const size_t class_size_without_overhead = sizeof(mirror::Class);
+  CHECK_LE(class_size_without_overhead, class_size);
+  const size_t overhead_size = class_size - class_size_without_overhead;
+
+  if (overhead_size != 0) {
     // Create a byte array to reflect the allocation of the
     // StaticField array at the end of this class.
     __ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
     __ AddClassStaticsId(klass);
-    __ AddU4(StackTraceSerialNumber(klass));
-    __ AddU4(byteLength);
+    __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(klass));
+    __ AddU4(overhead_size);
     __ AddU1(hprof_basic_byte);
-    for (int i = 0; i < byteLength; ++i) {
+    for (size_t i = 0; i < overhead_size; ++i) {
       __ AddU1(0);
     }
   }
 
   __ AddU1(HPROF_CLASS_DUMP);
   __ AddClassId(LookupClassId(klass));
-  __ AddU4(StackTraceSerialNumber(klass));
+  __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(klass));
   __ AddClassId(LookupClassId(klass->GetSuperClass()));
   __ AddObjectId(klass->GetClassLoader());
   __ AddObjectId(nullptr);    // no signer
@@ -986,7 +1131,7 @@
   if (klass->IsClassClass()) {
     // ClassObjects have their static fields appended, so aren't all the same size.
     // But they're at least this size.
-    __ AddU4(sizeof(mirror::Class));  // instance size
+    __ AddU4(class_size_without_overhead);  // instance size
   } else if (klass->IsStringClass()) {
     // Strings are variable length with character data at the end like arrays.
     // This outputs the size of an empty string.
@@ -1000,15 +1145,15 @@
   __ AddU2(0);  // empty const pool
 
   // Static fields
-  if (sFieldCount == 0) {
-    __ AddU2((uint16_t)0);
+  if (overhead_size == 0) {
+    __ AddU2(static_cast<uint16_t>(0));
   } else {
-    __ AddU2((uint16_t)(sFieldCount+1));
-    __ AddStringId(LookupStringId(kStaticOverheadName));
+    __ AddU2(static_cast<uint16_t>(num_static_fields + 1));
+    __ AddStringId(LookupStringId(kClassOverheadName));
     __ AddU1(hprof_basic_object);
     __ AddClassStaticsId(klass);
 
-    for (size_t i = 0; i < sFieldCount; ++i) {
+    for (size_t i = 0; i < num_static_fields; ++i) {
       ArtField* f = klass->GetStaticField(i);
 
       size_t size;
@@ -1072,7 +1217,7 @@
     __ AddU1(HPROF_OBJECT_ARRAY_DUMP);
 
     __ AddObjectId(obj);
-    __ AddU4(StackTraceSerialNumber(obj));
+    __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
     __ AddU4(length);
     __ AddClassId(LookupClassId(klass));
 
@@ -1087,7 +1232,7 @@
     __ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
 
     __ AddObjectId(obj);
-    __ AddU4(StackTraceSerialNumber(obj));
+    __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
     __ AddU4(length);
     __ AddU1(t);
 
@@ -1108,7 +1253,7 @@
   // obj is an instance object.
   __ AddU1(HPROF_INSTANCE_DUMP);
   __ AddObjectId(obj);
-  __ AddU4(StackTraceSerialNumber(obj));
+  __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
   __ AddClassId(LookupClassId(klass));
 
   // Reserve some space for the length of the instance data, which we won't
@@ -1175,7 +1320,7 @@
     mirror::String* s = obj->AsString();
     __ AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
     __ AddObjectId(string_value);
-    __ AddU4(StackTraceSerialNumber(obj));
+    __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
     __ AddU4(s->GetLength());
     __ AddU1(hprof_basic_char);
     __ AddU2List(s->GetValue(), s->GetLength());
diff --git a/runtime/indenter.h b/runtime/indenter.h
index d055d4e..38b398d 100644
--- a/runtime/indenter.h
+++ b/runtime/indenter.h
@@ -27,45 +27,76 @@
 class Indenter : public std::streambuf {
  public:
   Indenter(std::streambuf* out, char text, size_t count)
-      : indent_next_(true), out_sbuf_(out), text_(text), count_(count) {}
+      : indent_next_(true), out_sbuf_(out),
+        text_{text, text, text, text, text, text, text, text},  // NOLINT(whitespace/braces)
+        count_(count) {}
 
  private:
-  int_type overflow(int_type c) {
+  std::streamsize xsputn(const char* s, std::streamsize n) OVERRIDE {
+    std::streamsize result = n;  // Aborts on failure.
+    const char* eol = static_cast<const char*>(memchr(s, '\n', n));
+    while (eol != nullptr) {
+      size_t to_write = eol + 1 - s;
+      Write(s, to_write);
+      s += to_write;
+      n -= to_write;
+      indent_next_ = true;
+      eol = static_cast<const char*>(memchr(s, '\n', n));
+    }
+    if (n != 0u) {
+      Write(s, n);
+    }
+    return result;
+  }
+
+  int_type overflow(int_type c) OVERRIDE {
     if (UNLIKELY(c == std::char_traits<char>::eof())) {
       out_sbuf_->pubsync();
       return c;
     }
-    if (indent_next_) {
-      for (size_t i = 0; i < count_; ++i) {
-        int_type r = out_sbuf_->sputc(text_);
-        if (UNLIKELY(r != text_)) {
-          out_sbuf_->pubsync();
-          r = out_sbuf_->sputc(text_);
-          CHECK_EQ(r, text_) << "Error writing to buffer. Disk full?";
-        }
-      }
-    }
+    char data[1] = { static_cast<char>(c) };
+    Write(data, 1u);
     indent_next_ = (c == '\n');
-    int_type r = out_sbuf_->sputc(c);
-    if (UNLIKELY(r != c)) {
-      out_sbuf_->pubsync();
-      r = out_sbuf_->sputc(c);
-      CHECK_EQ(r, c) << "Error writing to buffer. Disk full?";
-    }
-    return r;
+    return c;
   }
 
   int sync() {
     return out_sbuf_->pubsync();
   }
 
+  void Write(const char* s, std::streamsize n) {
+    if (indent_next_) {
+      size_t remaining = count_;
+      while (remaining != 0u) {
+        size_t to_write = std::min(remaining, sizeof(text_));
+        RawWrite(text_, to_write);
+        remaining -= to_write;
+      }
+      indent_next_ = false;
+    }
+    RawWrite(s, n);
+  }
+
+  void RawWrite(const char* s, std::streamsize n) {
+    size_t written = out_sbuf_->sputn(s, n);
+    s += written;
+    n -= written;
+    while (n != 0u) {
+      out_sbuf_->pubsync();
+      written = out_sbuf_->sputn(s, n);
+      CHECK_NE(written, 0u) << "Error writing to buffer. Disk full?";
+      s += written;
+      n -= written;
+    }
+  }
+
   bool indent_next_;
 
   // Buffer to write output to.
   std::streambuf* const out_sbuf_;
 
   // Text output as indent.
-  const char text_;
+  const char text_[8];
 
   // Number of times text is output.
   const size_t count_;
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/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index a245890..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"
@@ -450,10 +451,13 @@
 static inline void AssignRegister(ShadowFrame* new_shadow_frame, const ShadowFrame& shadow_frame,
                                   size_t dest_reg, size_t src_reg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  // If both register locations contains the same value, the register probably holds a reference.
   // Uint required, so that sign extension does not make this wrong on 64b systems
   uint32_t src_value = shadow_frame.GetVReg(src_reg);
   mirror::Object* o = shadow_frame.GetVRegReference<kVerifyNone>(src_reg);
+
+  // If both register locations contains the same value, the register probably holds a reference.
+  // Note: As an optimization, non-moving collectors leave a stale reference value
+  // in the references array even after the original vreg was overwritten to a non-reference.
   if (src_value == reinterpret_cast<uintptr_t>(o)) {
     new_shadow_frame->SetVRegReference(dest_reg, o);
   } else {
@@ -477,12 +481,45 @@
   Runtime::Current()->AbortTransactionAndThrowAbortError(self, abort_msg);
 }
 
+// Separate declaration is required solely for the attributes.
+template<bool is_range, bool do_assignability_check> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+static inline bool DoCallCommon(ArtMethod* called_method,
+                                Thread* self,
+                                ShadowFrame& shadow_frame,
+                                JValue* result,
+                                uint16_t number_of_inputs,
+                                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>
-bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
-            const Instruction* inst, uint16_t inst_data, JValue* result) {
+static inline bool DoCallCommon(ArtMethod* called_method,
+                                Thread* self,
+                                ShadowFrame& shadow_frame,
+                                JValue* result,
+                                uint16_t number_of_inputs,
+                                uint32_t arg[Instruction::kMaxVarArgRegs],
+                                uint32_t vregC) {
   bool string_init = false;
   // Replace calls to String.<init> with equivalent StringFactory call.
-  if (called_method->GetDeclaringClass()->IsStringClass() && called_method->IsConstructor()) {
+  if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass()
+               && called_method->IsConstructor())) {
     ScopedObjectAccessUnchecked soa(self);
     jmethodID mid = soa.EncodeMethod(called_method);
     called_method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
@@ -491,28 +528,58 @@
 
   // Compute method information.
   const DexFile::CodeItem* code_item = called_method->GetCodeItem();
-  const uint16_t num_ins = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
+
+  // Number of registers for the callee's call frame.
   uint16_t num_regs;
   if (LIKELY(code_item != nullptr)) {
     num_regs = code_item->registers_size_;
-    DCHECK_EQ(string_init ? num_ins - 1 : num_ins, code_item->ins_size_);
+    DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
   } else {
     DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
-    num_regs = num_ins;
-    if (string_init) {
-      // The new StringFactory call is static and has one fewer argument.
-      num_regs--;
-    }
+    num_regs = number_of_inputs;
   }
 
+  // Hack for String init:
+  //
+  // Rewrite invoke-x java.lang.String.<init>(this, a, b, c, ...) into:
+  //         invoke-x StringFactory(a, b, c, ...)
+  // by effectively dropping the first virtual register from the invoke.
+  //
+  // (at this point the ArtMethod has already been replaced,
+  // so we just need to fix-up the arguments)
+  uint32_t string_init_vreg_this = is_range ? vregC : arg[0];
+  if (UNLIKELY(string_init)) {
+    DCHECK_GT(num_regs, 0u);  // As the method is an instance method, there should be at least 1.
+
+    // The new StringFactory call is static and has one fewer argument.
+    if (code_item == nullptr) {
+      DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
+      num_regs--;
+    }  // else ... don't need to change num_regs since it comes up from the string_init's code item
+    number_of_inputs--;
+
+    // Rewrite the var-args, dropping the 0th argument ("this")
+    for (uint32_t i = 1; i < Instruction::kMaxVarArgRegs; ++i) {
+      arg[i - 1] = arg[i];
+    }
+    arg[Instruction::kMaxVarArgRegs - 1] = 0;
+
+    // Rewrite the non-var-arg case
+    vregC++;  // Skips the 0th vreg in the range ("this").
+  }
+
+  // Parameter registers go at the end of the shadow frame.
+  DCHECK_GE(num_regs, number_of_inputs);
+  size_t first_dest_reg = num_regs - number_of_inputs;
+  DCHECK_NE(first_dest_reg, (size_t)-1);
+
   // Allocate shadow frame on the stack.
-  const char* old_cause = self->StartAssertNoThreadSuspension("DoCall");
+  const char* old_cause = self->StartAssertNoThreadSuspension("DoCallCommon");
   void* memory = alloca(ShadowFrame::ComputeSize(num_regs));
   ShadowFrame* new_shadow_frame(ShadowFrame::Create(num_regs, &shadow_frame, called_method, 0,
                                                     memory));
 
-  // Initialize new shadow frame.
-  size_t first_dest_reg = num_regs - num_ins;
+  // Initialize new shadow frame by copying the registers from the callee shadow frame.
   if (do_assignability_check) {
     // Slow path.
     // We might need to do class loading, which incurs a thread state change to kNative. So
@@ -527,33 +594,25 @@
     uint32_t shorty_len = 0;
     const char* shorty = new_shadow_frame->GetMethod()->GetShorty(&shorty_len);
 
-    // TODO: find a cleaner way to separate non-range and range information without duplicating
-    //       code.
-    uint32_t arg[5];  // only used in invoke-XXX.
-    uint32_t vregC;   // only used in invoke-XXX-range.
-    if (is_range) {
-      vregC = inst->VRegC_3rc();
-    } else {
-      inst->GetVarArgs(arg, inst_data);
-    }
-
     // Handle receiver apart since it's not part of the shorty.
     size_t dest_reg = first_dest_reg;
     size_t arg_offset = 0;
+
     if (!new_shadow_frame->GetMethod()->IsStatic()) {
       size_t receiver_reg = is_range ? vregC : arg[0];
       new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
       ++dest_reg;
       ++arg_offset;
-    } else if (string_init) {
-      // Skip the referrer for the new static StringFactory call.
-      ++dest_reg;
-      ++arg_offset;
+      DCHECK(!string_init);  // All StringFactory methods are static.
     }
+
+    // Copy the caller's invoke-* arguments into the callee's parameter registers.
     for (uint32_t shorty_pos = 0; dest_reg < num_regs; ++shorty_pos, ++dest_reg, ++arg_offset) {
-      DCHECK_LT(shorty_pos + 1, shorty_len);
+      // Skip the 0th 'shorty' type since it represents the return type.
+      DCHECK_LT(shorty_pos + 1, shorty_len) << "for shorty '" << shorty << "'";
       const size_t src_reg = (is_range) ? vregC + arg_offset : arg[arg_offset];
       switch (shorty[shorty_pos + 1]) {
+        // Handle Object references. 1 virtual register slot.
         case 'L': {
           Object* o = shadow_frame.GetVRegReference(src_reg);
           if (do_assignability_check && o != nullptr) {
@@ -578,50 +637,40 @@
           new_shadow_frame->SetVRegReference(dest_reg, o);
           break;
         }
+        // Handle doubles and longs. 2 consecutive virtual register slots.
         case 'J': case 'D': {
-          uint64_t wide_value = (static_cast<uint64_t>(shadow_frame.GetVReg(src_reg + 1)) << 32) |
-                                static_cast<uint32_t>(shadow_frame.GetVReg(src_reg));
+          uint64_t wide_value =
+              (static_cast<uint64_t>(shadow_frame.GetVReg(src_reg + 1)) << BitSizeOf<uint32_t>()) |
+               static_cast<uint32_t>(shadow_frame.GetVReg(src_reg));
           new_shadow_frame->SetVRegLong(dest_reg, wide_value);
+          // Skip the next virtual register slot since we already used it.
           ++dest_reg;
           ++arg_offset;
           break;
         }
+        // Handle all other primitives that are always 1 virtual register slot.
         default:
           new_shadow_frame->SetVReg(dest_reg, shadow_frame.GetVReg(src_reg));
           break;
       }
     }
   } else {
+    size_t arg_index = 0;
+
     // Fast path: no extra checks.
     if (is_range) {
-      uint16_t first_src_reg = inst->VRegC_3rc();
-      if (string_init) {
-        // Skip the referrer for the new static StringFactory call.
-        ++first_src_reg;
-        ++first_dest_reg;
-      }
+      // TODO: Implement the range version of invoke-lambda
+      uint16_t first_src_reg = vregC;
+
       for (size_t src_reg = first_src_reg, dest_reg = first_dest_reg; dest_reg < num_regs;
           ++dest_reg, ++src_reg) {
         AssignRegister(new_shadow_frame, shadow_frame, dest_reg, src_reg);
       }
     } else {
-      DCHECK_LE(num_ins, 5U);
-      uint16_t regList = inst->Fetch16(2);
-      uint16_t count = num_ins;
-      size_t arg_index = 0;
-      if (count == 5) {
-        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + 4U,
-                       (inst_data >> 8) & 0x0f);
-        --count;
-      }
-      if (string_init) {
-        // Skip the referrer for the new static StringFactory call.
-        regList >>= 4;
-        ++first_dest_reg;
-        --count;
-      }
-      for (; arg_index < count; ++arg_index, regList >>= 4) {
-        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + arg_index, regList & 0x0f);
+      DCHECK_LE(number_of_inputs, Instruction::kMaxVarArgRegs);
+
+      for (; arg_index < number_of_inputs; ++arg_index) {
+        AssignRegister(new_shadow_frame, shadow_frame, first_dest_reg + arg_index, arg[arg_index]);
       }
     }
     self->EndAssertNoThreadSuspension(old_cause);
@@ -629,36 +678,18 @@
 
   // 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);
   }
 
   if (string_init && !self->IsExceptionPending()) {
     // Set the new string result of the StringFactory.
-    uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
-    shadow_frame.SetVRegReference(vregC, result->GetL());
+    shadow_frame.SetVRegReference(string_init_vreg_this, result->GetL());
     // Overwrite all potential copies of the original result of the new-instance of string with the
     // new result of the StringFactory. Use the verifier to find this set of registers.
     ArtMethod* method = shadow_frame.GetMethod();
@@ -689,6 +720,56 @@
   return !self->IsExceptionPending();
 }
 
+template<bool is_range, bool do_assignability_check>
+bool DoLambdaCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
+                  const Instruction* inst, uint16_t inst_data, JValue* result) {
+  const uint4_t num_additional_registers = inst->VRegB_25x();
+  // Argument word count.
+  const uint16_t number_of_inputs = num_additional_registers + 1;
+  // The first input register is always present and is not encoded in the count.
+
+  // TODO: find a cleaner way to separate non-range and range information without duplicating
+  //       code.
+  uint32_t arg[Instruction::kMaxVarArgRegs];  // only used in invoke-XXX.
+  uint32_t vregC = 0;   // only used in invoke-XXX-range.
+  if (is_range) {
+    vregC = inst->VRegC_3rc();
+  } else {
+    // TODO(iam): See if it's possible to remove inst_data dependency from 35x to avoid this path
+    UNUSED(inst_data);
+    inst->GetAllArgs25x(arg);
+  }
+
+  // TODO: if there's an assignability check, throw instead?
+  DCHECK(called_method->IsStatic());
+
+  return DoCallCommon<is_range, do_assignability_check>(
+      called_method, self, shadow_frame,
+      result, number_of_inputs, arg, vregC);
+}
+
+template<bool is_range, bool do_assignability_check>
+bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
+            const Instruction* inst, uint16_t inst_data, JValue* result) {
+  // Argument word count.
+  const uint16_t number_of_inputs = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data);
+
+  // TODO: find a cleaner way to separate non-range and range information without duplicating
+  //       code.
+  uint32_t arg[Instruction::kMaxVarArgRegs];  // only used in invoke-XXX.
+  uint32_t vregC = 0;
+  if (is_range) {
+    vregC = inst->VRegC_3rc();
+  } else {
+    vregC = inst->VRegC_35c();
+    inst->GetVarArgs(arg, inst_data);
+  }
+
+  return DoCallCommon<is_range, do_assignability_check>(
+      called_method, self, shadow_frame,
+      result, number_of_inputs, arg, vregC);
+}
+
 template <bool is_range, bool do_access_check, bool transaction_active>
 bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
                       Thread* self, JValue* result) {
@@ -731,8 +812,8 @@
     self->AssertPendingOOMException();
     return false;
   }
-  uint32_t arg[5];  // only used in filled-new-array.
-  uint32_t vregC;   // only used in filled-new-array-range.
+  uint32_t arg[Instruction::kMaxVarArgRegs];  // only used in filled-new-array.
+  uint32_t vregC = 0;   // only used in filled-new-array-range.
   if (is_range) {
     vregC = inst->VRegC_3rc();
   } else {
@@ -814,6 +895,20 @@
 EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true);
 #undef EXPLICIT_DO_CALL_TEMPLATE_DECL
 
+// Explicit DoLambdaCall template function declarations.
+#define EXPLICIT_DO_LAMBDA_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check)               \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                          \
+  bool DoLambdaCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self,        \
+                                                        ShadowFrame& shadow_frame,              \
+                                                        const Instruction* inst,                \
+                                                        uint16_t inst_data,                     \
+                                                        JValue* result)
+EXPLICIT_DO_LAMBDA_CALL_TEMPLATE_DECL(false, false);
+EXPLICIT_DO_LAMBDA_CALL_TEMPLATE_DECL(false, true);
+EXPLICIT_DO_LAMBDA_CALL_TEMPLATE_DECL(true, false);
+EXPLICIT_DO_LAMBDA_CALL_TEMPLATE_DECL(true, true);
+#undef EXPLICIT_DO_LAMBDA_CALL_TEMPLATE_DECL
+
 // Explicit DoFilledNewArray template function declarations.
 #define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active)       \
   template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                            \
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0124d90..a12a58d 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -35,6 +35,7 @@
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "handle_scope-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/method.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
@@ -97,6 +98,151 @@
 bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
             const Instruction* inst, uint16_t inst_data, JValue* result);
 
+// Invokes the given lambda closure. This is part of the invocation support and is used by
+// DoLambdaInvoke functions.
+// Returns true on success, otherwise throws an exception and returns false.
+template<bool is_range, bool do_assignability_check>
+bool DoLambdaCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame,
+                  const Instruction* inst, uint16_t inst_data, JValue* result);
+
+// Validates that the art method corresponding to a lambda method target
+// is semantically valid:
+//
+// Must be ACC_STATIC and ACC_LAMBDA. Must be a concrete managed implementation
+// (i.e. not native, not proxy, not abstract, ...).
+//
+// If the validation fails, return false and raise an exception.
+static inline bool IsValidLambdaTargetOrThrow(ArtMethod* called_method)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  bool success = false;
+
+  if (UNLIKELY(called_method == nullptr)) {
+    // The shadow frame should already be pushed, so we don't need to update it.
+  } else if (UNLIKELY(called_method->IsAbstract())) {
+    ThrowAbstractMethodError(called_method);
+    // TODO(iam): Also handle the case when the method is non-static, what error do we throw?
+    // TODO(iam): Also make sure that ACC_LAMBDA is set.
+  } else if (UNLIKELY(called_method->GetCodeItem() == nullptr)) {
+    // Method could be native, proxy method, etc. Lambda targets have to be concrete impls,
+    // so don't allow this.
+  } else {
+    success = true;
+  }
+
+  return success;
+}
+
+// Write out the 'ArtMethod*' into vreg and vreg+1
+static inline void WriteLambdaClosureIntoVRegs(ShadowFrame& shadow_frame,
+                                               const ArtMethod& called_method,
+                                               uint32_t vreg) {
+  // Split the method into a lo and hi 32 bits so we can encode them into 2 virtual registers.
+  uint32_t called_method_lo = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&called_method));
+  uint32_t called_method_hi = static_cast<uint32_t>(reinterpret_cast<uint64_t>(&called_method)
+                                                    >> BitSizeOf<uint32_t>());
+  // Use uint64_t instead of uintptr_t to allow shifting past the max on 32-bit.
+  static_assert(sizeof(uint64_t) >= sizeof(uintptr_t), "Impossible");
+
+  DCHECK_NE(called_method_lo | called_method_hi, 0u);
+
+  shadow_frame.SetVReg(vreg, called_method_lo);
+  shadow_frame.SetVReg(vreg + 1, called_method_hi);
+}
+
+// Handles create-lambda instructions.
+// Returns true on success, otherwise throws an exception and returns false.
+// (Exceptions are thrown by creating a new exception and then being put in the thread TLS)
+//
+// As a work-in-progress implementation, this shoves the ArtMethod object corresponding
+// to the target dex method index into the target register vA and vA + 1.
+template<bool do_access_check>
+static inline bool DoCreateLambda(Thread* self, ShadowFrame& shadow_frame,
+                                  const Instruction* inst) {
+  /*
+   * create-lambda is opcode 0x21c
+   * - vA is the target register where the closure will be stored into
+   *   (also stores into vA + 1)
+   * - vB is the method index which will be the target for a later invoke-lambda
+   */
+  const uint32_t method_idx = inst->VRegB_21c();
+  mirror::Object* receiver = nullptr;  // Always static. (see 'kStatic')
+  ArtMethod* sf_method = shadow_frame.GetMethod();
+  ArtMethod* const called_method = FindMethodFromCode<kStatic, do_access_check>(
+      method_idx, &receiver, &sf_method, self);
+
+  uint32_t vregA = inst->VRegA_21c();
+
+  if (UNLIKELY(!IsValidLambdaTargetOrThrow(called_method))) {
+    CHECK(self->IsExceptionPending());
+    shadow_frame.SetVReg(vregA, 0u);
+    shadow_frame.SetVReg(vregA + 1, 0u);
+    return false;
+  }
+
+  WriteLambdaClosureIntoVRegs(shadow_frame, *called_method, vregA);
+  return true;
+}
+
+// Reads out the 'ArtMethod*' stored inside of vreg and vreg+1
+//
+// Validates that the art method points to a valid lambda function, otherwise throws
+// an exception and returns null.
+// (Exceptions are thrown by creating a new exception and then being put in the thread TLS)
+static inline ArtMethod* ReadLambdaClosureFromVRegsOrThrow(ShadowFrame& shadow_frame,
+                                                           uint32_t vreg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // TODO(iam): Introduce a closure abstraction that will contain the captured variables
+  // instead of just an ArtMethod.
+  // This is temporarily using 2 vregs because a native ArtMethod can be up to 64-bit,
+  // but once proper variable capture is implemented it will only use 1 vreg.
+  uint32_t vc_value_lo = shadow_frame.GetVReg(vreg);
+  uint32_t vc_value_hi = shadow_frame.GetVReg(vreg + 1);
+
+  uint64_t vc_value_ptr = (static_cast<uint64_t>(vc_value_hi) << BitSizeOf<uint32_t>())
+                           | vc_value_lo;
+
+  // Use uint64_t instead of uintptr_t to allow left-shifting past the max on 32-bit.
+  static_assert(sizeof(uint64_t) >= sizeof(uintptr_t), "Impossible");
+  ArtMethod* const called_method = reinterpret_cast<ArtMethod* const>(vc_value_ptr);
+
+  // Guard against the user passing a null closure, which is odd but (sadly) semantically valid.
+  if (UNLIKELY(called_method == nullptr)) {
+    ThrowNullPointerExceptionFromInterpreter();
+    return nullptr;
+  } else if (UNLIKELY(!IsValidLambdaTargetOrThrow(called_method))) {
+    return nullptr;
+  }
+
+  return called_method;
+}
+
+template<bool do_access_check>
+static inline bool DoInvokeLambda(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
+                                  uint16_t inst_data, JValue* result) {
+  /*
+   * invoke-lambda is opcode 0x25
+   *
+   * - vC is the closure register (both vC and vC + 1 will be used to store the closure).
+   * - vB is the number of additional registers up to |{vD,vE,vF,vG}| (4)
+   * - the rest of the registers are always var-args
+   *
+   * - reading var-args for 0x25 gets us vD,vE,vF,vG (but not vB)
+   */
+  uint32_t vC = inst->VRegC_25x();
+  ArtMethod* const called_method = ReadLambdaClosureFromVRegsOrThrow(shadow_frame, vC);
+
+  // Failed lambda target runtime check, an exception was raised.
+  if (UNLIKELY(called_method == nullptr)) {
+    CHECK(self->IsExceptionPending());
+    result->SetJ(0);
+    return false;
+  }
+
+  // Invoke a non-range lambda
+  return DoLambdaCall<false, do_access_check>(called_method, self, shadow_frame, inst, inst_data,
+                                              result);
+}
+
 // Handles invoke-XXX/range instructions.
 // Returns true on success, otherwise throws an exception and returns false.
 template<InvokeType type, bool is_range, bool do_access_check>
@@ -348,6 +494,89 @@
   return 3;
 }
 
+template <bool _do_check>
+static inline bool DoBoxLambda(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
+                               uint16_t inst_data) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  /*
+   * box-lambda vA, vB /// opcode 0xf8, format 22x
+   * - vA is the target register where the Object representation of the closure will be stored into
+   * - vB is a closure (made by create-lambda)
+   *   (also reads vB + 1)
+   */
+  uint32_t vreg_target_object = inst->VRegA_22x(inst_data);
+  uint32_t vreg_source_closure = inst->VRegB_22x();
+
+  ArtMethod* const closure_method = ReadLambdaClosureFromVRegsOrThrow(shadow_frame,
+                                                                      vreg_source_closure);
+
+  // Failed lambda target runtime check, an exception was raised.
+  if (UNLIKELY(closure_method == nullptr)) {
+    CHECK(self->IsExceptionPending());
+    return false;
+  }
+
+  // Convert the ArtMethod into a java.lang.reflect.Method which will serve
+  // as the temporary 'boxed' version of the lambda. This is good enough
+  // to check all the basic object identities that a boxed lambda must retain.
+
+  // TODO: Boxing an innate lambda (i.e. made with create-lambda) should make a proxy class
+  // TODO: Boxing a learned lambda (i.e. made with unbox-lambda) should return the original object
+  // TODO: Repeated boxing should return the same object reference
+  mirror::Method* method_as_object =
+      mirror::Method::CreateFromArtMethod(self, closure_method);
+
+  if (UNLIKELY(method_as_object == nullptr)) {
+    // Most likely an OOM has occurred.
+    CHECK(self->IsExceptionPending());
+    return false;
+  }
+
+  shadow_frame.SetVRegReference(vreg_target_object, method_as_object);
+  return true;
+}
+
+template <bool _do_check> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+static inline bool DoUnboxLambda(Thread* self ATTRIBUTE_UNUSED,
+                                 ShadowFrame& shadow_frame,
+                                 const Instruction* inst,
+                                 uint16_t inst_data) {
+  /*
+   * unbox-lambda vA, vB, [type id] /// opcode 0xf9, format 22c
+   * - vA is the target register where the closure will be written into
+   *   (also writes vA + 1)
+   * - vB is the Object representation of the closure (made by box-lambda)
+   */
+  uint32_t vreg_target_closure = inst->VRegA_22c(inst_data);
+  uint32_t vreg_source_object = inst->VRegB_22c();
+
+  // Raise NullPointerException if object is null
+  mirror::Object* boxed_closure_object = shadow_frame.GetVRegReference(vreg_source_object);
+  if (UNLIKELY(boxed_closure_object == nullptr)) {
+    ThrowNullPointerExceptionFromInterpreter();
+    return false;
+  }
+
+  // Raise ClassCastException if object is not instanceof java.lang.reflect.Method
+  if (UNLIKELY(!boxed_closure_object->InstanceOf(mirror::Method::StaticClass()))) {
+    ThrowClassCastException(mirror::Method::StaticClass(), boxed_closure_object->GetClass());
+    return false;
+  }
+
+  // TODO(iam): We must check that the closure object extends/implements the type
+  // specified in [type id]. This is not currently implemented since it's always a Method.
+
+  // If we got this far, the inputs are valid.
+  // Write out the java.lang.reflect.Method's embedded ArtMethod* into the vreg target.
+  mirror::AbstractMethod* boxed_closure_as_method =
+      down_cast<mirror::AbstractMethod*>(boxed_closure_object);
+
+  ArtMethod* unboxed_closure = boxed_closure_as_method->GetArtMethod();
+  DCHECK(unboxed_closure != nullptr);
+
+  WriteLambdaClosureIntoVRegs(shadow_frame, *unboxed_closure, vreg_target_closure);
+  return true;
+}
+
 uint32_t FindNextInstructionFollowingException(Thread* self, ShadowFrame& shadow_frame,
     uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -420,6 +649,46 @@
 EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true);   // invoke-virtual-quick-range.
 #undef EXPLICIT_INSTANTIATION_DO_INVOKE_VIRTUAL_QUICK
 
+// Explicitly instantiate all DoCreateLambda functions.
+#define EXPLICIT_DO_CREATE_LAMBDA_DECL(_do_check)                                    \
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                 \
+bool DoCreateLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame,              \
+                        const Instruction* inst)
+
+EXPLICIT_DO_CREATE_LAMBDA_DECL(false);  // create-lambda
+EXPLICIT_DO_CREATE_LAMBDA_DECL(true);   // create-lambda
+#undef EXPLICIT_DO_CREATE_LAMBDA_DECL
+
+// Explicitly instantiate all DoInvokeLambda functions.
+#define EXPLICIT_DO_INVOKE_LAMBDA_DECL(_do_check)                                    \
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                 \
+bool DoInvokeLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \
+                               uint16_t inst_data, JValue* result);
+
+EXPLICIT_DO_INVOKE_LAMBDA_DECL(false);  // invoke-lambda
+EXPLICIT_DO_INVOKE_LAMBDA_DECL(true);   // invoke-lambda
+#undef EXPLICIT_DO_INVOKE_LAMBDA_DECL
+
+// Explicitly instantiate all DoBoxLambda functions.
+#define EXPLICIT_DO_BOX_LAMBDA_DECL(_do_check)                                                \
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                          \
+bool DoBoxLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \
+                            uint16_t inst_data);
+
+EXPLICIT_DO_BOX_LAMBDA_DECL(false);  // box-lambda
+EXPLICIT_DO_BOX_LAMBDA_DECL(true);   // box-lambda
+#undef EXPLICIT_DO_BOX_LAMBDA_DECL
+
+// Explicitly instantiate all DoUnBoxLambda functions.
+#define EXPLICIT_DO_UNBOX_LAMBDA_DECL(_do_check)                                                \
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                            \
+bool DoUnboxLambda<_do_check>(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \
+                              uint16_t inst_data);
+
+EXPLICIT_DO_UNBOX_LAMBDA_DECL(false);  // unbox-lambda
+EXPLICIT_DO_UNBOX_LAMBDA_DECL(true);   // unbox-lambda
+#undef EXPLICIT_DO_BOX_LAMBDA_DECL
+
 
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 86027c5..ec923b6 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -75,6 +75,17 @@
 #define HANDLE_INSTRUCTION_START(opcode) op_##opcode:  // NOLINT(whitespace/labels)
 #define HANDLE_INSTRUCTION_END() UNREACHABLE_CODE_CHECK()
 
+// Use with instructions labeled with kExperimental flag:
+#define HANDLE_EXPERIMENTAL_INSTRUCTION_START(opcode)                                             \
+  HANDLE_INSTRUCTION_START(opcode);                                                               \
+  DCHECK(inst->IsExperimental());                                                                 \
+  if (Runtime::Current()->AreExperimentalLambdasEnabled()) {
+#define HANDLE_EXPERIMENTAL_INSTRUCTION_END()                                                     \
+  } else {                                                                                        \
+      UnexpectedOpcode(inst, shadow_frame);                                                       \
+  } HANDLE_INSTRUCTION_END();
+
+
 /**
  * Interpreter based on computed goto tables.
  *
@@ -1609,6 +1620,14 @@
   }
   HANDLE_INSTRUCTION_END();
 
+  HANDLE_EXPERIMENTAL_INSTRUCTION_START(INVOKE_LAMBDA) {
+    bool success = DoInvokeLambda<do_access_check>(self, shadow_frame, inst, inst_data,
+                                                   &result_register);
+    UPDATE_HANDLER_TABLE();
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_EXPERIMENTAL_INSTRUCTION_END();
+
   HANDLE_INSTRUCTION_START(NEG_INT)
     shadow_frame.SetVReg(
         inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
@@ -2390,6 +2409,24 @@
     ADVANCE(2);
   HANDLE_INSTRUCTION_END();
 
+  HANDLE_EXPERIMENTAL_INSTRUCTION_START(CREATE_LAMBDA) {
+    bool success = DoCreateLambda<true>(self, shadow_frame, inst);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_EXPERIMENTAL_INSTRUCTION_END();
+
+  HANDLE_EXPERIMENTAL_INSTRUCTION_START(BOX_LAMBDA) {
+    bool success = DoBoxLambda<do_access_check>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_EXPERIMENTAL_INSTRUCTION_END();
+
+  HANDLE_EXPERIMENTAL_INSTRUCTION_START(UNBOX_LAMBDA) {
+    bool success = DoUnboxLambda<do_access_check>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_EXPERIMENTAL_INSTRUCTION_END();
+
   HANDLE_INSTRUCTION_START(UNUSED_3E)
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
@@ -2422,10 +2459,6 @@
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
-  HANDLE_INSTRUCTION_START(UNUSED_F3)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
   HANDLE_INSTRUCTION_START(UNUSED_F4)
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
@@ -2434,22 +2467,10 @@
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
-  HANDLE_INSTRUCTION_START(UNUSED_F6)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
   HANDLE_INSTRUCTION_START(UNUSED_F7)
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
-  HANDLE_INSTRUCTION_START(UNUSED_F8)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F9)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
   HANDLE_INSTRUCTION_START(UNUSED_FA)
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index dd7aa40..78090bb 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -53,10 +53,15 @@
     }                                                                                           \
   } while (false)
 
+static bool IsExperimentalInstructionEnabled(const Instruction *inst) {
+  DCHECK(inst->IsExperimental());
+  return Runtime::Current()->AreExperimentalLambdasEnabled();
+}
+
 template<bool do_access_check, bool transaction_active>
 JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
                          ShadowFrame& shadow_frame, JValue result_register) {
-  bool do_assignability_check = do_access_check;
+  constexpr bool do_assignability_check = do_access_check;
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
     return JValue();
@@ -2217,8 +2222,59 @@
                              (inst->VRegC_22b() & 0x1f));
         inst = inst->Next_2xx();
         break;
+      case Instruction::INVOKE_LAMBDA: {
+        if (!IsExperimentalInstructionEnabled(inst)) {
+          UnexpectedOpcode(inst, shadow_frame);
+        }
+
+        PREAMBLE();
+        bool success = DoInvokeLambda<do_access_check>(self, shadow_frame, inst, inst_data,
+                                                       &result_register);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
+      case Instruction::CREATE_LAMBDA: {
+        if (!IsExperimentalInstructionEnabled(inst)) {
+          UnexpectedOpcode(inst, shadow_frame);
+        }
+
+        PREAMBLE();
+        bool success = DoCreateLambda<do_access_check>(self, shadow_frame, inst);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
+      case Instruction::UNUSED_F4:
+      case Instruction::UNUSED_F5:
+      case Instruction::UNUSED_F7: {
+        if (!IsExperimentalInstructionEnabled(inst)) {
+          UnexpectedOpcode(inst, shadow_frame);
+        }
+
+        CHECK(false);  // TODO(iam): Implement opcodes for lambdas
+        break;
+      }
+      case Instruction::BOX_LAMBDA: {
+        if (!IsExperimentalInstructionEnabled(inst)) {
+          UnexpectedOpcode(inst, shadow_frame);
+        }
+
+        PREAMBLE();
+        bool success = DoBoxLambda<do_access_check>(self, shadow_frame, inst, inst_data);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
+      case Instruction::UNBOX_LAMBDA: {
+        if (!IsExperimentalInstructionEnabled(inst)) {
+          UnexpectedOpcode(inst, shadow_frame);
+        }
+
+        PREAMBLE();
+        bool success = DoUnboxLambda<do_access_check>(self, shadow_frame, inst, inst_data);
+        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+        break;
+      }
       case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
-      case Instruction::UNUSED_F3 ... Instruction::UNUSED_FF:
+      case Instruction::UNUSED_FA ... Instruction::UNUSED_FF:
       case Instruction::UNUSED_79:
       case Instruction::UNUSED_7A:
         UnexpectedOpcode(inst, shadow_frame);
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/jni_internal.cc b/runtime/jni_internal.cc
index 0a01f78..cc176b7 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -406,7 +406,7 @@
     CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
-    return soa.AddLocalReference<jclass>(c->GetSuperClass());
+    return soa.AddLocalReference<jclass>(c->IsInterface() ? nullptr : c->GetSuperClass());
   }
 
   // Note: java_class1 should be safely castable to java_class2, and
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 99eb365..2a0cb28 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1238,7 +1238,7 @@
   ASSERT_NE(runnable_interface, nullptr);
   ASSERT_TRUE(env_->IsSameObject(object_class, env_->GetSuperclass(string_class)));
   ASSERT_EQ(env_->GetSuperclass(object_class), nullptr);
-  ASSERT_TRUE(env_->IsSameObject(object_class, env_->GetSuperclass(runnable_interface)));
+  ASSERT_EQ(env_->GetSuperclass(runnable_interface), nullptr);
 
   // Null as class should fail.
   CheckJniAbortCatcher jni_abort_catcher;
diff --git a/runtime/lock_word.h b/runtime/lock_word.h
index aafbfe4..a290575 100644
--- a/runtime/lock_word.h
+++ b/runtime/lock_word.h
@@ -210,6 +210,10 @@
     return lw1.GetValueWithoutReadBarrierState() == lw2.GetValueWithoutReadBarrierState();
   }
 
+  void Dump(std::ostream& os) {
+    os << "LockWord:" << std::hex << value_;
+  }
+
  private:
   // Default constructor with no lock ownership.
   LockWord();
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 6566060..7e640c6 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -221,7 +221,7 @@
   // We call this here so that we can try and generate a full error
   // message with the overlapping mapping. There's no guarantee that
   // that there will be an overlap though, since
-  // - The kernel is not *required* to honour expected_ptr unless MAP_FIXED is
+  // - The kernel is not *required* to honor expected_ptr unless MAP_FIXED is
   //   true, even if there is no overlap
   // - There might have been an overlap at the point of mmap, but the
   //   overlapping region has since been unmapped.
@@ -436,7 +436,7 @@
     return nullptr;
   }
   return new MemMap(name, reinterpret_cast<uint8_t*>(actual), byte_count, actual,
-                    page_aligned_byte_count, prot, false);
+                    page_aligned_byte_count, prot, reuse);
 }
 
 MemMap* MemMap::MapDummy(const char* name, uint8_t* addr, size_t byte_count) {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index d343292..88d75ab 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -239,7 +239,7 @@
 }
 
 template<typename T>
-template<bool kTransactionActive, bool kCheckTransaction>
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
 inline void PrimitiveArray<T>::SetWithoutChecks(int32_t i, T value) {
   if (kCheckTransaction) {
     DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
@@ -247,7 +247,7 @@
   if (kTransactionActive) {
     Runtime::Current()->RecordWriteArray(this, i, GetWithoutChecks(i));
   }
-  DCHECK(CheckIsValidIndex(i));
+  DCHECK(CheckIsValidIndex<kVerifyFlags>(i));
   GetData()[i] = value;
 }
 // Backward copy where elements are of aligned appropriately for T. Count is in T sized units.
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index c4f6c84..e65611d 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -133,7 +133,9 @@
 
   // TODO fix thread safety analysis broken by the use of template. This should be
   // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
-  template<bool kTransactionActive, bool kCheckTransaction = true>
+  template<bool kTransactionActive,
+           bool kCheckTransaction = true,
+           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetWithoutChecks(int32_t i, T value) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS;
 
   /*
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 0538f4b..7f89b1d 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -552,7 +552,8 @@
 
 template<VerifyObjectFlags kVerifyFlags>
 inline Primitive::Type Class::GetPrimitiveType() {
-  DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t));
+  static_assert(sizeof(Primitive::Type) == sizeof(int32_t),
+                "art::Primitive::Type and int32_t have different sizes.");
   int32_t v32 = GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_));
   Primitive::Type type = static_cast<Primitive::Type>(v32 & 0xFFFF);
   DCHECK_EQ(static_cast<size_t>(v32 >> 16), Primitive::ComponentSizeShift(type));
@@ -561,7 +562,8 @@
 
 template<VerifyObjectFlags kVerifyFlags>
 inline size_t Class::GetPrimitiveTypeSizeShift() {
-  DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t));
+  static_assert(sizeof(Primitive::Type) == sizeof(int32_t),
+                "art::Primitive::Type and int32_t have different sizes.");
   int32_t v32 = GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_));
   size_t size_shift = static_cast<Primitive::Type>(v32 >> 16);
   DCHECK_EQ(size_shift, Primitive::ComponentSizeShift(static_cast<Primitive::Type>(v32 & 0xFFFF)));
@@ -666,7 +668,7 @@
 inline void Class::VisitReferences(mirror::Class* klass, const Visitor& visitor) {
   VisitInstanceFieldsReferences<kVisitClass>(klass, visitor);
   // Right after a class is allocated, but not yet loaded
-  // (kStatusNotReady, see ClassLinkder::LoadClass()), GC may find it
+  // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it
   // and scan it. IsTemp() may call Class::GetAccessFlags() but may
   // fail in the DCHECK in Class::GetAccessFlags() because the class
   // status is kStatusNotReady. To avoid it, rely on IsResolved()
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 0453906..ba0a9fc 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1211,7 +1211,12 @@
   // Descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
   HeapReference<String> name_;
 
-  // The superclass, or null if this is java.lang.Object, an interface or primitive type.
+  // The superclass, or null if this is java.lang.Object or a primitive type.
+  //
+  // Note that interfaces have java.lang.Object as their
+  // superclass. This doesn't match the expectations in JNI
+  // GetSuperClass or java.lang.Class.getSuperClass() which need to
+  // check for interfaces and return null.
   HeapReference<Class> super_class_;
 
   // If class verify fails, we must return same error on subsequent tries.
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 05c44e5..e019d5a 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -60,19 +60,23 @@
       OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass);
 }
 
+template<VerifyObjectFlags kVerifyFlags>
 inline LockWord Object::GetLockWord(bool as_volatile) {
   if (as_volatile) {
-    return LockWord(GetField32Volatile(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+    return LockWord(GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
   }
-  return LockWord(GetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
+  return LockWord(GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_)));
 }
 
+template<VerifyObjectFlags kVerifyFlags>
 inline void Object::SetLockWord(LockWord new_val, bool as_volatile) {
   // Force use of non-transactional mode and do not check.
   if (as_volatile) {
-    SetField32Volatile<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
+    SetField32Volatile<false, false, kVerifyFlags>(
+        OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
   } else {
-    SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
+    SetField32<false, false, kVerifyFlags>(
+        OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue());
   }
 }
 
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 60c756a..f1c96b5 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -125,7 +125,9 @@
 
   // As_volatile can be false if the mutators are suspended. This is an optimization since it
   // avoids the barriers.
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   LockWord GetLockWord(bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetLockWord(LockWord new_val, bool as_volatile) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool CasLockWordWeakSequentiallyConsistent(LockWord old_val, LockWord new_val)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index bef4af6..4a7e7b3 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -129,7 +129,8 @@
     }
   }
   // Perform the memmove using int memmove then perform the write barrier.
-  CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t));
+  static_assert(sizeof(HeapReference<T>) == sizeof(uint32_t),
+                "art::mirror::HeapReference<T> and uint32_t have different sizes.");
   IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this);
   IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src);
   if (kUseReadBarrier) {
@@ -172,7 +173,8 @@
     }
   }
   // Perform the memmove using int memcpy then perform the write barrier.
-  CHECK_EQ(sizeof(HeapReference<T>), sizeof(uint32_t));
+  static_assert(sizeof(HeapReference<T>) == sizeof(uint32_t),
+                "art::mirror::HeapReference<T> and uint32_t have different sizes.");
   IntArray* dstAsIntArray = reinterpret_cast<IntArray*>(this);
   IntArray* srcAsIntArray = reinterpret_cast<IntArray*>(src);
   if (kUseReadBarrier) {
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index d283f58..b689057 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -176,11 +176,13 @@
 }
 
 template <bool kIsInstrumented>
-inline String* String::AllocFromCharArray(Thread* self, int32_t array_length,
+inline String* String::AllocFromCharArray(Thread* self, int32_t count,
                                           Handle<CharArray> array, int32_t offset,
                                           gc::AllocatorType allocator_type) {
-  SetStringCountAndValueVisitorFromCharArray visitor(array_length, array, offset);
-  String* new_string = Alloc<kIsInstrumented>(self, array_length, allocator_type, visitor);
+  // It is a caller error to have a count less than the actual array's size.
+  DCHECK_GE(array->GetLength(), count);
+  SetStringCountAndValueVisitorFromCharArray visitor(count, array, offset);
+  String* new_string = Alloc<kIsInstrumented>(self, count, allocator_type, visitor);
   return new_string;
 }
 
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index a8f16d7..af06385 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -95,7 +95,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template <bool kIsInstrumented>
-  ALWAYS_INLINE static String* AllocFromCharArray(Thread* self, int32_t array_length,
+  ALWAYS_INLINE static String* AllocFromCharArray(Thread* self, int32_t count,
                                                   Handle<CharArray> array, int32_t offset,
                                                   gc::AllocatorType allocator_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 0c39f2b..1515630 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -55,60 +55,29 @@
   return nullptr;
 }
 
-static jint VMClassLoader_getBootClassPathSize(JNIEnv*, jclass) {
-  return Runtime::Current()->GetClassLinker()->GetBootClassPath().size();
-}
-
 /*
- * Returns a string URL for a resource with the specified 'javaName' in
- * entry 'index' of the boot class path.
- *
- * We return a newly-allocated String in the following form:
- *
- *   jar:file://path!/name
- *
- * Where "path" is the bootstrap class path entry and "name" is the string
- * passed into this method.  "path" needs to be an absolute path (starting
- * with '/'); if it's not we'd need to make it absolute as part of forming
- * the URL string.
+ * Returns an array of entries from the boot classpath that could contain resources.
  */
-static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstring javaName,
-                                                      jint index) {
-  ScopedUtfChars name(env, javaName);
-  if (name.c_str() == nullptr) {
-    return nullptr;
-  }
-
+static jobjectArray VMClassLoader_getBootClassPathEntries(JNIEnv* env, jclass) {
   const std::vector<const DexFile*>& path =
       Runtime::Current()->GetClassLinker()->GetBootClassPath();
-  if (index < 0 || size_t(index) >= path.size()) {
-    return nullptr;
-  }
-  const DexFile* dex_file = path[index];
+  jclass stringClass = env->FindClass("java/lang/String");
+  jobjectArray array = env->NewObjectArray(path.size(), stringClass, nullptr);
+  for (size_t i = 0; i < path.size(); ++i) {
+    const DexFile* dex_file = path[i];
 
-  // For multidex locations, e.g., x.jar:classes2.dex, we want to look into x.jar.
-  const std::string& location(dex_file->GetBaseLocation());
+    // For multidex locations, e.g., x.jar:classes2.dex, we want to look into x.jar.
+    const std::string& location(dex_file->GetBaseLocation());
 
-  std::string error_msg;
-  std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(location.c_str(), &error_msg));
-  if (zip_archive.get() == nullptr) {
-    LOG(WARNING) << "Failed to open zip archive '" << location << "': " << error_msg;
-    return nullptr;
+    jstring javaPath = env->NewStringUTF(location.c_str());
+    env->SetObjectArrayElement(array, i, javaPath);
   }
-  std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(name.c_str(), &error_msg));
-  if (zip_entry.get() == nullptr) {
-    return nullptr;
-  }
-
-  std::string url;
-  StringAppendF(&url, "jar:file://%s!/%s", location.c_str(), name.c_str());
-  return env->NewStringUTF(url.c_str());
+  return array;
 }
 
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(VMClassLoader, findLoadedClass, "!(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;"),
-  NATIVE_METHOD(VMClassLoader, getBootClassPathResource, "(Ljava/lang/String;I)Ljava/lang/String;"),
-  NATIVE_METHOD(VMClassLoader, getBootClassPathSize, "!()I"),
+  NATIVE_METHOD(VMClassLoader, getBootClassPathEntries, "()[Ljava/lang/String;"),
 };
 
 void register_java_lang_VMClassLoader(JNIEnv* env) {
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index b96ddc8..9ce4a02 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -38,7 +38,7 @@
 }
 
 static jboolean DdmVmInternal_getRecentAllocationStatus(JNIEnv*, jclass) {
-  return Dbg::IsAllocTrackingEnabled();
+  return Runtime::Current()->GetHeap()->IsAllocTrackingEnabled();
 }
 
 /*
diff --git a/runtime/oat.h b/runtime/oat.h
index 000ae8e..5706c4e 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', '5', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 8e99dbb..df34ce7 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -17,13 +17,6 @@
 #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 {
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 0bc834f..d08af71 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -257,9 +257,15 @@
           .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)
+      .Define({"-Xexperimental-lambdas", "-Xnoexperimental-lambdas"})
+          .WithType<bool>()
+          .WithValues({true, false})
+          .IntoKey(M::ExperimentalLambdas)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
@@ -368,23 +374,28 @@
   return true;
 }
 
-bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized,
-                          RuntimeArgumentMap* runtime_options) {
+// Intended for local changes only.
+static void MaybeOverrideVerbosity() {
   //  gLogVerbosity.class_linker = true;  // TODO: don't check this in!
   //  gLogVerbosity.compiler = true;  // TODO: don't check this in!
+  //  gLogVerbosity.deopt = true;  // TODO: don't check this in!
   //  gLogVerbosity.gc = true;  // TODO: don't check this in!
   //  gLogVerbosity.heap = true;  // TODO: don't check this in!
   //  gLogVerbosity.jdwp = true;  // TODO: don't check this in!
   //  gLogVerbosity.jit = true;  // TODO: don't check this in!
   //  gLogVerbosity.jni = true;  // TODO: don't check this in!
   //  gLogVerbosity.monitor = true;  // TODO: don't check this in!
+  //  gLogVerbosity.oat = true;  // TODO: don't check this in!
   //  gLogVerbosity.profiler = true;  // TODO: don't check this in!
   //  gLogVerbosity.signals = true;  // TODO: don't check this in!
   //  gLogVerbosity.startup = true;  // TODO: don't check this in!
   //  gLogVerbosity.third_party_jni = true;  // TODO: don't check this in!
   //  gLogVerbosity.threads = true;  // TODO: don't check this in!
   //  gLogVerbosity.verifier = true;  // TODO: don't check this in!
+}
 
+bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognized,
+                          RuntimeArgumentMap* runtime_options) {
   for (size_t i = 0; i < options.size(); ++i) {
     if (true && options[0].first == "-Xzygote") {
       LOG(INFO) << "option[" << i << "]=" << options[i].first;
@@ -453,6 +464,8 @@
     }
   }
 
+  MaybeOverrideVerbosity();
+
   // -Xprofile:
   Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock));
 
@@ -537,6 +550,12 @@
     args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
   }
 
+  if (args.GetOrDefault(M::ExperimentalLambdas)) {
+    LOG(WARNING) << "Experimental lambdas have been enabled. All lambda opcodes have "
+                 << "an unstable specification and are nearly guaranteed to change over time. "
+                 << "Do not attempt to write shipping code against these opcodes.";
+  }
+
   *runtime_options = std::move(args);
   return true;
 }
@@ -656,6 +675,8 @@
   UsageMessage(stream, "  -X[no]image-dex2oat (Whether to create and use a boot image)\n");
   UsageMessage(stream, "  -Xno-dex-file-fallback "
                        "(Don't fall back to dex files without oat files)\n");
+  UsageMessage(stream, "  -X[no]experimental-lambdas\n"
+                       "     (Enable new experimental dalvik opcodes, off by default)\n");
   UsageMessage(stream, "\n");
 
   UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
diff --git a/runtime/profiler.cc b/runtime/profiler.cc
index ab28a9a..87b0d43 100644
--- a/runtime/profiler.cc
+++ b/runtime/profiler.cc
@@ -304,7 +304,9 @@
   } while (length > 0);
 
   // Truncate the file to the new length.
-  ftruncate(fd, full_length);
+  if (ftruncate(fd, full_length) == -1) {
+    LOG(ERROR) << "Failed to truncate profile file " << full_name;
+  }
 
   // Now unlock the file, allowing another process in.
   err = flock(fd, LOCK_UN);
diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h
index d341ee1..7014813 100644
--- a/runtime/read_barrier-inl.h
+++ b/runtime/read_barrier-inl.h
@@ -31,7 +31,7 @@
 template <typename MirrorType, ReadBarrierOption kReadBarrierOption, bool kMaybeDuringStartup>
 inline MirrorType* ReadBarrier::Barrier(
     mirror::Object* obj, MemberOffset offset, mirror::HeapReference<MirrorType>* ref_addr) {
-  const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
+  constexpr bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
   if (with_read_barrier && kUseBakerReadBarrier) {
     // The higher bits of the rb ptr, rb_ptr_high_bits (must be zero)
     // is used to create artificial data dependency from the is_gray
@@ -74,7 +74,8 @@
 }
 
 template <typename MirrorType, ReadBarrierOption kReadBarrierOption, bool kMaybeDuringStartup>
-inline MirrorType* ReadBarrier::BarrierForRoot(MirrorType** root) {
+inline MirrorType* ReadBarrier::BarrierForRoot(MirrorType** root,
+                                               GcRootSource* gc_root_source) {
   MirrorType* ref = *root;
   const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
   if (with_read_barrier && kUseBakerReadBarrier) {
@@ -87,7 +88,7 @@
     if (Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->IsMarking()) {
       ref = reinterpret_cast<MirrorType*>(Mark(ref));
     }
-    AssertToSpaceInvariant(nullptr, MemberOffset(0), ref);
+    AssertToSpaceInvariant(gc_root_source, ref);
     return ref;
   } else if (with_read_barrier && kUseBrooksReadBarrier) {
     // To be implemented.
@@ -105,7 +106,7 @@
       Atomic<mirror::Object*>* atomic_root = reinterpret_cast<Atomic<mirror::Object*>*>(root);
       atomic_root->CompareExchangeStrongSequentiallyConsistent(old_ref, ref);
     }
-    AssertToSpaceInvariant(nullptr, MemberOffset(0), ref);
+    AssertToSpaceInvariant(gc_root_source, ref);
     return ref;
   } else {
     return ref;
@@ -114,7 +115,8 @@
 
 // TODO: Reduce copy paste
 template <typename MirrorType, ReadBarrierOption kReadBarrierOption, bool kMaybeDuringStartup>
-inline MirrorType* ReadBarrier::BarrierForRoot(mirror::CompressedReference<MirrorType>* root) {
+inline MirrorType* ReadBarrier::BarrierForRoot(mirror::CompressedReference<MirrorType>* root,
+                                               GcRootSource* gc_root_source) {
   MirrorType* ref = root->AsMirrorPtr();
   const bool with_read_barrier = kReadBarrierOption == kWithReadBarrier;
   if (with_read_barrier && kUseBakerReadBarrier) {
@@ -127,7 +129,7 @@
     if (Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->IsMarking()) {
       ref = reinterpret_cast<MirrorType*>(Mark(ref));
     }
-    AssertToSpaceInvariant(nullptr, MemberOffset(0), ref);
+    AssertToSpaceInvariant(gc_root_source, ref);
     return ref;
   } else if (with_read_barrier && kUseBrooksReadBarrier) {
     // To be implemented.
@@ -147,7 +149,7 @@
           reinterpret_cast<Atomic<mirror::CompressedReference<MirrorType>>*>(root);
       atomic_root->CompareExchangeStrongSequentiallyConsistent(old_ref, new_ref);
     }
-    AssertToSpaceInvariant(nullptr, MemberOffset(0), ref);
+    AssertToSpaceInvariant(gc_root_source, ref);
     return ref;
   } else {
     return ref;
@@ -183,6 +185,17 @@
   }
 }
 
+inline void ReadBarrier::AssertToSpaceInvariant(GcRootSource* gc_root_source,
+                                                mirror::Object* ref) {
+  if (kEnableToSpaceInvariantChecks || kIsDebugBuild) {
+    if (ref == nullptr || IsDuringStartup()) {
+      return;
+    }
+    Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->
+        AssertToSpaceInvariant(gc_root_source, ref);
+  }
+}
+
 inline mirror::Object* ReadBarrier::Mark(mirror::Object* obj) {
   return Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->Mark(obj);
 }
diff --git a/runtime/read_barrier.h b/runtime/read_barrier.h
index aa72e97..55cef68 100644
--- a/runtime/read_barrier.h
+++ b/runtime/read_barrier.h
@@ -19,6 +19,7 @@
 
 #include "base/mutex.h"
 #include "base/macros.h"
+#include "gc_root.h"
 #include "jni.h"
 #include "mirror/object_reference.h"
 #include "offsets.h"
@@ -54,14 +55,16 @@
   // whereas the return value must be an updated reference.
   template <typename MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier,
             bool kMaybeDuringStartup = false>
-  ALWAYS_INLINE static MirrorType* BarrierForRoot(MirrorType** root)
+  ALWAYS_INLINE static MirrorType* BarrierForRoot(MirrorType** root,
+                                                  GcRootSource* gc_root_source = nullptr)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // It's up to the implementation whether the given root gets updated
   // whereas the return value must be an updated reference.
   template <typename MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier,
             bool kMaybeDuringStartup = false>
-  ALWAYS_INLINE static MirrorType* BarrierForRoot(mirror::CompressedReference<MirrorType>* root)
+  ALWAYS_INLINE static MirrorType* BarrierForRoot(mirror::CompressedReference<MirrorType>* root,
+                                                  GcRootSource* gc_root_source = nullptr)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static bool IsDuringStartup();
@@ -75,6 +78,9 @@
   static void AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset,
                                      mirror::Object* ref)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // With GcRootSource.
+  static void AssertToSpaceInvariant(GcRootSource* gc_root_source, mirror::Object* ref)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static mirror::Object* Mark(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/read_barrier_c.h b/runtime/read_barrier_c.h
index 88bda3a..4f408dd 100644
--- a/runtime/read_barrier_c.h
+++ b/runtime/read_barrier_c.h
@@ -31,6 +31,10 @@
 // #define USE_TABLE_LOOKUP_READ_BARRIER
 #endif
 
+#ifdef ART_HEAP_POISONING
+#define USE_HEAP_POISONING
+#endif
+
 #if defined(USE_BAKER_READ_BARRIER) || defined(USE_BROOKS_READ_BARRIER)
 #define USE_BAKER_OR_BROOKS_READ_BARRIER
 #endif
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 6f17e7d..9707fb8 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -505,6 +505,7 @@
 };
 
 TEST_F(ReflectionTest, StaticMainMethod) {
+  TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK();
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Main");
   StackHandleScope<1> hs(soa.Self());
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1453e9f..5067b0d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -191,8 +191,10 @@
       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) {
+      zygote_max_failed_boots_(0),
+      experimental_lambdas_(false) {
   CheckAsmSupportOffsetsAndSizes();
   std::fill(callee_save_methods_, callee_save_methods_ + arraysize(callee_save_methods_), 0u);
 }
@@ -405,6 +407,7 @@
   GetInternTable()->SweepInternTableWeaks(visitor, arg);
   GetMonitorList()->SweepMonitorList(visitor, arg);
   GetJavaVM()->SweepJniWeakGlobals(visitor, arg);
+  GetHeap()->SweepAllocationRecords(visitor, arg);
 }
 
 bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
@@ -485,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();
 
@@ -836,6 +841,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)) {
@@ -843,6 +850,7 @@
   }
 
   zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);
+  experimental_lambdas_ = runtime_options.GetOrDefault(Opt::ExperimentalLambdas);
 
   XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
   ATRACE_BEGIN("CreateHeap");
@@ -932,33 +940,37 @@
       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);
+      }
     }
   }
 
@@ -1381,6 +1393,7 @@
 void Runtime::VisitConcurrentRoots(RootVisitor* visitor, VisitRootFlags flags) {
   intern_table_->VisitRoots(visitor, flags);
   class_linker_->VisitRoots(visitor, flags);
+  heap_->VisitAllocationRecords(visitor);
   if ((flags & kVisitRootFlagNewRoots) == 0) {
     // Guaranteed to have no new roots in the constant roots.
     VisitConstantRoots(visitor);
@@ -1481,12 +1494,14 @@
   monitor_list_->DisallowNewMonitors();
   intern_table_->DisallowNewInterns();
   java_vm_->DisallowNewWeakGlobals();
+  heap_->DisallowNewAllocationRecords();
 }
 
 void Runtime::AllowNewSystemWeaks() {
   monitor_list_->AllowNewMonitors();
   intern_table_->AllowNewInterns();
   java_vm_->AllowNewWeakGlobals();
+  heap_->AllowNewAllocationRecords();
 }
 
 void Runtime::EnsureNewSystemWeaksDisallowed() {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index e569333..bcc7118 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -527,6 +527,10 @@
     return zygote_max_failed_boots_;
   }
 
+  bool AreExperimentalLambdasEnabled() const {
+    return experimental_lambdas_;
+  }
+
   // Create the JIT and instrumentation and code cache.
   void CreateJit();
 
@@ -711,6 +715,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,
@@ -727,6 +736,12 @@
   // zygote.
   uint32_t zygote_max_failed_boots_;
 
+  // Enable experimental opcodes that aren't fully specified yet. The intent is to
+  // eventually publish them as public-usable opcodes, but they aren't ready yet.
+  //
+  // Experimental opcodes should not be used by other production code.
+  bool experimental_lambdas_;
+
   MethodRefToStringInitRegMap method_ref_string_init_reg_map_;
 
   DISALLOW_COPY_AND_ASSIGN(Runtime);
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index d65e18e..f0b3c4e 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -340,6 +340,9 @@
                       << "Thread: " << tid << " \"" << thread_name << "\"\n"
                       << "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
                       << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
+  if (kIsDebugBuild && signal_number == SIGSEGV) {
+    PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
+  }
   Runtime* runtime = Runtime::Current();
   if (runtime != nullptr) {
     if (IsTimeoutSignal(signal_number)) {
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 8b504c1..dc4c0c7 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -30,6 +30,8 @@
 // If a default value is omitted here, T{} is used as the default value, which is
 // almost-always the value of the type as if it was memset to all 0.
 //
+// Please keep the columns aligned if possible when adding new rows.
+//
 
 // Parse-able keys from the command line.
 RUNTIME_OPTIONS_KEY (Unit,                Zygote)
@@ -62,11 +64,11 @@
 RUNTIME_OPTIONS_KEY (Unit,                DumpJITInfoOnShutdown)
 RUNTIME_OPTIONS_KEY (Unit,                IgnoreMaxFootprint)
 RUNTIME_OPTIONS_KEY (Unit,                LowMemoryMode)
-RUNTIME_OPTIONS_KEY (bool,                UseTLAB,                        kUseTlab)
+RUNTIME_OPTIONS_KEY (bool,                UseTLAB,                        (kUseTlab || kUseReadBarrier))
 RUNTIME_OPTIONS_KEY (bool,                EnableHSpaceCompactForOOM,      true)
-RUNTIME_OPTIONS_KEY (bool,                UseJIT,      false)
-RUNTIME_OPTIONS_KEY (unsigned int,        JITCompileThreshold, jit::Jit::kDefaultCompileThreshold)
-RUNTIME_OPTIONS_KEY (MemoryKiB,           JITCodeCacheCapacity, jit::JitCodeCache::kDefaultCapacity)
+RUNTIME_OPTIONS_KEY (bool,                UseJIT,                         false)
+RUNTIME_OPTIONS_KEY (unsigned int,        JITCompileThreshold,            jit::Jit::kDefaultCompileThreshold)
+RUNTIME_OPTIONS_KEY (MemoryKiB,           JITCodeCacheCapacity,           jit::JitCodeCache::kDefaultCapacity)
 RUNTIME_OPTIONS_KEY (MillisecondsToNanoseconds, \
                                           HSpaceCompactForOOMMinIntervalsMs,\
                                                                           MsToNs(100 * 1000))  // 100s
@@ -77,10 +79,10 @@
 RUNTIME_OPTIONS_KEY (bool,                Relocate,                       kDefaultMustRelocate)
 RUNTIME_OPTIONS_KEY (bool,                Dex2Oat,                        true)
 RUNTIME_OPTIONS_KEY (bool,                ImageDex2Oat,                   true)
-                                                        // kPoisonHeapReferences currently works with
+                                                        // kUseReadBarrier currently works with
                                                         // the interpreter only.
                                                         // TODO: make it work with the compiler.
-RUNTIME_OPTIONS_KEY (bool,                Interpret,                      (kPoisonHeapReferences || kUseReadBarrier)) // -Xint
+RUNTIME_OPTIONS_KEY (bool,                Interpret,                      kUseReadBarrier) // -Xint
                                                         // Disable the compiler for CC (for now).
 RUNTIME_OPTIONS_KEY (XGcOption,           GcOption)  // -Xgc:
 RUNTIME_OPTIONS_KEY (gc::space::LargeObjectSpaceType, \
@@ -89,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)
@@ -105,9 +108,13 @@
                                           ImageCompilerOptions)  // -Ximage-compiler-option ...
 RUNTIME_OPTIONS_KEY (bool,                Verify,                         true)
 RUNTIME_OPTIONS_KEY (std::string,         NativeBridge)
+RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           10)
+RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
 RUNTIME_OPTIONS_KEY (std::string,         CpuAbiList)
+RUNTIME_OPTIONS_KEY (bool,                ExperimentalLambdas,            false) // -X[no]experimental-lambdas
 
 // Not parse-able from command line, but can be provided explicitly.
+// (Do not add anything here that is defined in ParsedOptions::MakeParser)
 RUNTIME_OPTIONS_KEY (const std::vector<const DexFile*>*, \
                                           BootClassPathDexList)  // TODO: make unique_ptr
 RUNTIME_OPTIONS_KEY (InstructionSet,      ImageInstructionSet,            kRuntimeISA)
@@ -120,7 +127,5 @@
                                                                           // We don't call abort(3) by default; see
                                                                           // Runtime::Abort.
 RUNTIME_OPTIONS_KEY (void (*)(),          HookAbort,                      nullptr)
-RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           10)
-RUNTIME_OPTIONS_KEY (Unit,                NoDexFileFallback)
 
 #undef RUNTIME_OPTIONS_KEY
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 6cca4d2..6f3b0a3 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -19,6 +19,7 @@
 #include "arch/context.h"
 #include "art_method-inl.h"
 #include "base/hex_dump.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc_map.h"
 #include "gc/space/image_space.h"
@@ -103,15 +104,46 @@
       cur_quick_frame_pc_(0),
       num_frames_(num_frames),
       cur_depth_(0),
+      current_inlining_depth_(0),
       context_(context) {
   DCHECK(thread == Thread::Current() || thread->IsSuspended()) << *thread;
 }
 
+InlineInfo StackVisitor::GetCurrentInlineInfo() const {
+  ArtMethod* outer_method = *GetCurrentQuickFrame();
+  uint32_t native_pc_offset = outer_method->NativeQuickPcOffset(cur_quick_frame_pc_);
+  CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+  DCHECK(stack_map.IsValid());
+  return code_info.GetInlineInfoOf(stack_map, encoding);
+}
+
+ArtMethod* StackVisitor::GetMethod() const {
+  if (cur_shadow_frame_ != nullptr) {
+    return cur_shadow_frame_->GetMethod();
+  } else if (cur_quick_frame_ != nullptr) {
+    if (IsInInlinedFrame()) {
+      size_t depth_in_stack_map = current_inlining_depth_ - 1;
+      InlineInfo inline_info = GetCurrentInlineInfo();
+      return GetResolvedMethod(*GetCurrentQuickFrame(), inline_info, depth_in_stack_map);
+    } else {
+      return *cur_quick_frame_;
+    }
+  }
+  return nullptr;
+}
+
 uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const {
   if (cur_shadow_frame_ != nullptr) {
     return cur_shadow_frame_->GetDexPC();
   } else if (cur_quick_frame_ != nullptr) {
-    return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+    if (IsInInlinedFrame()) {
+      size_t depth_in_stack_map = current_inlining_depth_ - 1;
+      return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map);
+    } else {
+      return GetMethod()->ToDexPc(cur_quick_frame_pc_, abort_on_failure);
+    }
   } else {
     return 0;
   }
@@ -229,35 +261,51 @@
 
 bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind,
                                             uint32_t* val) const {
-  const void* code_pointer = m->GetQuickOatCodePointer(sizeof(void*));
-  DCHECK(code_pointer != nullptr);
-  uint32_t native_pc_offset = m->NativeQuickPcOffset(cur_quick_frame_pc_);
-  CodeInfo code_info = m->GetOptimizedCodeInfo();
-  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  DCHECK_EQ(m, GetMethod());
   const DexFile::CodeItem* code_item = m->GetCodeItem();
   DCHECK(code_item != nullptr) << PrettyMethod(m);  // Can't be null or how would we compile
                                                     // its instructions?
-  DCHECK_LT(vreg, code_item->registers_size_);
   uint16_t number_of_dex_registers = code_item->registers_size_;
-  DexRegisterMap dex_register_map =
-      code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
+  DCHECK_LT(vreg, code_item->registers_size_);
+
+  ArtMethod* outer_method = *GetCurrentQuickFrame();
+  const void* code_pointer = outer_method->GetQuickOatCodePointer(sizeof(void*));
+  DCHECK(code_pointer != nullptr);
+  CodeInfo code_info = outer_method->GetOptimizedCodeInfo();
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+
+  uint32_t native_pc_offset = outer_method->NativeQuickPcOffset(cur_quick_frame_pc_);
+  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+  DCHECK(stack_map.IsValid());
+  size_t depth_in_stack_map = current_inlining_depth_ - 1;
+
+  DexRegisterMap dex_register_map = IsInInlinedFrame()
+      ? code_info.GetDexRegisterMapAtDepth(depth_in_stack_map,
+                                           code_info.GetInlineInfoOf(stack_map, encoding),
+                                           encoding,
+                                           number_of_dex_registers)
+      : code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
+
   DexRegisterLocation::Kind location_kind =
-      dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info);
+      dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info, encoding);
   switch (location_kind) {
     case DexRegisterLocation::Kind::kInStack: {
-      const int32_t offset =
-          dex_register_map.GetStackOffsetInBytes(vreg, number_of_dex_registers, code_info);
+      const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg,
+                                                                    number_of_dex_registers,
+                                                                    code_info,
+                                                                    encoding);
       const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset;
       *val = *reinterpret_cast<const uint32_t*>(addr);
       return true;
     }
     case DexRegisterLocation::Kind::kInRegister:
     case DexRegisterLocation::Kind::kInFpuRegister: {
-      uint32_t reg = dex_register_map.GetMachineRegister(vreg, number_of_dex_registers, code_info);
+      uint32_t reg =
+          dex_register_map.GetMachineRegister(vreg, number_of_dex_registers, code_info, encoding);
       return GetRegisterIfAccessible(reg, kind, val);
     }
     case DexRegisterLocation::Kind::kConstant:
-      *val = dex_register_map.GetConstant(vreg, number_of_dex_registers, code_info);
+      *val = dex_register_map.GetConstant(vreg, number_of_dex_registers, code_info, encoding);
       return true;
     case DexRegisterLocation::Kind::kNone:
       return false;
@@ -265,7 +313,10 @@
       LOG(FATAL)
           << "Unexpected location kind"
           << DexRegisterLocation::PrettyDescriptor(
-                dex_register_map.GetLocationInternalKind(vreg, number_of_dex_registers, code_info));
+                dex_register_map.GetLocationInternalKind(vreg,
+                                                         number_of_dex_registers,
+                                                         code_info,
+                                                         encoding));
       UNREACHABLE();
   }
 }
@@ -734,6 +785,28 @@
       ArtMethod* method = *cur_quick_frame_;
       while (method != nullptr) {
         SanityCheckFrame();
+
+        if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
+            && method->IsOptimized(sizeof(void*))) {
+          CodeInfo code_info = method->GetOptimizedCodeInfo();
+          StackMapEncoding encoding = code_info.ExtractEncoding();
+          uint32_t native_pc_offset = method->NativeQuickPcOffset(cur_quick_frame_pc_);
+          StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+          if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding)) {
+            InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
+            DCHECK_EQ(current_inlining_depth_, 0u);
+            for (current_inlining_depth_ = inline_info.GetDepth();
+                 current_inlining_depth_ != 0;
+                 --current_inlining_depth_) {
+              bool should_continue = VisitFrame();
+              if (UNLIKELY(!should_continue)) {
+                return;
+              }
+              cur_depth_++;
+            }
+          }
+        }
+
         bool should_continue = VisitFrame();
         if (UNLIKELY(!should_continue)) {
           return;
@@ -784,7 +857,6 @@
               << " native=" << method->IsNative()
               << " entrypoints=" << method->GetEntryPointFromQuickCompiledCode()
               << "," << method->GetEntryPointFromJni()
-              << "," << method->GetEntryPointFromInterpreter()
               << " next=" << *cur_quick_frame_;
         }
 
diff --git a/runtime/stack.h b/runtime/stack.h
index 38dfe1b..d60714f 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -36,9 +36,10 @@
 
 class ArtMethod;
 class Context;
-class ShadowFrame;
 class HandleScope;
+class InlineInfo;
 class ScopedObjectAccess;
+class ShadowFrame;
 class StackVisitor;
 class Thread;
 
@@ -94,6 +95,8 @@
   }
   ~ShadowFrame() {}
 
+  // TODO(iam): Clean references array up since they're always there,
+  // we don't need to do conditionals.
   bool HasReferenceArray() const {
     return true;
   }
@@ -148,6 +151,9 @@
     return *reinterpret_cast<unaligned_double*>(vreg);
   }
 
+  // Look up the reference given its virtual register number.
+  // If this returns non-null then this does not mean the vreg is currently a reference
+  // on non-moving collectors. Check that the raw reg with GetVReg is equal to this if not certain.
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   mirror::Object* GetVRegReference(size_t i) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK_LT(i, NumberOfVRegs());
@@ -282,6 +288,8 @@
   ShadowFrame(uint32_t num_vregs, ShadowFrame* link, ArtMethod* method,
               uint32_t dex_pc, bool has_reference_array)
       : number_of_vregs_(num_vregs), link_(link), method_(method), dex_pc_(dex_pc) {
+    // TODO(iam): Remove this parameter, it's an an artifact of portable removal
+    DCHECK(has_reference_array);
     if (has_reference_array) {
       memset(vregs_, 0, num_vregs * (sizeof(uint32_t) + sizeof(StackReference<mirror::Object>)));
     } else {
@@ -305,6 +313,15 @@
   ShadowFrame* link_;
   ArtMethod* method_;
   uint32_t dex_pc_;
+
+  // This is a two-part array:
+  //  - [0..number_of_vregs) holds the raw virtual registers, and each element here is always 4
+  //    bytes.
+  //  - [number_of_vregs..number_of_vregs*2) holds only reference registers. Each element here is
+  //    ptr-sized.
+  // In other words when a primitive is stored in vX, the second (reference) part of the array will
+  // be null. When a reference is stored in vX, the second (reference) part of the array will be a
+  // copy of vX.
   uint32_t vregs_[0];
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ShadowFrame);
@@ -425,15 +442,7 @@
   void WalkStack(bool include_transitions = false)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    if (cur_shadow_frame_ != nullptr) {
-      return cur_shadow_frame_->GetMethod();
-    } else if (cur_quick_frame_ != nullptr) {
-      return *cur_quick_frame_;
-    } else {
-      return nullptr;
-    }
-  }
+  ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsShadowFrame() const {
     return cur_shadow_frame_ != nullptr;
@@ -576,7 +585,7 @@
   }
 
   bool IsInInlinedFrame() const {
-    return false;
+    return current_inlining_depth_ != 0;
   }
 
   uintptr_t GetCurrentQuickFramePc() const {
@@ -668,6 +677,8 @@
 
   void SanityCheckFrame() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  InlineInfo GetCurrentInlineInfo() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   Thread* const thread_;
   const StackWalkKind walk_kind_;
   ShadowFrame* cur_shadow_frame_;
@@ -677,6 +688,9 @@
   size_t num_frames_;
   // Depth of the frame we're currently at.
   size_t cur_depth_;
+  // Current inlining depth of the method we are currently at.
+  // 0 if there is no inlined frame.
+  size_t current_inlining_depth_;
 
  protected:
   Context* const context_;
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index 11e7e44..741cd90 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -18,6 +18,9 @@
 
 #include <stdint.h>
 
+#include "indenter.h"
+#include "invoke_type.h"
+
 namespace art {
 
 constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex;
@@ -26,9 +29,10 @@
 
 DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind(uint16_t dex_register_number,
                                                                   uint16_t number_of_dex_registers,
-                                                                  const CodeInfo& code_info) const {
+                                                                  const CodeInfo& code_info,
+                                                                  const StackMapEncoding& enc) const {
   DexRegisterLocationCatalog dex_register_location_catalog =
-      code_info.GetDexRegisterLocationCatalog();
+      code_info.GetDexRegisterLocationCatalog(enc);
   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
       dex_register_number,
       number_of_dex_registers,
@@ -38,9 +42,10 @@
 
 DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number,
                                                            uint16_t number_of_dex_registers,
-                                                           const CodeInfo& code_info) const {
+                                                           const CodeInfo& code_info,
+                                                           const StackMapEncoding& enc) const {
   DexRegisterLocationCatalog dex_register_location_catalog =
-      code_info.GetDexRegisterLocationCatalog();
+      code_info.GetDexRegisterLocationCatalog(enc);
   size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
       dex_register_number,
       number_of_dex_registers,
@@ -48,230 +53,192 @@
   return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index);
 }
 
-// Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
-// this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
-static uint32_t LoadAt(MemoryRegion region,
-                       size_t number_of_bytes,
-                       size_t offset,
-                       bool check_max = false) {
+uint32_t StackMap::LoadAt(size_t number_of_bytes, size_t offset, bool check_max) const {
   if (number_of_bytes == 0u) {
     DCHECK(!check_max);
     return 0;
   } else if (number_of_bytes == 1u) {
-    uint8_t value = region.LoadUnaligned<uint8_t>(offset);
-    if (check_max && value == 0xFF) {
-      return -1;
-    } else {
-      return value;
-    }
+    uint8_t value = region_.LoadUnaligned<uint8_t>(offset);
+    return (check_max && value == 0xFF) ? -1 : value;
   } else if (number_of_bytes == 2u) {
-    uint16_t value = region.LoadUnaligned<uint16_t>(offset);
-    if (check_max && value == 0xFFFF) {
-      return -1;
-    } else {
-      return value;
-    }
+    uint16_t value = region_.LoadUnaligned<uint16_t>(offset);
+    return (check_max && value == 0xFFFF) ? -1 : value;
   } else if (number_of_bytes == 3u) {
-    uint16_t low = region.LoadUnaligned<uint16_t>(offset);
-    uint16_t high = region.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
+    uint16_t low = region_.LoadUnaligned<uint16_t>(offset);
+    uint16_t high = region_.LoadUnaligned<uint8_t>(offset + sizeof(uint16_t));
     uint32_t value = (high << 16) + low;
-    if (check_max && value == 0xFFFFFF) {
-      return -1;
-    } else {
-      return value;
-    }
+    return (check_max && value == 0xFFFFFF) ? -1 : value;
   } else {
     DCHECK_EQ(number_of_bytes, 4u);
-    return region.LoadUnaligned<uint32_t>(offset);
+    return region_.LoadUnaligned<uint32_t>(offset);
   }
 }
 
-static void StoreAt(MemoryRegion region, size_t number_of_bytes, size_t offset, uint32_t value) {
+void StackMap::StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const {
   if (number_of_bytes == 0u) {
     DCHECK_EQ(value, 0u);
   } else if (number_of_bytes == 1u) {
-    region.StoreUnaligned<uint8_t>(offset, value);
+    region_.StoreUnaligned<uint8_t>(offset, value);
   } else if (number_of_bytes == 2u) {
-    region.StoreUnaligned<uint16_t>(offset, value);
+    region_.StoreUnaligned<uint16_t>(offset, value);
   } else if (number_of_bytes == 3u) {
-    region.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
-    region.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
+    region_.StoreUnaligned<uint16_t>(offset, Low16Bits(value));
+    region_.StoreUnaligned<uint8_t>(offset + sizeof(uint16_t), High16Bits(value));
   } else {
-    region.StoreUnaligned<uint32_t>(offset, value);
+    region_.StoreUnaligned<uint32_t>(offset, value);
     DCHECK_EQ(number_of_bytes, 4u);
   }
 }
 
-uint32_t StackMap::GetDexPc(const CodeInfo& info) const {
-  return LoadAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset());
-}
-
-void StackMap::SetDexPc(const CodeInfo& info, uint32_t dex_pc) {
-  StoreAt(region_, info.NumberOfBytesForDexPc(), info.ComputeStackMapDexPcOffset(), dex_pc);
-}
-
-uint32_t StackMap::GetNativePcOffset(const CodeInfo& info) const {
-  return LoadAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset());
-}
-
-void StackMap::SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset) {
-  StoreAt(region_, info.NumberOfBytesForNativePc(), info.ComputeStackMapNativePcOffset(), native_pc_offset);
-}
-
-uint32_t StackMap::GetDexRegisterMapOffset(const CodeInfo& info) const {
-  return LoadAt(region_,
-                info.NumberOfBytesForDexRegisterMap(),
-                info.ComputeStackMapDexRegisterMapOffset(),
-                /* check_max */ true);
-}
-
-void StackMap::SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset) {
-  StoreAt(region_,
-          info.NumberOfBytesForDexRegisterMap(),
-          info.ComputeStackMapDexRegisterMapOffset(),
-          offset);
-}
-
-uint32_t StackMap::GetInlineDescriptorOffset(const CodeInfo& info) const {
-  if (!info.HasInlineInfo()) return kNoInlineInfo;
-  return LoadAt(region_,
-                info.NumberOfBytesForInlineInfo(),
-                info.ComputeStackMapInlineInfoOffset(),
-                /* check_max */ true);
-}
-
-void StackMap::SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset) {
-  DCHECK(info.HasInlineInfo());
-  StoreAt(region_,
-          info.NumberOfBytesForInlineInfo(),
-          info.ComputeStackMapInlineInfoOffset(),
-          offset);
-}
-
-uint32_t StackMap::GetRegisterMask(const CodeInfo& info) const {
-  return LoadAt(region_,
-                info.NumberOfBytesForRegisterMask(),
-                info.ComputeStackMapRegisterMaskOffset());
-}
-
-void StackMap::SetRegisterMask(const CodeInfo& info, uint32_t mask) {
-  StoreAt(region_,
-          info.NumberOfBytesForRegisterMask(),
-          info.ComputeStackMapRegisterMaskOffset(),
-          mask);
-}
-
-size_t StackMap::ComputeStackMapSizeInternal(size_t stack_mask_size,
-                                             size_t number_of_bytes_for_inline_info,
-                                             size_t number_of_bytes_for_dex_map,
-                                             size_t number_of_bytes_for_dex_pc,
-                                             size_t number_of_bytes_for_native_pc,
-                                             size_t number_of_bytes_for_register_mask) {
-  return stack_mask_size
-      + number_of_bytes_for_inline_info
-      + number_of_bytes_for_dex_map
-      + number_of_bytes_for_dex_pc
-      + number_of_bytes_for_native_pc
-      + number_of_bytes_for_register_mask;
-}
-
-size_t StackMap::ComputeStackMapSize(size_t stack_mask_size,
-                                     size_t inline_info_size,
-                                     size_t dex_register_map_size,
-                                     size_t dex_pc_max,
-                                     size_t native_pc_max,
-                                     size_t register_mask_max) {
-  return ComputeStackMapSizeInternal(
-      stack_mask_size,
-      inline_info_size == 0
-          ? 0
-            // + 1 to also encode kNoInlineInfo.
-          :  CodeInfo::EncodingSizeInBytes(inline_info_size + dex_register_map_size + 1),
-      // + 1 to also encode kNoDexRegisterMap.
-      CodeInfo::EncodingSizeInBytes(dex_register_map_size + 1),
-      CodeInfo::EncodingSizeInBytes(dex_pc_max),
-      CodeInfo::EncodingSizeInBytes(native_pc_max),
-      CodeInfo::EncodingSizeInBytes(register_mask_max));
-}
-
-MemoryRegion StackMap::GetStackMask(const CodeInfo& info) const {
-  return region_.Subregion(info.ComputeStackMapStackMaskOffset(), info.GetStackMaskSize());
-}
-
 static void DumpRegisterMapping(std::ostream& os,
                                 size_t dex_register_num,
                                 DexRegisterLocation location,
                                 const std::string& prefix = "v",
                                 const std::string& suffix = "") {
-  os << "      " << prefix << dex_register_num << ": "
-     << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind())
-     << " (" << location.GetValue() << ")" << suffix << '\n';
+  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';
 }
 
-void CodeInfo::DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const {
-  StackMap stack_map = GetStackMapAt(stack_map_num);
-  os << "    StackMap " << stack_map_num
-     << std::hex
-     << " (dex_pc=0x" << stack_map.GetDexPc(*this)
-     << ", native_pc_offset=0x" << stack_map.GetNativePcOffset(*this)
-     << ", dex_register_map_offset=0x" << stack_map.GetDexRegisterMapOffset(*this)
-     << ", inline_info_offset=0x" << stack_map.GetInlineDescriptorOffset(*this)
-     << ", register_mask=0x" << stack_map.GetRegisterMask(*this)
-     << std::dec
-     << ", stack_mask=0b";
-  MemoryRegion stack_mask = stack_map.GetStackMask(*this);
-  for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) {
-    os << stack_mask.LoadBit(e - i - 1);
-  }
-  os << ")\n";
-};
-
-void CodeInfo::Dump(std::ostream& os, uint16_t number_of_dex_registers) const {
+void CodeInfo::Dump(std::ostream& os,
+                    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();
-  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=" << HasInlineInfo()
-     << ", number_of_bytes_for_inline_info=" << NumberOfBytesForInlineInfo()
-     << ", number_of_bytes_for_dex_register_map=" << NumberOfBytesForDexRegisterMap()
-     << ", number_of_bytes_for_dex_pc=" << NumberOfBytesForDexPc()
-     << ", number_of_bytes_for_native_pc=" << NumberOfBytesForNativePc()
-     << ", number_of_bytes_for_register_mask=" << NumberOfBytesForRegisterMask()
-     << ")\n";
-
+  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";
   // Display the Dex register location catalog.
-  size_t number_of_location_catalog_entries = GetNumberOfDexRegisterLocationCatalogEntries();
-  size_t location_catalog_size_in_bytes = GetDexRegisterLocationCatalogSize();
-  os << "  DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries
-     << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n";
-  DexRegisterLocationCatalog dex_register_location_catalog = GetDexRegisterLocationCatalog();
-  for (size_t i = 0; i < number_of_location_catalog_entries; ++i) {
-    DexRegisterLocation location = dex_register_location_catalog.GetDexRegisterLocation(i);
-    DumpRegisterMapping(os, i, location, "entry ");
-  }
-
+  GetDexRegisterLocationCatalog(encoding).Dump(indented_os, *this);
   // Display stack maps along with (live) Dex register maps.
-  for (size_t i = 0; i < number_of_stack_maps; ++i) {
-    StackMap stack_map = GetStackMapAt(i);
-    DumpStackMapHeader(os, i);
-    if (stack_map.HasDexRegisterMap(*this)) {
-      DexRegisterMap dex_register_map = GetDexRegisterMapOf(stack_map, number_of_dex_registers);
-      // TODO: Display the bit mask of live Dex registers.
-      for (size_t j = 0; j < number_of_dex_registers; ++j) {
-        if (dex_register_map.IsDexRegisterLive(j)) {
-          size_t location_catalog_entry_index = dex_register_map.GetLocationCatalogEntryIndex(
-              j, number_of_dex_registers, number_of_location_catalog_entries);
-          DexRegisterLocation location =
-              dex_register_map.GetDexRegisterLocation(j, number_of_dex_registers, *this);
-          DumpRegisterMapping(
-              os, j, location, "v",
-              "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
-        }
-      }
+  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,
+                     *this,
+                     encoding,
+                     code_offset,
+                     number_of_dex_registers,
+                     " " + std::to_string(i));
     }
   }
-  // TODO: Dump the stack map's inline information.
+  // TODO: Dump the stack map's inline information? We need to know more from the caller:
+  //       we need to know the number of dex registers for each inlined method.
+}
+
+void DexRegisterLocationCatalog::Dump(std::ostream& os, 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
+      << "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 ");
+  }
+}
+
+void DexRegisterMap::Dump(std::ostream& os,
+                          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)) {
+      size_t location_catalog_entry_index = GetLocationCatalogEntryIndex(
+          j, number_of_dex_registers, number_of_location_catalog_entries);
+      DexRegisterLocation location = GetDexRegisterLocation(j,
+                                                            number_of_dex_registers,
+                                                            code_info,
+                                                            encoding);
+      DumpRegisterMapping(
+          indented_os, j, location, "v",
+          "\t[entry " + std::to_string(static_cast<int>(location_catalog_entry_index)) + "]");
+    }
+  }
+}
+
+void StackMap::Dump(std::ostream& os,
+                    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";
+  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);
+  }
+  indented_os << ")\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);
+  }
+  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);
+  }
+}
+
+void InlineInfo::Dump(std::ostream& os,
+                      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";
+
+  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";
+    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]);
+    }
+  }
 }
 
 }  // namespace art
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 6cc1709..4e42008 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -32,6 +32,7 @@
 static constexpr size_t kVRegSize = 4;
 
 class CodeInfo;
+class StackMapEncoding;
 
 /**
  * Classes in the following file are wrapper on stack map information backed
@@ -39,47 +40,6 @@
  * their own fields.
  */
 
-/**
- * Inline information for a specific PC. The information is of the form:
- * [inlining_depth, [method_dex reference]+]
- */
-class InlineInfo {
- public:
-  explicit InlineInfo(MemoryRegion region) : region_(region) {}
-
-  uint8_t GetDepth() const {
-    return region_.LoadUnaligned<uint8_t>(kDepthOffset);
-  }
-
-  void SetDepth(uint8_t depth) {
-    region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
-  }
-
-  uint32_t GetMethodReferenceIndexAtDepth(uint8_t depth) const {
-    return region_.LoadUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize());
-  }
-
-  void SetMethodReferenceIndexAtDepth(uint8_t depth, uint32_t index) {
-    region_.StoreUnaligned<uint32_t>(kFixedSize + depth * SingleEntrySize(), index);
-  }
-
-  static size_t SingleEntrySize() {
-    return sizeof(uint32_t);
-  }
-
- private:
-  // TODO: Instead of plain types such as "uint8_t", introduce
-  // typedefs (and document the memory layout of InlineInfo).
-  static constexpr int kDepthOffset = 0;
-  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
-
-  MemoryRegion region_;
-
-  friend class CodeInfo;
-  friend class StackMap;
-  friend class StackMapStream;
-};
-
 // Dex register location container used by DexRegisterMap and StackMapStream.
 class DexRegisterLocation {
  public:
@@ -397,6 +357,8 @@
     return region_.size();
   }
 
+  void Dump(std::ostream& os, 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
   // mapped to a DexRegisterLocation::Kind::kNone location).
@@ -476,26 +438,30 @@
   // Get the surface kind of Dex register `dex_register_number`.
   DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number,
                                             uint16_t number_of_dex_registers,
-                                            const CodeInfo& code_info) const {
+                                            const CodeInfo& code_info,
+                                            const StackMapEncoding& enc) const {
     return DexRegisterLocation::ConvertToSurfaceKind(
-        GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info));
+        GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc));
   }
 
   // Get the internal kind of Dex register `dex_register_number`.
   DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number,
                                                     uint16_t number_of_dex_registers,
-                                                    const CodeInfo& code_info) const;
+                                                    const CodeInfo& code_info,
+                                                    const StackMapEncoding& enc) const;
 
   // Get the Dex register location `dex_register_number`.
   DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number,
                                              uint16_t number_of_dex_registers,
-                                             const CodeInfo& code_info) const;
+                                             const CodeInfo& code_info,
+                                             const StackMapEncoding& enc) const;
 
   int32_t GetStackOffsetInBytes(uint16_t dex_register_number,
                                 uint16_t number_of_dex_registers,
-                                const CodeInfo& code_info) const {
+                                const CodeInfo& code_info,
+                                const StackMapEncoding& enc) const {
     DexRegisterLocation location =
-        GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info);
+        GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
     DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack);
     // GetDexRegisterLocation returns the offset in bytes.
     return location.GetValue();
@@ -503,18 +469,21 @@
 
   int32_t GetConstant(uint16_t dex_register_number,
                       uint16_t number_of_dex_registers,
-                      const CodeInfo& code_info) const {
+                      const CodeInfo& code_info,
+                      const StackMapEncoding& enc) const {
     DexRegisterLocation location =
-        GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info);
-    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant);
+        GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
+    DCHECK(location.GetKind() == DexRegisterLocation::Kind::kConstant)
+        << DexRegisterLocation::PrettyDescriptor(location.GetKind());
     return location.GetValue();
   }
 
   int32_t GetMachineRegister(uint16_t dex_register_number,
                              uint16_t number_of_dex_registers,
-                             const CodeInfo& code_info) const {
+                             const CodeInfo& code_info,
+                             const StackMapEncoding& enc) const {
     DexRegisterLocation location =
-        GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info);
+        GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc);
     DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister
            || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister)
         << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
@@ -641,6 +610,8 @@
     return region_.size();
   }
 
+  void Dump(std::ostream& o, const CodeInfo& code_info, uint16_t number_of_dex_registers) const;
+
  private:
   // Return the index in the Dex register map corresponding to the Dex
   // register number `dex_register_number`.
@@ -664,6 +635,111 @@
   friend class StackMapStream;
 };
 
+class StackMapEncoding {
+ public:
+  StackMapEncoding() {}
+
+  StackMapEncoding(size_t stack_mask_size,
+                   size_t bytes_for_inline_info,
+                   size_t bytes_for_dex_register_map,
+                   size_t bytes_for_dex_pc,
+                   size_t bytes_for_native_pc,
+                   size_t bytes_for_register_mask)
+      : bytes_for_stack_mask_(stack_mask_size),
+        bytes_for_inline_info_(bytes_for_inline_info),
+        bytes_for_dex_register_map_(bytes_for_dex_register_map),
+        bytes_for_dex_pc_(bytes_for_dex_pc),
+        bytes_for_native_pc_(bytes_for_native_pc),
+        bytes_for_register_mask_(bytes_for_register_mask) {}
+
+  static StackMapEncoding CreateFromSizes(size_t stack_mask_size,
+                                          size_t inline_info_size,
+                                          size_t dex_register_map_size,
+                                          size_t dex_pc_max,
+                                          size_t native_pc_max,
+                                          size_t register_mask_max) {
+    return StackMapEncoding(
+        stack_mask_size,
+        // + 1 to also encode kNoInlineInfo: if an inline info offset
+        // is at 0xFF, we want to overflow to a larger encoding, because it will
+        // conflict with kNoInlineInfo.
+        // The offset is relative to the dex register map. TODO: Change this.
+        inline_info_size == 0
+          ? 0
+          : EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1),
+        // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
+        // is at 0xFF, we want to overflow to a larger encoding, because it will
+        // conflict with kNoDexRegisterMap.
+        EncodingSizeInBytes(dex_register_map_size + 1),
+        EncodingSizeInBytes(dex_pc_max),
+        EncodingSizeInBytes(native_pc_max),
+        EncodingSizeInBytes(register_mask_max));
+  }
+
+  // Get the size of one stack map of this CodeInfo object, in bytes.
+  // All stack maps of a CodeInfo have the same size.
+  size_t ComputeStackMapSize() const {
+    return bytes_for_register_mask_
+         + bytes_for_stack_mask_
+         + bytes_for_inline_info_
+         + bytes_for_dex_register_map_
+         + bytes_for_dex_pc_
+         + bytes_for_native_pc_;
+  }
+
+  bool HasInlineInfo() const { return bytes_for_inline_info_ > 0; }
+
+  size_t NumberOfBytesForStackMask() const { return bytes_for_stack_mask_; }
+  size_t NumberOfBytesForInlineInfo() const { return bytes_for_inline_info_; }
+  size_t NumberOfBytesForDexRegisterMap() const { return bytes_for_dex_register_map_; }
+  size_t NumberOfBytesForDexPc() const { return bytes_for_dex_pc_; }
+  size_t NumberOfBytesForNativePc() const { return bytes_for_native_pc_; }
+  size_t NumberOfBytesForRegisterMask() const { return bytes_for_register_mask_; }
+
+  size_t ComputeStackMapRegisterMaskOffset() const {
+    return kRegisterMaskOffset;
+  }
+
+  size_t ComputeStackMapStackMaskOffset() const {
+    return ComputeStackMapRegisterMaskOffset() + bytes_for_register_mask_;
+  }
+
+  size_t ComputeStackMapDexPcOffset() const {
+    return ComputeStackMapStackMaskOffset() + bytes_for_stack_mask_;
+  }
+
+  size_t ComputeStackMapNativePcOffset() const {
+    return ComputeStackMapDexPcOffset() + bytes_for_dex_pc_;
+  }
+
+  size_t ComputeStackMapDexRegisterMapOffset() const {
+    return ComputeStackMapNativePcOffset() + bytes_for_native_pc_;
+  }
+
+  size_t ComputeStackMapInlineInfoOffset() const {
+    return ComputeStackMapDexRegisterMapOffset() + bytes_for_dex_register_map_;
+  }
+
+ private:
+  static size_t EncodingSizeInBytes(size_t max_element) {
+    DCHECK(IsUint<32>(max_element));
+    return (max_element == 0) ? 0
+         : IsUint<8>(max_element) ? 1
+         : IsUint<16>(max_element) ? 2
+         : IsUint<24>(max_element) ? 3
+         : 4;
+  }
+
+  static constexpr int kRegisterMaskOffset = 0;
+
+  size_t bytes_for_stack_mask_;
+  size_t bytes_for_inline_info_;
+  size_t bytes_for_dex_register_map_;
+  size_t bytes_for_dex_pc_;
+  size_t bytes_for_native_pc_;
+  size_t bytes_for_register_mask_;
+};
+
 /**
  * A Stack Map holds compilation information for a specific PC necessary for:
  * - Mapping it to a dex PC,
@@ -675,49 +751,85 @@
  * The information is of the form:
  * [dex_pc, native_pc_offset, dex_register_map_offset, inlining_info_offset, register_mask,
  * stack_mask].
- *
- * Note that register_mask is fixed size, but stack_mask is variable size, depending on the
- * stack size of a method.
  */
 class StackMap {
  public:
+  StackMap() {}
   explicit StackMap(MemoryRegion region) : region_(region) {}
 
-  uint32_t GetDexPc(const CodeInfo& info) const;
+  bool IsValid() const { return region_.pointer() != nullptr; }
 
-  void SetDexPc(const CodeInfo& info, uint32_t dex_pc);
-
-  uint32_t GetNativePcOffset(const CodeInfo& info) const;
-
-  void SetNativePcOffset(const CodeInfo& info, uint32_t native_pc_offset);
-
-  uint32_t GetDexRegisterMapOffset(const CodeInfo& info) const;
-
-  void SetDexRegisterMapOffset(const CodeInfo& info, uint32_t offset);
-
-  uint32_t GetInlineDescriptorOffset(const CodeInfo& info) const;
-
-  void SetInlineDescriptorOffset(const CodeInfo& info, uint32_t offset);
-
-  uint32_t GetRegisterMask(const CodeInfo& info) const;
-
-  void SetRegisterMask(const CodeInfo& info, uint32_t mask);
-
-  MemoryRegion GetStackMask(const CodeInfo& info) const;
-
-  void SetStackMask(const CodeInfo& info, const BitVector& sp_map) {
-    MemoryRegion region = GetStackMask(info);
-    for (size_t i = 0; i < region.size_in_bits(); i++) {
-      region.StoreBit(i, sp_map.IsBitSet(i));
-    }
+  uint32_t GetDexPc(const StackMapEncoding& encoding) const {
+    return LoadAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset());
   }
 
-  bool HasDexRegisterMap(const CodeInfo& info) const {
-    return GetDexRegisterMapOffset(info) != kNoDexRegisterMap;
+  void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) {
+    StoreAt(encoding.NumberOfBytesForDexPc(), encoding.ComputeStackMapDexPcOffset(), dex_pc);
   }
 
-  bool HasInlineInfo(const CodeInfo& info) const {
-    return GetInlineDescriptorOffset(info) != kNoInlineInfo;
+  uint32_t GetNativePcOffset(const StackMapEncoding& encoding) const {
+    return LoadAt(encoding.NumberOfBytesForNativePc(), encoding.ComputeStackMapNativePcOffset());
+  }
+
+  void SetNativePcOffset(const StackMapEncoding& encoding, uint32_t native_pc_offset) {
+    StoreAt(encoding.NumberOfBytesForNativePc(),
+            encoding.ComputeStackMapNativePcOffset(),
+            native_pc_offset);
+  }
+
+  uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const {
+    return LoadAt(encoding.NumberOfBytesForDexRegisterMap(),
+                  encoding.ComputeStackMapDexRegisterMapOffset(),
+                  /* check_max */ true);
+  }
+
+  void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) {
+    StoreAt(encoding.NumberOfBytesForDexRegisterMap(),
+            encoding.ComputeStackMapDexRegisterMapOffset(),
+            offset);
+  }
+
+  uint32_t GetInlineDescriptorOffset(const StackMapEncoding& encoding) const {
+    if (!encoding.HasInlineInfo()) return kNoInlineInfo;
+    return LoadAt(encoding.NumberOfBytesForInlineInfo(),
+                  encoding.ComputeStackMapInlineInfoOffset(),
+                  /* check_max */ true);
+  }
+
+  void SetInlineDescriptorOffset(const StackMapEncoding& encoding, uint32_t offset) {
+    DCHECK(encoding.HasInlineInfo());
+    StoreAt(encoding.NumberOfBytesForInlineInfo(),
+            encoding.ComputeStackMapInlineInfoOffset(),
+            offset);
+  }
+
+  uint32_t GetRegisterMask(const StackMapEncoding& encoding) const {
+    return LoadAt(encoding.NumberOfBytesForRegisterMask(),
+                  encoding.ComputeStackMapRegisterMaskOffset());
+  }
+
+  void SetRegisterMask(const StackMapEncoding& encoding, uint32_t mask) {
+    StoreAt(encoding.NumberOfBytesForRegisterMask(),
+            encoding.ComputeStackMapRegisterMaskOffset(),
+            mask);
+  }
+
+  MemoryRegion GetStackMask(const StackMapEncoding& encoding) const {
+    return region_.Subregion(encoding.ComputeStackMapStackMaskOffset(),
+                             encoding.NumberOfBytesForStackMask());
+  }
+
+  void SetStackMask(const StackMapEncoding& encoding, const BitVector& sp_map) {
+    MemoryRegion region = GetStackMask(encoding);
+    sp_map.CopyTo(region.start(), region.size());
+  }
+
+  bool HasDexRegisterMap(const StackMapEncoding& encoding) const {
+    return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap;
+  }
+
+  bool HasInlineInfo(const StackMapEncoding& encoding) const {
+    return GetInlineDescriptorOffset(encoding) != kNoInlineInfo;
   }
 
   bool Equals(const StackMap& other) const {
@@ -725,12 +837,12 @@
        && region_.size() == other.region_.size();
   }
 
-  static size_t ComputeStackMapSize(size_t stack_mask_size,
-                                    size_t inline_info_size,
-                                    size_t dex_register_map_size,
-                                    size_t dex_pc_max,
-                                    size_t native_pc_max,
-                                    size_t register_mask_max);
+  void Dump(std::ostream& os,
+            const CodeInfo& code_info,
+            const StackMapEncoding& encoding,
+            uint32_t code_offset,
+            uint16_t number_of_dex_registers,
+            const std::string& header_suffix = "") const;
 
   // Special (invalid) offset for the DexRegisterMapOffset field meaning
   // that there is no Dex register map for this stack map.
@@ -741,25 +853,105 @@
   static constexpr uint32_t kNoInlineInfo = -1;
 
  private:
-  static size_t ComputeStackMapSizeInternal(size_t stack_mask_size,
-                                            size_t number_of_bytes_for_inline_info,
-                                            size_t number_of_bytes_for_dex_map,
-                                            size_t number_of_bytes_for_dex_pc,
-                                            size_t number_of_bytes_for_native_pc,
-                                            size_t number_of_bytes_for_register_mask);
-
   // TODO: Instead of plain types such as "uint32_t", introduce
   // typedefs (and document the memory layout of StackMap).
-  static constexpr int kRegisterMaskOffset = 0;
   static constexpr int kFixedSize = 0;
 
+  // Loads `number_of_bytes` at the given `offset` and assemble a uint32_t. If `check_max` is true,
+  // this method converts a maximum value of size `number_of_bytes` into a uint32_t 0xFFFFFFFF.
+  uint32_t LoadAt(size_t number_of_bytes, size_t offset, bool check_max = false) const;
+  void StoreAt(size_t number_of_bytes, size_t offset, uint32_t value) const;
+
+  MemoryRegion region_;
+
+  friend class StackMapStream;
+};
+
+/**
+ * Inline information for a specific PC. The information is of the form:
+ * [inlining_depth, [dex_pc, method_index, dex_register_map_offset]+]
+ */
+class InlineInfo {
+ public:
+  explicit InlineInfo(MemoryRegion region) : region_(region) {}
+
+  uint8_t GetDepth() const {
+    return region_.LoadUnaligned<uint8_t>(kDepthOffset);
+  }
+
+  void SetDepth(uint8_t depth) {
+    region_.StoreUnaligned<uint8_t>(kDepthOffset, depth);
+  }
+
+  uint32_t GetMethodIndexAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
+  }
+
+  void SetMethodIndexAtDepth(uint8_t depth, uint32_t index) {
+    region_.StoreUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
+  }
+
+  uint32_t GetDexPcAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
+  }
+
+  void SetDexPcAtDepth(uint8_t depth, uint32_t dex_pc) {
+    region_.StoreUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
+  }
+
+  uint8_t GetInvokeTypeAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint8_t>(
+        kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
+  }
+
+  void SetInvokeTypeAtDepth(uint8_t depth, uint8_t invoke_type) {
+    region_.StoreUnaligned<uint8_t>(
+        kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
+  }
+
+  uint32_t GetDexRegisterMapOffsetAtDepth(uint8_t depth) const {
+    return region_.LoadUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
+  }
+
+  void SetDexRegisterMapOffsetAtDepth(uint8_t depth, uint32_t offset) {
+    region_.StoreUnaligned<uint32_t>(
+        kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
+  }
+
+  bool HasDexRegisterMapAtDepth(uint8_t depth) const {
+    return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
+  }
+
+  static size_t SingleEntrySize() {
+    return kFixedEntrySize;
+  }
+
+  void Dump(std::ostream& os, const CodeInfo& info, uint16_t* number_of_dex_registers) const;
+
+ private:
+  // TODO: Instead of plain types such as "uint8_t", introduce
+  // typedefs (and document the memory layout of InlineInfo).
+  static constexpr int kDepthOffset = 0;
+  static constexpr int kFixedSize = kDepthOffset + sizeof(uint8_t);
+
+  static constexpr int kMethodIndexOffset = 0;
+  static constexpr int kDexPcOffset = kMethodIndexOffset + sizeof(uint32_t);
+  static constexpr int kInvokeTypeOffset = kDexPcOffset + sizeof(uint32_t);
+  static constexpr int kDexRegisterMapOffset = kInvokeTypeOffset + sizeof(uint8_t);
+  static constexpr int kFixedEntrySize = kDexRegisterMapOffset + sizeof(uint32_t);
+
   MemoryRegion region_;
 
   friend class CodeInfo;
+  friend class StackMap;
   friend class StackMapStream;
 };
 
-
 /**
  * Wrapper around all compiler information collected for a method.
  * The information is of the form:
@@ -775,39 +967,23 @@
     region_ = MemoryRegion(const_cast<void*>(data), size);
   }
 
-  static size_t EncodingSizeInBytes(size_t max_element) {
-    DCHECK(IsUint<32>(max_element));
-    return (max_element == 0) ? 0
-         : IsUint<8>(max_element) ? 1
-         : IsUint<16>(max_element) ? 2
-         : IsUint<24>(max_element) ? 3
-         : 4;
+  StackMapEncoding ExtractEncoding() const {
+    return StackMapEncoding(region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset),
+                            GetNumberOfBytesForEncoding(kInlineInfoBitOffset),
+                            GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset),
+                            GetNumberOfBytesForEncoding(kDexPcBitOffset),
+                            GetNumberOfBytesForEncoding(kNativePcBitOffset),
+                            GetNumberOfBytesForEncoding(kRegisterMaskBitOffset));
   }
 
-  void SetEncoding(size_t inline_info_size,
-                   size_t dex_register_map_size,
-                   size_t dex_pc_max,
-                   size_t native_pc_max,
-                   size_t register_mask_max) {
-    if (inline_info_size != 0) {
-      region_.StoreBit(kHasInlineInfoBitOffset, 1);
-      // + 1 to also encode kNoInlineInfo: if an inline info offset
-      // is at 0xFF, we want to overflow to a larger encoding, because it will
-      // conflict with kNoInlineInfo.
-      // The offset is relative to the dex register map. TODO: Change this.
-      SetEncodingAt(kInlineInfoBitOffset,
-                    EncodingSizeInBytes(dex_register_map_size + inline_info_size + 1));
-    } else {
-      region_.StoreBit(kHasInlineInfoBitOffset, 0);
-      SetEncodingAt(kInlineInfoBitOffset, 0);
-    }
-    // + 1 to also encode kNoDexRegisterMap: if a dex register map offset
-    // is at 0xFF, we want to overflow to a larger encoding, because it will
-    // conflict with kNoDexRegisterMap.
-    SetEncodingAt(kDexRegisterMapBitOffset, EncodingSizeInBytes(dex_register_map_size + 1));
-    SetEncodingAt(kDexPcBitOffset, EncodingSizeInBytes(dex_pc_max));
-    SetEncodingAt(kNativePcBitOffset, EncodingSizeInBytes(native_pc_max));
-    SetEncodingAt(kRegisterMaskBitOffset, EncodingSizeInBytes(register_mask_max));
+  void SetEncoding(const StackMapEncoding& encoding) {
+    region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, encoding.NumberOfBytesForStackMask());
+    region_.StoreBit(kHasInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo() != 0);
+    SetEncodingAt(kInlineInfoBitOffset, encoding.NumberOfBytesForInlineInfo());
+    SetEncodingAt(kDexRegisterMapBitOffset, encoding.NumberOfBytesForDexRegisterMap());
+    SetEncodingAt(kDexPcBitOffset, encoding.NumberOfBytesForDexPc());
+    SetEncodingAt(kNativePcBitOffset, encoding.NumberOfBytesForNativePc());
+    SetEncodingAt(kRegisterMaskBitOffset, encoding.NumberOfBytesForRegisterMask());
   }
 
   void SetEncodingAt(size_t bit_offset, size_t number_of_bytes) {
@@ -828,68 +1004,15 @@
     return region_.LoadBit(kHasInlineInfoBitOffset);
   }
 
-  size_t NumberOfBytesForInlineInfo() const {
-    return GetNumberOfBytesForEncoding(kInlineInfoBitOffset);
-  }
-
-  size_t NumberOfBytesForDexRegisterMap() const {
-    return GetNumberOfBytesForEncoding(kDexRegisterMapBitOffset);
-  }
-
-  size_t NumberOfBytesForRegisterMask() const {
-    return GetNumberOfBytesForEncoding(kRegisterMaskBitOffset);
-  }
-
-  size_t NumberOfBytesForNativePc() const {
-    return GetNumberOfBytesForEncoding(kNativePcBitOffset);
-  }
-
-  size_t NumberOfBytesForDexPc() const {
-    return GetNumberOfBytesForEncoding(kDexPcBitOffset);
-  }
-
-  size_t ComputeStackMapRegisterMaskOffset() const {
-    return StackMap::kRegisterMaskOffset;
-  }
-
-  size_t ComputeStackMapStackMaskOffset() const {
-    return ComputeStackMapRegisterMaskOffset()
-        + (NumberOfBytesForRegisterMask() * sizeof(uint8_t));
-  }
-
-  size_t ComputeStackMapDexPcOffset() const {
-    return ComputeStackMapStackMaskOffset() + GetStackMaskSize();
-  }
-
-  size_t ComputeStackMapNativePcOffset() const {
-    return ComputeStackMapDexPcOffset()
-        + (NumberOfBytesForDexPc() * sizeof(uint8_t));
-  }
-
-  size_t ComputeStackMapDexRegisterMapOffset() const {
-    return ComputeStackMapNativePcOffset()
-        + (NumberOfBytesForNativePc() * sizeof(uint8_t));
-  }
-
-  size_t ComputeStackMapInlineInfoOffset() const {
-    CHECK(HasInlineInfo());
-    return ComputeStackMapDexRegisterMapOffset()
-        + (NumberOfBytesForDexRegisterMap() * sizeof(uint8_t));
-  }
-
-  uint32_t GetDexRegisterLocationCatalogOffset() const {
-    return kFixedSize;
-  }
-
-  DexRegisterLocationCatalog GetDexRegisterLocationCatalog() const {
+  DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const StackMapEncoding& encoding) const {
     return DexRegisterLocationCatalog(region_.Subregion(
-        GetDexRegisterLocationCatalogOffset(),
-        GetDexRegisterLocationCatalogSize()));
+        GetDexRegisterLocationCatalogOffset(encoding),
+        GetDexRegisterLocationCatalogSize(encoding)));
   }
 
-  StackMap GetStackMapAt(size_t i) const {
-    size_t size = StackMapSize();
-    return StackMap(GetStackMaps().Subregion(i * size, size));
+  StackMap GetStackMapAt(size_t i, const StackMapEncoding& encoding) const {
+    size_t stack_map_size = encoding.ComputeStackMapSize();
+    return StackMap(GetStackMaps(encoding).Subregion(i * stack_map_size, stack_map_size));
   }
 
   uint32_t GetOverallSize() const {
@@ -908,19 +1031,11 @@
     region_.StoreUnaligned<uint32_t>(kNumberOfDexRegisterLocationCatalogEntriesOffset, num_entries);
   }
 
-  uint32_t GetDexRegisterLocationCatalogSize() const {
-    return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(),
+  uint32_t GetDexRegisterLocationCatalogSize(const StackMapEncoding& encoding) const {
+    return ComputeDexRegisterLocationCatalogSize(GetDexRegisterLocationCatalogOffset(encoding),
                                                  GetNumberOfDexRegisterLocationCatalogEntries());
   }
 
-  uint32_t GetStackMaskSize() const {
-    return region_.LoadUnaligned<uint32_t>(kStackMaskSizeOffset);
-  }
-
-  void SetStackMaskSize(uint32_t size) {
-    region_.StoreUnaligned<uint32_t>(kStackMaskSizeOffset, size);
-  }
-
   size_t GetNumberOfStackMaps() const {
     return region_.LoadUnaligned<uint32_t>(kNumberOfStackMapsOffset);
   }
@@ -929,70 +1044,86 @@
     region_.StoreUnaligned<uint32_t>(kNumberOfStackMapsOffset, number_of_stack_maps);
   }
 
-  // Get the size of one stack map of this CodeInfo object, in bytes.
-  // All stack maps of a CodeInfo have the same size.
-  size_t StackMapSize() const {
-    return StackMap::ComputeStackMapSizeInternal(GetStackMaskSize(),
-                                                 NumberOfBytesForInlineInfo(),
-                                                 NumberOfBytesForDexRegisterMap(),
-                                                 NumberOfBytesForDexPc(),
-                                                 NumberOfBytesForNativePc(),
-                                                 NumberOfBytesForRegisterMask());
-  }
-
   // Get the size all the stack maps of this CodeInfo object, in bytes.
-  size_t GetStackMapsSize() const {
-    return StackMapSize() * GetNumberOfStackMaps();
+  size_t GetStackMapsSize(const StackMapEncoding& encoding) const {
+    return encoding.ComputeStackMapSize() * GetNumberOfStackMaps();
   }
 
-  size_t GetDexRegisterMapsOffset() const {
-    return GetStackMapsOffset() + GetStackMapsSize();
+  uint32_t GetDexRegisterLocationCatalogOffset(const StackMapEncoding& encoding) const {
+    return GetStackMapsOffset() + GetStackMapsSize(encoding);
+  }
+
+  size_t GetDexRegisterMapsOffset(const StackMapEncoding& encoding) const {
+    return GetDexRegisterLocationCatalogOffset(encoding)
+         + GetDexRegisterLocationCatalogSize(encoding);
   }
 
   uint32_t GetStackMapsOffset() const {
-    return GetDexRegisterLocationCatalogOffset() + GetDexRegisterLocationCatalogSize();
+    return kFixedSize;
   }
 
-  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, uint32_t number_of_dex_registers) const {
-    DCHECK(stack_map.HasDexRegisterMap(*this));
-    uint32_t offset = GetDexRegisterMapsOffset() + stack_map.GetDexRegisterMapOffset(*this);
+  DexRegisterMap GetDexRegisterMapOf(StackMap stack_map,
+                                     const StackMapEncoding& encoding,
+                                     uint32_t number_of_dex_registers) const {
+    DCHECK(stack_map.HasDexRegisterMap(encoding));
+    uint32_t offset = GetDexRegisterMapsOffset(encoding)
+                      + stack_map.GetDexRegisterMapOffset(encoding);
     size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
     return DexRegisterMap(region_.Subregion(offset, size));
   }
 
-  InlineInfo GetInlineInfoOf(StackMap stack_map) const {
-    DCHECK(stack_map.HasInlineInfo(*this));
-    uint32_t offset = stack_map.GetInlineDescriptorOffset(*this) + GetDexRegisterMapsOffset();
+  // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`.
+  DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth,
+                                          InlineInfo inline_info,
+                                          const StackMapEncoding& encoding,
+                                          uint32_t number_of_dex_registers) const {
+    DCHECK(inline_info.HasDexRegisterMapAtDepth(depth));
+    uint32_t offset = GetDexRegisterMapsOffset(encoding)
+                      + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
+    size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers);
+    return DexRegisterMap(region_.Subregion(offset, size));
+  }
+
+  InlineInfo GetInlineInfoOf(StackMap stack_map, const StackMapEncoding& encoding) const {
+    DCHECK(stack_map.HasInlineInfo(encoding));
+    uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding)
+                      + GetDexRegisterMapsOffset(encoding);
     uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
     return InlineInfo(region_.Subregion(offset,
         InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
   }
 
-  StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
+  StackMap GetStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
-      StackMap stack_map = GetStackMapAt(i);
-      if (stack_map.GetDexPc(*this) == dex_pc) {
+      StackMap stack_map = GetStackMapAt(i, encoding);
+      if (stack_map.GetDexPc(encoding) == dex_pc) {
         return stack_map;
       }
     }
-    LOG(FATAL) << "Unreachable";
-    UNREACHABLE();
+    return StackMap();
   }
 
-  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const {
+  StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
+                                        const StackMapEncoding& encoding) const {
     // TODO: stack maps are sorted by native pc, we can do a binary search.
     for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
-      StackMap stack_map = GetStackMapAt(i);
-      if (stack_map.GetNativePcOffset(*this) == native_pc_offset) {
+      StackMap stack_map = GetStackMapAt(i, encoding);
+      if (stack_map.GetNativePcOffset(encoding) == native_pc_offset) {
         return stack_map;
       }
     }
-    LOG(FATAL) << "Unreachable";
-    UNREACHABLE();
+    return StackMap();
   }
 
-  void Dump(std::ostream& os, uint16_t number_of_dex_registers) const;
-  void DumpStackMapHeader(std::ostream& os, size_t stack_map_num) const;
+  // Dump this CodeInfo object on `os`.  `code_offset` is the (absolute)
+  // native PC of the compiled method and `number_of_dex_registers` the
+  // 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,
+            uint32_t code_offset,
+            uint16_t number_of_dex_registers,
+            bool dump_stack_maps) const;
 
  private:
   // TODO: Instead of plain types such as "uint32_t", introduce
@@ -1013,10 +1144,10 @@
   static constexpr int kNativePcBitOffset = kDexPcBitOffset + 3;
   static constexpr int kRegisterMaskBitOffset = kNativePcBitOffset + 3;
 
-  MemoryRegion GetStackMaps() const {
+  MemoryRegion GetStackMaps(const StackMapEncoding& encoding) const {
     return region_.size() == 0
         ? MemoryRegion()
-        : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize());
+        : region_.Subregion(GetStackMapsOffset(), GetStackMapsSize(encoding));
   }
 
   // Compute the size of the Dex register map associated to the stack map at
diff --git a/runtime/stride_iterator.h b/runtime/stride_iterator.h
index bd622f3..d8d21aa 100644
--- a/runtime/stride_iterator.h
+++ b/runtime/stride_iterator.h
@@ -62,6 +62,7 @@
 
  private:
   uintptr_t ptr_;
+  // Not const for operator=.
   size_t stride_;
 };
 
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index f7ef894..5f965f1 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 {
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index f314f61..37a86f1 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1277,7 +1277,8 @@
   tlsPtr_.name = new std::string(kThreadNameDuringStartup);
   tlsPtr_.nested_signal_state = static_cast<jmp_buf*>(malloc(sizeof(jmp_buf)));
 
-  CHECK_EQ((sizeof(Thread) % 4), 0U) << sizeof(Thread);
+  static_assert((sizeof(Thread) % 4) == 0U,
+                "art::Thread has a size which is not a multiple of 4.");
   tls32_.state_and_flags.as_struct.flags = 0;
   tls32_.state_and_flags.as_struct.state = kNative;
   memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes));
@@ -2326,8 +2327,10 @@
         const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m, sizeof(void*));
         uintptr_t native_pc_offset = m->NativeQuickPcOffset(GetCurrentQuickFramePc(), entry_point);
         CodeInfo code_info = m->GetOptimizedCodeInfo();
-        StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
-        MemoryRegion mask = map.GetStackMask(code_info);
+        StackMapEncoding encoding = code_info.ExtractEncoding();
+        StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
+        DCHECK(map.IsValid());
+        MemoryRegion mask = map.GetStackMask(encoding);
         // Visit stack entries that hold pointers.
         for (size_t i = 0; i < mask.size_in_bits(); ++i) {
           if (mask.LoadBit(i)) {
@@ -2343,7 +2346,7 @@
           }
         }
         // Visit callee-save registers that hold pointers.
-        uint32_t register_mask = map.GetRegisterMask(code_info);
+        uint32_t register_mask = map.GetRegisterMask(encoding);
         for (size_t i = 0; i < BitSizeOf<uint32_t>(); ++i) {
           if (register_mask & (1 << i)) {
             mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(i));
@@ -2359,8 +2362,7 @@
         // Can't be null or how would we compile its instructions?
         DCHECK(code_item != nullptr) << PrettyMethod(m);
         NativePcOffsetToReferenceMap map(native_gc_map);
-        size_t num_regs = std::min(map.RegWidth() * 8,
-                                   static_cast<size_t>(code_item->registers_size_));
+        size_t num_regs = map.RegWidth() * 8;
         if (num_regs > 0) {
           Runtime* runtime = Runtime::Current();
           const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(m, sizeof(void*));
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index b697b43..7e8128f 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -28,7 +28,6 @@
 #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"
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/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index e3999c1..09db7cd 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -583,6 +583,7 @@
     case VERIFY_ERROR_ACCESS_METHOD:
     case VERIFY_ERROR_INSTANTIATION:
     case VERIFY_ERROR_CLASS_CHANGE:
+    case VERIFY_ERROR_FORCE_INTERPRETER:
       if (Runtime::Current()->IsAotCompiler() || !can_load_classes_) {
         // If we're optimistically running verification at compile time, turn NO_xxx, ACCESS_xxx,
         // class change and instantiation errors into soft verification errors so that we re-verify
@@ -1022,12 +1023,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;
@@ -1125,12 +1135,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;
@@ -1799,9 +1818,13 @@
           DCHECK(!return_type.IsUninitializedReference());
           const uint32_t vregA = inst->VRegA_11x();
           const RegType& reg_type = work_line_->GetRegisterType(this, vregA);
-          // Disallow returning uninitialized values and verify that the reference in vAA is an
-          // instance of the "return_type"
-          if (reg_type.IsUninitializedTypes()) {
+          // Disallow returning undefined, conflict & uninitialized values and verify that the
+          // reference in vAA is an instance of the "return_type."
+          if (reg_type.IsUndefined()) {
+            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning undefined register";
+          } else if (reg_type.IsConflict()) {
+            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "returning register with conflict";
+          } else if (reg_type.IsUninitializedTypes()) {
             Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "returning uninitialized object '"
                                               << reg_type << "'";
           } else if (!return_type.IsAssignableFrom(reg_type)) {
@@ -2437,10 +2460,7 @@
     case Instruction::INVOKE_DIRECT:
     case Instruction::INVOKE_DIRECT_RANGE: {
       bool is_range = (inst->Opcode() == Instruction::INVOKE_DIRECT_RANGE);
-      ArtMethod* called_method = VerifyInvocationArgs(inst,
-                                                      METHOD_DIRECT,
-                                                      is_range,
-                                                      false);
+      ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_DIRECT, is_range, false);
       const char* return_type_descriptor;
       bool is_constructor;
       const RegType* return_type = nullptr;
@@ -2520,10 +2540,7 @@
     case Instruction::INVOKE_STATIC:
     case Instruction::INVOKE_STATIC_RANGE: {
         bool is_range = (inst->Opcode() == Instruction::INVOKE_STATIC_RANGE);
-        ArtMethod* called_method = VerifyInvocationArgs(inst,
-                                                        METHOD_STATIC,
-                                                        is_range,
-                                                        false);
+        ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_STATIC, is_range, false);
         const char* descriptor;
         if (called_method == nullptr) {
           uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
@@ -2545,10 +2562,7 @@
     case Instruction::INVOKE_INTERFACE:
     case Instruction::INVOKE_INTERFACE_RANGE: {
       bool is_range =  (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
-      ArtMethod* abs_method = VerifyInvocationArgs(inst,
-                                                   METHOD_INTERFACE,
-                                                   is_range,
-                                                   false);
+      ArtMethod* abs_method = VerifyInvocationArgs(inst, METHOD_INTERFACE, is_range, false);
       if (abs_method != nullptr) {
         mirror::Class* called_interface = abs_method->GetDeclaringClass();
         if (!called_interface->IsInterface() && !called_interface->IsObjectClass()) {
@@ -2897,10 +2911,49 @@
       }
       break;
     }
+    case Instruction::INVOKE_LAMBDA: {
+      // Don't bother verifying, instead the interpreter will take the slow path with access checks.
+      // If the code would've normally hard-failed, then the interpreter will throw the
+      // appropriate verification errors at runtime.
+      Fail(VERIFY_ERROR_FORCE_INTERPRETER);  // TODO(iam): implement invoke-lambda verification
+      break;
+    }
+    case Instruction::CREATE_LAMBDA: {
+      // Don't bother verifying, instead the interpreter will take the slow path with access checks.
+      // If the code would've normally hard-failed, then the interpreter will throw the
+      // appropriate verification errors at runtime.
+      Fail(VERIFY_ERROR_FORCE_INTERPRETER);  // TODO(iam): implement create-lambda verification
+      break;
+    }
+
+    case Instruction::UNUSED_F4:
+    case Instruction::UNUSED_F5:
+    case Instruction::UNUSED_F7: {
+      DCHECK(false);  // TODO(iam): Implement opcodes for lambdas
+      // Conservatively fail verification on release builds.
+      Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_);
+      break;
+    }
+
+    case Instruction::BOX_LAMBDA: {
+      // Don't bother verifying, instead the interpreter will take the slow path with access checks.
+      // If the code would've normally hard-failed, then the interpreter will throw the
+      // appropriate verification errors at runtime.
+      Fail(VERIFY_ERROR_FORCE_INTERPRETER);  // TODO(iam): implement box-lambda verification
+      break;
+    }
+
+     case Instruction::UNBOX_LAMBDA: {
+      // Don't bother verifying, instead the interpreter will take the slow path with access checks.
+      // If the code would've normally hard-failed, then the interpreter will throw the
+      // appropriate verification errors at runtime.
+      Fail(VERIFY_ERROR_FORCE_INTERPRETER);  // TODO(iam): implement unbox-lambda verification
+      break;
+    }
 
     /* These should never appear during verification. */
     case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
-    case Instruction::UNUSED_F3 ... Instruction::UNUSED_FF:
+    case Instruction::UNUSED_FA ... Instruction::UNUSED_FF:
     case Instruction::UNUSED_79:
     case Instruction::UNUSED_7A:
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_);
@@ -3391,7 +3444,10 @@
     }
     if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
       const RegType* res_method_class;
-      if (res_method != nullptr) {
+      // Miranda methods have the declaring interface as their declaring class, not the abstract
+      // class. It would be wrong to use this for the type check (interface type checks are
+      // postponed to runtime).
+      if (res_method != nullptr && !res_method->IsMiranda()) {
         mirror::Class* klass = res_method->GetDeclaringClass();
         std::string temp;
         res_method_class = &FromClass(klass->GetDescriptor(&temp), klass,
@@ -3442,11 +3498,27 @@
             << " but expected " << reg_type;
         return nullptr;
       }
-    } else if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
-      // Continue on soft failures. We need to find possible hard failures to avoid problems in the
-      // compiler.
-      if (have_pending_hard_failure_) {
-        return nullptr;
+    } else {
+      if (!work_line_->VerifyRegisterType(this, get_reg, reg_type)) {
+        // Continue on soft failures. We need to find possible hard failures to avoid problems in
+        // the compiler.
+        if (have_pending_hard_failure_) {
+          return nullptr;
+        }
+      } else if (reg_type.IsLongOrDoubleTypes()) {
+        // Check that registers are consecutive (for non-range invokes). Invokes are the only
+        // instructions not specifying register pairs by the first component, but require them
+        // nonetheless. Only check when there's an actual register in the parameters. If there's
+        // none, this will fail below.
+        if (!is_range && sig_registers + 1 < expected_args) {
+          uint32_t second_reg = arg[sig_registers + 1];
+          if (second_reg != get_reg + 1) {
+            Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation, long or double parameter "
+                "at index " << sig_registers << " is not a pair: " << get_reg << " + "
+                << second_reg << ".";
+            return nullptr;
+          }
+        }
       }
     }
     sig_registers += reg_type.IsLongOrDoubleTypes() ?  2 : 1;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 62800fb..2550694 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -77,6 +77,16 @@
   VERIFY_ERROR_ACCESS_METHOD,   // IllegalAccessError.
   VERIFY_ERROR_CLASS_CHANGE,    // IncompatibleClassChangeError.
   VERIFY_ERROR_INSTANTIATION,   // InstantiationError.
+  // For opcodes that don't have complete verifier support (such as lambda opcodes),
+  // we need a way to continue execution at runtime without attempting to re-verify
+  // (since we know it will fail no matter what). Instead, run as the interpreter
+  // in a special "do access checks" mode which will perform verifier-like checking
+  // on the fly.
+  //
+  // TODO: Once all new opcodes have implemented full verifier support, this can be removed.
+  VERIFY_ERROR_FORCE_INTERPRETER,  // Skip the verification phase at runtime;
+                                   // force the interpreter to do access checks.
+                                   // (sets a soft fail at compile time).
 };
 std::ostream& operator<<(std::ostream& os, const VerifyError& rhs);
 
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index 88c1f69..9daaf8e 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -124,7 +124,7 @@
 
   // Resist the urge to delete the space. <: is a bigraph sequence.
   std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
-  const int32_t error = FindEntry(handle_, ZipEntryName(name), zip_entry.get());
+  const int32_t error = FindEntry(handle_, ZipString(name), zip_entry.get());
   if (error) {
     *error_msg = std::string(ErrorCodeString(error));
     return nullptr;
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
index e1aae11..b9e37a1 100644
--- a/sigchainlib/Android.mk
+++ b/sigchainlib/Android.mk
@@ -22,6 +22,7 @@
 LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+LOCAL_ASFLAGS += $(ART_TARGET_ASFLAGS)
 LOCAL_SRC_FILES := sigchain_dummy.cc
 LOCAL_CLANG = $(ART_TARGET_CLANG)
 LOCAL_MODULE:= libsigchain
@@ -36,6 +37,7 @@
 LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+LOCAL_ASFLAGS += $(ART_TARGET_ASFLAGS)
 LOCAL_SRC_FILES := sigchain.cc
 LOCAL_CLANG = $(ART_TARGET_CLANG)
 LOCAL_MODULE:= libsigchain
@@ -51,6 +53,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_IS_HOST_MODULE := true
 LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
 LOCAL_CLANG = $(ART_HOST_CLANG)
 LOCAL_SRC_FILES := sigchain_dummy.cc
 LOCAL_MODULE:= libsigchain
@@ -65,6 +68,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_IS_HOST_MODULE := true
 LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
+LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
 LOCAL_CLANG = $(ART_HOST_CLANG)
 LOCAL_SRC_FILES := sigchain.cc
 LOCAL_MODULE:= libsigchain
@@ -72,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/004-StackWalk/src/Main.java b/test/004-StackWalk/src/Main.java
index 1e2a91b..9a1d0ab 100644
--- a/test/004-StackWalk/src/Main.java
+++ b/test/004-StackWalk/src/Main.java
@@ -2,9 +2,14 @@
   public Main() {
   }
 
-  int f() {
+  int $noinline$f() throws Exception {
     g(1);
     g(2);
+
+    // This loop currently defeats inlining of `f`.
+    for (int i = 0; i < 10; i++) {
+      Thread.sleep(0);
+    }
     return 0;
   }
 
@@ -86,8 +91,8 @@
     System.loadLibrary("arttest");
   }
 
-  public static void main(String[] args) {
+  public static void main(String[] args) throws Exception {
     Main st = new Main();
-    st.f();
+    st.$noinline$f();
   }
 }
diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
index f66b715..6b15514 100644
--- a/test/004-StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -45,11 +45,11 @@
     if (m_name == "f") {
       if (gJava_StackWalk_refmap_calls == 1) {
         CHECK_EQ(1U, GetDexPc());
-        CHECK_REGS(1);
+        CHECK_REGS(4);
       } else {
         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
         CHECK_EQ(5U, GetDexPc());
-        CHECK_REGS(1);
+        CHECK_REGS(4);
       }
     } else if (m_name == "g") {
       if (gJava_StackWalk_refmap_calls == 1) {
diff --git a/test/004-UnsafeTest/info.txt b/test/004-UnsafeTest/info.txt
index 00b0d9a..bccc01f 100644
--- a/test/004-UnsafeTest/info.txt
+++ b/test/004-UnsafeTest/info.txt
@@ -1 +1 @@
-Imported from oat tests.
+Test support for sun.misc.Unsafe.
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java
index 708f61f..818f5d9 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -36,6 +36,13 @@
     }
   }
 
+  private static void check(Object actual, Object expected, String msg) {
+    if (actual != expected) {
+      System.out.println(msg + " : " + actual + " != " + expected);
+      System.exit(1);
+    }
+  }
+
   private static Unsafe getUnsafe() throws Exception {
     Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
     Field f = unsafeClass.getDeclaredField("theUnsafe");
@@ -80,6 +87,7 @@
         "Unsafe.arrayIndexScale(Object[])");
 
     TestClass t = new TestClass();
+
     int intValue = 12345678;
     Field intField = TestClass.class.getDeclaredField("intVar");
     long intOffset = unsafe.objectFieldOffset(intField);
@@ -87,14 +95,23 @@
     unsafe.putInt(t, intOffset, intValue);
     check(t.intVar, intValue, "Unsafe.putInt(Object, long, int)");
     check(unsafe.getInt(t, intOffset), intValue, "Unsafe.getInt(Object, long)");
+
+    long longValue = 1234567887654321L;
     Field longField = TestClass.class.getDeclaredField("longVar");
     long longOffset = unsafe.objectFieldOffset(longField);
-    long longValue = 1234567887654321L;
     check(unsafe.getLong(t, longOffset), 0, "Unsafe.getLong(Object, long) - initial");
     unsafe.putLong(t, longOffset, longValue);
     check(t.longVar, longValue, "Unsafe.putLong(Object, long, long)");
     check(unsafe.getLong(t, longOffset), longValue, "Unsafe.getLong(Object, long)");
 
+    Object objectValue = new Object();
+    Field objectField = TestClass.class.getDeclaredField("objectVar");
+    long objectOffset = unsafe.objectFieldOffset(objectField);
+    check(unsafe.getObject(t, objectOffset), null, "Unsafe.getObject(Object, long) - initial");
+    unsafe.putObject(t, objectOffset, objectValue);
+    check(t.objectVar, objectValue, "Unsafe.putObject(Object, long, Object)");
+    check(unsafe.getObject(t, objectOffset), objectValue, "Unsafe.getObject(Object, long)");
+
     if (unsafe.compareAndSwapInt(t, intOffset, 0, 1)) {
         System.out.println("Unexpectedly succeeding compareAndSwap...");
     }
@@ -114,11 +131,22 @@
     if (!unsafe.compareAndSwapLong(t, longOffset, 0, 1)) {
         System.out.println("Unexpectedly not succeeding compareAndSwapLong...");
     }
+
+    if (unsafe.compareAndSwapObject(t, objectOffset, null, new Object())) {
+        System.out.println("Unexpectedly succeeding compareAndSwapObject...");
+    }
+    if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue, null)) {
+        System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+    }
+    if (!unsafe.compareAndSwapObject(t, objectOffset, null, new Object())) {
+        System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+    }
   }
 
   private static class TestClass {
     public int intVar = 0;
     public long longVar = 0;
+    public Object objectVar = null;
   }
 
   private static native int vmArrayBaseOffset(Class clazz);
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index b4381f4..3bb6747 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -22,13 +22,13 @@
 ./iface-gen
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JACK} --output-dex . src
+  # Use the default Jack commands
+  ./default-build
 else
   mkdir classes
   ${JAVAC} -d classes src/*.java
 
   # 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
-
-zip $TEST_NAME.jar classes.dex
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index cac034e..0de56f9 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -34,31 +34,10 @@
     }
 
     public static WeakReference<FinalizerTest> makeRef() {
-        /*
-         * Make ft in another thread, so there is no danger of
-         * a conservative reference leaking onto the main thread's
-         * stack.
-         */
-
-        final List<WeakReference<FinalizerTest>> wimp =
-                new ArrayList<WeakReference<FinalizerTest>>();
-        Thread t = new Thread() {
-                public void run() {
-                    FinalizerTest ft = new FinalizerTest("wahoo");
-                    wimp.add(new WeakReference<FinalizerTest>(ft));
-                    ft = null;
-                }
-            };
-
-        t.start();
-
-        try {
-            t.join();
-        } catch (InterruptedException ie) {
-            throw new RuntimeException(ie);
-        }
-
-        return wimp.get(0);
+        FinalizerTest ft = new FinalizerTest("wahoo");
+        WeakReference<FinalizerTest> ref = new WeakReference<FinalizerTest>(ft);
+        ft = null;
+        return ref;
     }
 
     public static String wimpString(final WeakReference<FinalizerTest> wimp) {
diff --git a/test/067-preemptive-unpark/src/Main.java b/test/067-preemptive-unpark/src/Main.java
index 2c099b9..beb3262 100644
--- a/test/067-preemptive-unpark/src/Main.java
+++ b/test/067-preemptive-unpark/src/Main.java
@@ -40,22 +40,24 @@
     /**
      * Set up {@link #UNSAFE}.
      */
-    public static void setUp() {
+    public static void setUp() throws Exception{
         /*
          * Subvert the access check to get the unique Unsafe instance.
          * We can do this because there's no security manager
          * installed when running the test.
          */
+        Field field = null;
         try {
-            Field field = Unsafe.class.getDeclaredField("THE_ONE");
-            field.setAccessible(true);
-
-            UNSAFE = (Unsafe) field.get(null);
-        } catch (NoSuchFieldException ex) {
-            throw new RuntimeException(ex);
-        } catch (IllegalAccessException ex) {
-            throw new RuntimeException(ex);
+            field = Unsafe.class.getDeclaredField("THE_ONE");
+        } catch (NoSuchFieldException e1) {
+            try {
+                field = Unsafe.class.getDeclaredField("theUnsafe");
+            } catch (NoSuchFieldException e2) {
+                throw new RuntimeException("Failed to find THE_ONE or theUnsafe");
+            }
         }
+        field.setAccessible(true);
+        UNSAFE = (Unsafe) field.get(null);
     }
 
     /**
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index a8db069..add2ff6 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -20,6 +20,9 @@
 import java.util.Map;
 
 public class Main {
+    private static final String TEMP_FILE_NAME_PREFIX = "test";
+    private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
+
     public static void main(String[] args) throws Exception {
         String name = System.getProperty("java.vm.name");
         if (!"Dalvik".equals(name)) {
@@ -32,21 +35,31 @@
 
     private static File createTempFile() throws Exception {
         try {
-            return  File.createTempFile("test", ".trace");
+            return  File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
         } catch (IOException e) {
             System.setProperty("java.io.tmpdir", "/data/local/tmp");
             try {
-                return File.createTempFile("test", ".trace");
+                return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
             } catch (IOException e2) {
                 System.setProperty("java.io.tmpdir", "/sdcard");
-                return File.createTempFile("test", ".trace");
+                return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
             }
         }
     }
 
     private static void testMethodTracing() throws Exception {
-        File tempFile = createTempFile();
-        tempFile.deleteOnExit();
+        File tempFile = null;
+        try {
+            tempFile = createTempFile();
+            testMethodTracingToFile(tempFile);
+        } finally {
+            if (tempFile != null) {
+                tempFile.delete();
+            }
+        }
+    }
+
+    private static void testMethodTracingToFile(File tempFile) throws Exception {
         String tempFileName = tempFile.getPath();
 
         if (VMDebug.getMethodTracingMode() != 0) {
diff --git a/test/133-static-invoke-super/src/Main.java b/test/133-static-invoke-super/src/Main.java
index 7cfd099..e694998 100644
--- a/test/133-static-invoke-super/src/Main.java
+++ b/test/133-static-invoke-super/src/Main.java
@@ -26,14 +26,14 @@
         run(timing);
     }
 
-    static int testBasis(int interations) {
-      (new SubClass()).testDirect(interations);
-      return interations;
+    static int testBasis(int iterations) {
+      (new SubClass()).testDirect(iterations);
+      return iterations;
     }
 
-    static int testStatic(int interations) {
-      (new SubClass()).testStatic(interations);
-      return interations;
+    static int testStatic(int iterations) {
+      (new SubClass()).testStatic(iterations);
+      return iterations;
     }
 
     static public void run(boolean timing) {
diff --git a/test/135-MirandaDispatch/expected.txt b/test/135-MirandaDispatch/expected.txt
index 134d8d0..5b098e5 100644
--- a/test/135-MirandaDispatch/expected.txt
+++ b/test/135-MirandaDispatch/expected.txt
@@ -1 +1,2 @@
+b/21646347
 Finishing
diff --git a/test/135-MirandaDispatch/smali/b_21646347.smali b/test/135-MirandaDispatch/smali/b_21646347.smali
new file mode 100644
index 0000000..b4979a5
--- /dev/null
+++ b/test/135-MirandaDispatch/smali/b_21646347.smali
@@ -0,0 +1,15 @@
+.class public LB21646347;
+
+# If an invoke-virtual dispatches to a miranda method, ensure that we test for the receiver
+# being a subclass of the abstract class, not postpone the check because the miranda method's
+# declaring class is an interface.
+
+.super Ljava/lang/Object;
+
+.method public static run(LB21646347;)V
+    .registers 1
+    # Invoke the miranda method on an object of this class. This should fail type-checking,
+    # instead of letting this pass as the declaring class is an interface.
+    invoke-virtual {v0}, LMain$AbstractClass;->m()V
+    return-void
+.end method
diff --git a/test/135-MirandaDispatch/src/Main.java b/test/135-MirandaDispatch/src/Main.java
index bb005b0..ada8cef 100644
--- a/test/135-MirandaDispatch/src/Main.java
+++ b/test/135-MirandaDispatch/src/Main.java
@@ -46,6 +46,15 @@
         if (counter != loopIterations * loopIterations) {
           System.out.println("Expected " + loopIterations * loopIterations + " got " + counter);
         }
+
+        try {
+            Class<?> b21646347 = Class.forName("B21646347");
+            throw new RuntimeException("Expected a VerifyError");
+        } catch (VerifyError expected) {
+            System.out.println("b/21646347");
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
         System.out.println("Finishing");
     }
 }
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 78cf2aa..ecbbbc7 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -14,8 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Temporarily disable address space layout randomization (ASLR).
-# This is need on host so that the linker loads core.oat at fixed address.
-export LD_USE_LOAD_BIAS=1
-
 exec ${RUN} "$@"
diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build
index 9d19809..5ff73ec 100644
--- a/test/303-verification-stress/build
+++ b/test/303-verification-stress/build
@@ -22,13 +22,13 @@
 ./classes-gen
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JACK} --output-dex . src
+  # Use the default Jack commands
+  ./default-build
 else
   mkdir classes
   ${JAVAC} -d classes src/*.java
 
   # 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
-
-zip $TEST_NAME.jar classes.dex
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 7ce2868..9f8f417 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -138,552 +138,554 @@
   }
 
   private static void byteToLong() {
-    assertLongEquals(1L, $opt$ByteToLong((byte)1));
-    assertLongEquals(0L, $opt$ByteToLong((byte)0));
-    assertLongEquals(-1L, $opt$ByteToLong((byte)-1));
-    assertLongEquals(51L, $opt$ByteToLong((byte)51));
-    assertLongEquals(-51L, $opt$ByteToLong((byte)-51));
-    assertLongEquals(127L, $opt$ByteToLong((byte)127));  // 2^7 - 1
-    assertLongEquals(-127L, $opt$ByteToLong((byte)-127));  // -(2^7 - 1)
-    assertLongEquals(-128L, $opt$ByteToLong((byte)-128));  // -(2^7)
+    assertLongEquals(1L, $opt$noinline$ByteToLong((byte)1));
+    assertLongEquals(0L, $opt$noinline$ByteToLong((byte)0));
+    assertLongEquals(-1L, $opt$noinline$ByteToLong((byte)-1));
+    assertLongEquals(51L, $opt$noinline$ByteToLong((byte)51));
+    assertLongEquals(-51L, $opt$noinline$ByteToLong((byte)-51));
+    assertLongEquals(127L, $opt$noinline$ByteToLong((byte)127));  // 2^7 - 1
+    assertLongEquals(-127L, $opt$noinline$ByteToLong((byte)-127));  // -(2^7 - 1)
+    assertLongEquals(-128L, $opt$noinline$ByteToLong((byte)-128));  // -(2^7)
   }
 
   private static void shortToLong() {
-    assertLongEquals(1L, $opt$ShortToLong((short)1));
-    assertLongEquals(0L, $opt$ShortToLong((short)0));
-    assertLongEquals(-1L, $opt$ShortToLong((short)-1));
-    assertLongEquals(51L, $opt$ShortToLong((short)51));
-    assertLongEquals(-51L, $opt$ShortToLong((short)-51));
-    assertLongEquals(32767L, $opt$ShortToLong((short)32767));  // 2^15 - 1
-    assertLongEquals(-32767L, $opt$ShortToLong((short)-32767));  // -(2^15 - 1)
-    assertLongEquals(-32768L, $opt$ShortToLong((short)-32768));  // -(2^15)
+    assertLongEquals(1L, $opt$noinline$ShortToLong((short)1));
+    assertLongEquals(0L, $opt$noinline$ShortToLong((short)0));
+    assertLongEquals(-1L, $opt$noinline$ShortToLong((short)-1));
+    assertLongEquals(51L, $opt$noinline$ShortToLong((short)51));
+    assertLongEquals(-51L, $opt$noinline$ShortToLong((short)-51));
+    assertLongEquals(32767L, $opt$noinline$ShortToLong((short)32767));  // 2^15 - 1
+    assertLongEquals(-32767L, $opt$noinline$ShortToLong((short)-32767));  // -(2^15 - 1)
+    assertLongEquals(-32768L, $opt$noinline$ShortToLong((short)-32768));  // -(2^15)
   }
 
   private static void intToLong() {
-    assertLongEquals(1L, $opt$IntToLong(1));
-    assertLongEquals(0L, $opt$IntToLong(0));
-    assertLongEquals(-1L, $opt$IntToLong(-1));
-    assertLongEquals(51L, $opt$IntToLong(51));
-    assertLongEquals(-51L, $opt$IntToLong(-51));
-    assertLongEquals(2147483647L, $opt$IntToLong(2147483647));  // 2^31 - 1
-    assertLongEquals(-2147483647L, $opt$IntToLong(-2147483647));  // -(2^31 - 1)
-    assertLongEquals(-2147483648L, $opt$IntToLong(-2147483648));  // -(2^31)
+    assertLongEquals(1L, $opt$noinline$IntToLong(1));
+    assertLongEquals(0L, $opt$noinline$IntToLong(0));
+    assertLongEquals(-1L, $opt$noinline$IntToLong(-1));
+    assertLongEquals(51L, $opt$noinline$IntToLong(51));
+    assertLongEquals(-51L, $opt$noinline$IntToLong(-51));
+    assertLongEquals(2147483647L, $opt$noinline$IntToLong(2147483647));  // 2^31 - 1
+    assertLongEquals(-2147483647L, $opt$noinline$IntToLong(-2147483647));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$noinline$IntToLong(-2147483648));  // -(2^31)
   }
 
   private static void charToLong() {
-    assertLongEquals(1L, $opt$CharToLong((char)1));
-    assertLongEquals(0L, $opt$CharToLong((char)0));
-    assertLongEquals(51L, $opt$CharToLong((char)51));
-    assertLongEquals(32767L, $opt$CharToLong((char)32767));  // 2^15 - 1
-    assertLongEquals(65535L, $opt$CharToLong((char)65535));  // 2^16 - 1
-    assertLongEquals(65535L, $opt$CharToLong((char)-1));
-    assertLongEquals(65485L, $opt$CharToLong((char)-51));
-    assertLongEquals(32769L, $opt$CharToLong((char)-32767));  // -(2^15 - 1)
-    assertLongEquals(32768L, $opt$CharToLong((char)-32768));  // -(2^15)
+    assertLongEquals(1L, $opt$noinline$CharToLong((char)1));
+    assertLongEquals(0L, $opt$noinline$CharToLong((char)0));
+    assertLongEquals(51L, $opt$noinline$CharToLong((char)51));
+    assertLongEquals(32767L, $opt$noinline$CharToLong((char)32767));  // 2^15 - 1
+    assertLongEquals(65535L, $opt$noinline$CharToLong((char)65535));  // 2^16 - 1
+    assertLongEquals(65535L, $opt$noinline$CharToLong((char)-1));
+    assertLongEquals(65485L, $opt$noinline$CharToLong((char)-51));
+    assertLongEquals(32769L, $opt$noinline$CharToLong((char)-32767));  // -(2^15 - 1)
+    assertLongEquals(32768L, $opt$noinline$CharToLong((char)-32768));  // -(2^15)
   }
 
   private static void byteToFloat() {
-    assertFloatEquals(1F, $opt$ByteToFloat((byte)1));
-    assertFloatEquals(0F, $opt$ByteToFloat((byte)0));
-    assertFloatEquals(-1F, $opt$ByteToFloat((byte)-1));
-    assertFloatEquals(51F, $opt$ByteToFloat((byte)51));
-    assertFloatEquals(-51F, $opt$ByteToFloat((byte)-51));
-    assertFloatEquals(127F, $opt$ByteToFloat((byte)127));  // 2^7 - 1
-    assertFloatEquals(-127F, $opt$ByteToFloat((byte)-127));  // -(2^7 - 1)
-    assertFloatEquals(-128F, $opt$ByteToFloat((byte)-128));  // -(2^7)
+    assertFloatEquals(1F, $opt$noinline$ByteToFloat((byte)1));
+    assertFloatEquals(0F, $opt$noinline$ByteToFloat((byte)0));
+    assertFloatEquals(-1F, $opt$noinline$ByteToFloat((byte)-1));
+    assertFloatEquals(51F, $opt$noinline$ByteToFloat((byte)51));
+    assertFloatEquals(-51F, $opt$noinline$ByteToFloat((byte)-51));
+    assertFloatEquals(127F, $opt$noinline$ByteToFloat((byte)127));  // 2^7 - 1
+    assertFloatEquals(-127F, $opt$noinline$ByteToFloat((byte)-127));  // -(2^7 - 1)
+    assertFloatEquals(-128F, $opt$noinline$ByteToFloat((byte)-128));  // -(2^7)
   }
 
   private static void shortToFloat() {
-    assertFloatEquals(1F, $opt$ShortToFloat((short)1));
-    assertFloatEquals(0F, $opt$ShortToFloat((short)0));
-    assertFloatEquals(-1F, $opt$ShortToFloat((short)-1));
-    assertFloatEquals(51F, $opt$ShortToFloat((short)51));
-    assertFloatEquals(-51F, $opt$ShortToFloat((short)-51));
-    assertFloatEquals(32767F, $opt$ShortToFloat((short)32767));  // 2^15 - 1
-    assertFloatEquals(-32767F, $opt$ShortToFloat((short)-32767));  // -(2^15 - 1)
-    assertFloatEquals(-32768F, $opt$ShortToFloat((short)-32768));  // -(2^15)
+    assertFloatEquals(1F, $opt$noinline$ShortToFloat((short)1));
+    assertFloatEquals(0F, $opt$noinline$ShortToFloat((short)0));
+    assertFloatEquals(-1F, $opt$noinline$ShortToFloat((short)-1));
+    assertFloatEquals(51F, $opt$noinline$ShortToFloat((short)51));
+    assertFloatEquals(-51F, $opt$noinline$ShortToFloat((short)-51));
+    assertFloatEquals(32767F, $opt$noinline$ShortToFloat((short)32767));  // 2^15 - 1
+    assertFloatEquals(-32767F, $opt$noinline$ShortToFloat((short)-32767));  // -(2^15 - 1)
+    assertFloatEquals(-32768F, $opt$noinline$ShortToFloat((short)-32768));  // -(2^15)
   }
 
   private static void intToFloat() {
-    assertFloatEquals(1F, $opt$IntToFloat(1));
-    assertFloatEquals(0F, $opt$IntToFloat(0));
-    assertFloatEquals(-1F, $opt$IntToFloat(-1));
-    assertFloatEquals(51F, $opt$IntToFloat(51));
-    assertFloatEquals(-51F, $opt$IntToFloat(-51));
-    assertFloatEquals(16777215F, $opt$IntToFloat(16777215));  // 2^24 - 1
-    assertFloatEquals(-16777215F, $opt$IntToFloat(-16777215));  // -(2^24 - 1)
-    assertFloatEquals(16777216F, $opt$IntToFloat(16777216));  // 2^24
-    assertFloatEquals(-16777216F, $opt$IntToFloat(-16777216));  // -(2^24)
-    assertFloatEquals(2147483647F, $opt$IntToFloat(2147483647));  // 2^31 - 1
-    assertFloatEquals(-2147483648F, $opt$IntToFloat(-2147483648));  // -(2^31)
+    assertFloatEquals(1F, $opt$noinline$IntToFloat(1));
+    assertFloatEquals(0F, $opt$noinline$IntToFloat(0));
+    assertFloatEquals(-1F, $opt$noinline$IntToFloat(-1));
+    assertFloatEquals(51F, $opt$noinline$IntToFloat(51));
+    assertFloatEquals(-51F, $opt$noinline$IntToFloat(-51));
+    assertFloatEquals(16777215F, $opt$noinline$IntToFloat(16777215));  // 2^24 - 1
+    assertFloatEquals(-16777215F, $opt$noinline$IntToFloat(-16777215));  // -(2^24 - 1)
+    assertFloatEquals(16777216F, $opt$noinline$IntToFloat(16777216));  // 2^24
+    assertFloatEquals(-16777216F, $opt$noinline$IntToFloat(-16777216));  // -(2^24)
+    assertFloatEquals(2147483647F, $opt$noinline$IntToFloat(2147483647));  // 2^31 - 1
+    assertFloatEquals(-2147483648F, $opt$noinline$IntToFloat(-2147483648));  // -(2^31)
   }
 
   private static void charToFloat() {
-    assertFloatEquals(1F, $opt$CharToFloat((char)1));
-    assertFloatEquals(0F, $opt$CharToFloat((char)0));
-    assertFloatEquals(51F, $opt$CharToFloat((char)51));
-    assertFloatEquals(32767F, $opt$CharToFloat((char)32767));  // 2^15 - 1
-    assertFloatEquals(65535F, $opt$CharToFloat((char)65535));  // 2^16 - 1
-    assertFloatEquals(65535F, $opt$CharToFloat((char)-1));
-    assertFloatEquals(65485F, $opt$CharToFloat((char)-51));
-    assertFloatEquals(32769F, $opt$CharToFloat((char)-32767));  // -(2^15 - 1)
-    assertFloatEquals(32768F, $opt$CharToFloat((char)-32768));  // -(2^15)
+    assertFloatEquals(1F, $opt$noinline$CharToFloat((char)1));
+    assertFloatEquals(0F, $opt$noinline$CharToFloat((char)0));
+    assertFloatEquals(51F, $opt$noinline$CharToFloat((char)51));
+    assertFloatEquals(32767F, $opt$noinline$CharToFloat((char)32767));  // 2^15 - 1
+    assertFloatEquals(65535F, $opt$noinline$CharToFloat((char)65535));  // 2^16 - 1
+    assertFloatEquals(65535F, $opt$noinline$CharToFloat((char)-1));
+    assertFloatEquals(65485F, $opt$noinline$CharToFloat((char)-51));
+    assertFloatEquals(32769F, $opt$noinline$CharToFloat((char)-32767));  // -(2^15 - 1)
+    assertFloatEquals(32768F, $opt$noinline$CharToFloat((char)-32768));  // -(2^15)
   }
 
   private static void byteToDouble() {
-    assertDoubleEquals(1D, $opt$ByteToDouble((byte)1));
-    assertDoubleEquals(0D, $opt$ByteToDouble((byte)0));
-    assertDoubleEquals(-1D, $opt$ByteToDouble((byte)-1));
-    assertDoubleEquals(51D, $opt$ByteToDouble((byte)51));
-    assertDoubleEquals(-51D, $opt$ByteToDouble((byte)-51));
-    assertDoubleEquals(127D, $opt$ByteToDouble((byte)127));  // 2^7 - 1
-    assertDoubleEquals(-127D, $opt$ByteToDouble((byte)-127));  // -(2^7 - 1)
-    assertDoubleEquals(-128D, $opt$ByteToDouble((byte)-128));  // -(2^7)
+    assertDoubleEquals(1D, $opt$noinline$ByteToDouble((byte)1));
+    assertDoubleEquals(0D, $opt$noinline$ByteToDouble((byte)0));
+    assertDoubleEquals(-1D, $opt$noinline$ByteToDouble((byte)-1));
+    assertDoubleEquals(51D, $opt$noinline$ByteToDouble((byte)51));
+    assertDoubleEquals(-51D, $opt$noinline$ByteToDouble((byte)-51));
+    assertDoubleEquals(127D, $opt$noinline$ByteToDouble((byte)127));  // 2^7 - 1
+    assertDoubleEquals(-127D, $opt$noinline$ByteToDouble((byte)-127));  // -(2^7 - 1)
+    assertDoubleEquals(-128D, $opt$noinline$ByteToDouble((byte)-128));  // -(2^7)
   }
 
   private static void shortToDouble() {
-    assertDoubleEquals(1D, $opt$ShortToDouble((short)1));
-    assertDoubleEquals(0D, $opt$ShortToDouble((short)0));
-    assertDoubleEquals(-1D, $opt$ShortToDouble((short)-1));
-    assertDoubleEquals(51D, $opt$ShortToDouble((short)51));
-    assertDoubleEquals(-51D, $opt$ShortToDouble((short)-51));
-    assertDoubleEquals(32767D, $opt$ShortToDouble((short)32767));  // 2^15 - 1
-    assertDoubleEquals(-32767D, $opt$ShortToDouble((short)-32767));  // -(2^15 - 1)
-    assertDoubleEquals(-32768D, $opt$ShortToDouble((short)-32768));  // -(2^15)
+    assertDoubleEquals(1D, $opt$noinline$ShortToDouble((short)1));
+    assertDoubleEquals(0D, $opt$noinline$ShortToDouble((short)0));
+    assertDoubleEquals(-1D, $opt$noinline$ShortToDouble((short)-1));
+    assertDoubleEquals(51D, $opt$noinline$ShortToDouble((short)51));
+    assertDoubleEquals(-51D, $opt$noinline$ShortToDouble((short)-51));
+    assertDoubleEquals(32767D, $opt$noinline$ShortToDouble((short)32767));  // 2^15 - 1
+    assertDoubleEquals(-32767D, $opt$noinline$ShortToDouble((short)-32767));  // -(2^15 - 1)
+    assertDoubleEquals(-32768D, $opt$noinline$ShortToDouble((short)-32768));  // -(2^15)
   }
 
   private static void intToDouble() {
-    assertDoubleEquals(1D, $opt$IntToDouble(1));
-    assertDoubleEquals(0D, $opt$IntToDouble(0));
-    assertDoubleEquals(-1D, $opt$IntToDouble(-1));
-    assertDoubleEquals(51D, $opt$IntToDouble(51));
-    assertDoubleEquals(-51D, $opt$IntToDouble(-51));
-    assertDoubleEquals(16777216D, $opt$IntToDouble(16777216));  // 2^24
-    assertDoubleEquals(-16777216D, $opt$IntToDouble(-16777216));  // -(2^24)
-    assertDoubleEquals(2147483647D, $opt$IntToDouble(2147483647));  // 2^31 - 1
-    assertDoubleEquals(-2147483648D, $opt$IntToDouble(-2147483648));  // -(2^31)
+    assertDoubleEquals(1D, $opt$noinline$IntToDouble(1));
+    assertDoubleEquals(0D, $opt$noinline$IntToDouble(0));
+    assertDoubleEquals(-1D, $opt$noinline$IntToDouble(-1));
+    assertDoubleEquals(51D, $opt$noinline$IntToDouble(51));
+    assertDoubleEquals(-51D, $opt$noinline$IntToDouble(-51));
+    assertDoubleEquals(16777216D, $opt$noinline$IntToDouble(16777216));  // 2^24
+    assertDoubleEquals(-16777216D, $opt$noinline$IntToDouble(-16777216));  // -(2^24)
+    assertDoubleEquals(2147483647D, $opt$noinline$IntToDouble(2147483647));  // 2^31 - 1
+    assertDoubleEquals(-2147483648D, $opt$noinline$IntToDouble(-2147483648));  // -(2^31)
   }
 
   private static void charToDouble() {
-    assertDoubleEquals(1D, $opt$CharToDouble((char)1));
-    assertDoubleEquals(0D, $opt$CharToDouble((char)0));
-    assertDoubleEquals(51D, $opt$CharToDouble((char)51));
-    assertDoubleEquals(32767D, $opt$CharToDouble((char)32767));  // 2^15 - 1
-    assertDoubleEquals(65535D, $opt$CharToDouble((char)65535));  // 2^16 - 1
-    assertDoubleEquals(65535D, $opt$CharToDouble((char)-1));
-    assertDoubleEquals(65485D, $opt$CharToDouble((char)-51));
-    assertDoubleEquals(32769D, $opt$CharToDouble((char)-32767));  // -(2^15 - 1)
-    assertDoubleEquals(32768D, $opt$CharToDouble((char)-32768));  // -(2^15)
+    assertDoubleEquals(1D, $opt$noinline$CharToDouble((char)1));
+    assertDoubleEquals(0D, $opt$noinline$CharToDouble((char)0));
+    assertDoubleEquals(51D, $opt$noinline$CharToDouble((char)51));
+    assertDoubleEquals(32767D, $opt$noinline$CharToDouble((char)32767));  // 2^15 - 1
+    assertDoubleEquals(65535D, $opt$noinline$CharToDouble((char)65535));  // 2^16 - 1
+    assertDoubleEquals(65535D, $opt$noinline$CharToDouble((char)-1));
+    assertDoubleEquals(65485D, $opt$noinline$CharToDouble((char)-51));
+    assertDoubleEquals(32769D, $opt$noinline$CharToDouble((char)-32767));  // -(2^15 - 1)
+    assertDoubleEquals(32768D, $opt$noinline$CharToDouble((char)-32768));  // -(2^15)
   }
 
   private static void longToInt() {
-    assertIntEquals(1, $opt$LongToInt(1L));
-    assertIntEquals(0, $opt$LongToInt(0L));
-    assertIntEquals(-1, $opt$LongToInt(-1L));
-    assertIntEquals(51, $opt$LongToInt(51L));
-    assertIntEquals(-51, $opt$LongToInt(-51L));
-    assertIntEquals(2147483647, $opt$LongToInt(2147483647L));  // 2^31 - 1
-    assertIntEquals(-2147483647, $opt$LongToInt(-2147483647L));  // -(2^31 - 1)
-    assertIntEquals(-2147483648, $opt$LongToInt(-2147483648L));  // -(2^31)
-    assertIntEquals(-2147483648, $opt$LongToInt(2147483648L));  // (2^31)
-    assertIntEquals(2147483647, $opt$LongToInt(-2147483649L));  // -(2^31 + 1)
-    assertIntEquals(-1, $opt$LongToInt(9223372036854775807L));  // 2^63 - 1
-    assertIntEquals(1, $opt$LongToInt(-9223372036854775807L));  // -(2^63 - 1)
-    assertIntEquals(0, $opt$LongToInt(-9223372036854775808L));  // -(2^63)
+    assertIntEquals(1, $opt$noinline$LongToInt(1L));
+    assertIntEquals(0, $opt$noinline$LongToInt(0L));
+    assertIntEquals(-1, $opt$noinline$LongToInt(-1L));
+    assertIntEquals(51, $opt$noinline$LongToInt(51L));
+    assertIntEquals(-51, $opt$noinline$LongToInt(-51L));
+    assertIntEquals(2147483647, $opt$noinline$LongToInt(2147483647L));  // 2^31 - 1
+    assertIntEquals(-2147483647, $opt$noinline$LongToInt(-2147483647L));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$noinline$LongToInt(-2147483648L));  // -(2^31)
+    assertIntEquals(-2147483648, $opt$noinline$LongToInt(2147483648L));  // (2^31)
+    assertIntEquals(2147483647, $opt$noinline$LongToInt(-2147483649L));  // -(2^31 + 1)
+    assertIntEquals(-1, $opt$noinline$LongToInt(9223372036854775807L));  // 2^63 - 1
+    assertIntEquals(1, $opt$noinline$LongToInt(-9223372036854775807L));  // -(2^63 - 1)
+    assertIntEquals(0, $opt$noinline$LongToInt(-9223372036854775808L));  // -(2^63)
 
-    assertIntEquals(42, $opt$LongLiteralToInt());
+    assertIntEquals(42, $opt$noinline$LongLiteralToInt());
 
     // Ensure long-to-int conversions truncates values as expected.
-    assertLongEquals(1L, $opt$IntToLong($opt$LongToInt(4294967297L)));  // 2^32 + 1
-    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(4294967296L)));  // 2^32
-    assertLongEquals(-1L, $opt$IntToLong($opt$LongToInt(4294967295L)));  // 2^32 - 1
-    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(0L)));
-    assertLongEquals(1L, $opt$IntToLong($opt$LongToInt(-4294967295L)));  // -(2^32 - 1)
-    assertLongEquals(0L, $opt$IntToLong($opt$LongToInt(-4294967296L)));  // -(2^32)
-    assertLongEquals(-1, $opt$IntToLong($opt$LongToInt(-4294967297L)));  // -(2^32 + 1)
+    assertLongEquals(1L, $opt$noinline$IntToLong($opt$noinline$LongToInt(4294967297L)));  // 2^32 + 1
+    assertLongEquals(0L, $opt$noinline$IntToLong($opt$noinline$LongToInt(4294967296L)));  // 2^32
+    assertLongEquals(-1L, $opt$noinline$IntToLong($opt$noinline$LongToInt(4294967295L)));  // 2^32 - 1
+    assertLongEquals(0L, $opt$noinline$IntToLong($opt$noinline$LongToInt(0L)));
+    assertLongEquals(1L, $opt$noinline$IntToLong($opt$noinline$LongToInt(-4294967295L)));  // -(2^32 - 1)
+    assertLongEquals(0L, $opt$noinline$IntToLong($opt$noinline$LongToInt(-4294967296L)));  // -(2^32)
+    assertLongEquals(-1, $opt$noinline$IntToLong($opt$noinline$LongToInt(-4294967297L)));  // -(2^32 + 1)
   }
 
   private static void longToFloat() {
-    assertFloatEquals(1F, $opt$LongToFloat(1L));
-    assertFloatEquals(0F, $opt$LongToFloat(0L));
-    assertFloatEquals(-1F, $opt$LongToFloat(-1L));
-    assertFloatEquals(51F, $opt$LongToFloat(51L));
-    assertFloatEquals(-51F, $opt$LongToFloat(-51L));
-    assertFloatEquals(2147483647F, $opt$LongToFloat(2147483647L));  // 2^31 - 1
-    assertFloatEquals(-2147483647F, $opt$LongToFloat(-2147483647L));  // -(2^31 - 1)
-    assertFloatEquals(-2147483648F, $opt$LongToFloat(-2147483648L));  // -(2^31)
-    assertFloatEquals(2147483648F, $opt$LongToFloat(2147483648L));  // (2^31)
-    assertFloatEquals(-2147483649F, $opt$LongToFloat(-2147483649L));  // -(2^31 + 1)
-    assertFloatEquals(4294967296F, $opt$LongToFloat(4294967296L));  // (2^32)
-    assertFloatEquals(-4294967296F, $opt$LongToFloat(-4294967296L));  // -(2^32)
-    assertFloatEquals(140739635871745F, $opt$LongToFloat(140739635871745L));  // 1 + 2^15 + 2^31 + 2^47
-    assertFloatEquals(-140739635871745F, $opt$LongToFloat(-140739635871745L));  // -(1 + 2^15 + 2^31 + 2^47)
-    assertFloatEquals(9223372036854775807F, $opt$LongToFloat(9223372036854775807L));  // 2^63 - 1
-    assertFloatEquals(-9223372036854775807F, $opt$LongToFloat(-9223372036854775807L));  // -(2^63 - 1)
-    assertFloatEquals(-9223372036854775808F, $opt$LongToFloat(-9223372036854775808L));  // -(2^63)
+    assertFloatEquals(1F, $opt$noinline$LongToFloat(1L));
+    assertFloatEquals(0F, $opt$noinline$LongToFloat(0L));
+    assertFloatEquals(-1F, $opt$noinline$LongToFloat(-1L));
+    assertFloatEquals(51F, $opt$noinline$LongToFloat(51L));
+    assertFloatEquals(-51F, $opt$noinline$LongToFloat(-51L));
+    assertFloatEquals(2147483647F, $opt$noinline$LongToFloat(2147483647L));  // 2^31 - 1
+    assertFloatEquals(-2147483647F, $opt$noinline$LongToFloat(-2147483647L));  // -(2^31 - 1)
+    assertFloatEquals(-2147483648F, $opt$noinline$LongToFloat(-2147483648L));  // -(2^31)
+    assertFloatEquals(2147483648F, $opt$noinline$LongToFloat(2147483648L));  // (2^31)
+    assertFloatEquals(-2147483649F, $opt$noinline$LongToFloat(-2147483649L));  // -(2^31 + 1)
+    assertFloatEquals(4294967296F, $opt$noinline$LongToFloat(4294967296L));  // (2^32)
+    assertFloatEquals(-4294967296F, $opt$noinline$LongToFloat(-4294967296L));  // -(2^32)
+    assertFloatEquals(140739635871745F, $opt$noinline$LongToFloat(140739635871745L));  // 1 + 2^15 + 2^31 + 2^47
+    assertFloatEquals(-140739635871745F, $opt$noinline$LongToFloat(-140739635871745L));  // -(1 + 2^15 + 2^31 + 2^47)
+    assertFloatEquals(9223372036854775807F, $opt$noinline$LongToFloat(9223372036854775807L));  // 2^63 - 1
+    assertFloatEquals(-9223372036854775807F, $opt$noinline$LongToFloat(-9223372036854775807L));  // -(2^63 - 1)
+    assertFloatEquals(-9223372036854775808F, $opt$noinline$LongToFloat(-9223372036854775808L));  // -(2^63)
   }
 
   private static void longToDouble() {
-    assertDoubleEquals(1D, $opt$LongToDouble(1L));
-    assertDoubleEquals(0D, $opt$LongToDouble(0L));
-    assertDoubleEquals(-1D, $opt$LongToDouble(-1L));
-    assertDoubleEquals(51D, $opt$LongToDouble(51L));
-    assertDoubleEquals(-51D, $opt$LongToDouble(-51L));
-    assertDoubleEquals(2147483647D, $opt$LongToDouble(2147483647L));  // 2^31 - 1
-    assertDoubleEquals(-2147483647D, $opt$LongToDouble(-2147483647L));  // -(2^31 - 1)
-    assertDoubleEquals(-2147483648D, $opt$LongToDouble(-2147483648L));  // -(2^31)
-    assertDoubleEquals(2147483648D, $opt$LongToDouble(2147483648L));  // (2^31)
-    assertDoubleEquals(-2147483649D, $opt$LongToDouble(-2147483649L));  // -(2^31 + 1)
-    assertDoubleEquals(4294967296D, $opt$LongToDouble(4294967296L));  // (2^32)
-    assertDoubleEquals(-4294967296D, $opt$LongToDouble(-4294967296L));  // -(2^32)
-    assertDoubleEquals(140739635871745D, $opt$LongToDouble(140739635871745L));  // 1 + 2^15 + 2^31 + 2^47
-    assertDoubleEquals(-140739635871745D, $opt$LongToDouble(-140739635871745L));  // -(1 + 2^15 + 2^31 + 2^47)
-    assertDoubleEquals(9223372036854775807D, $opt$LongToDouble(9223372036854775807L));  // 2^63 - 1
-    assertDoubleEquals(-9223372036854775807D, $opt$LongToDouble(-9223372036854775807L));  // -(2^63 - 1)
-    assertDoubleEquals(-9223372036854775808D, $opt$LongToDouble(-9223372036854775808L));  // -(2^63)
+    assertDoubleEquals(1D, $opt$noinline$LongToDouble(1L));
+    assertDoubleEquals(0D, $opt$noinline$LongToDouble(0L));
+    assertDoubleEquals(-1D, $opt$noinline$LongToDouble(-1L));
+    assertDoubleEquals(51D, $opt$noinline$LongToDouble(51L));
+    assertDoubleEquals(-51D, $opt$noinline$LongToDouble(-51L));
+    assertDoubleEquals(2147483647D, $opt$noinline$LongToDouble(2147483647L));  // 2^31 - 1
+    assertDoubleEquals(-2147483647D, $opt$noinline$LongToDouble(-2147483647L));  // -(2^31 - 1)
+    assertDoubleEquals(-2147483648D, $opt$noinline$LongToDouble(-2147483648L));  // -(2^31)
+    assertDoubleEquals(2147483648D, $opt$noinline$LongToDouble(2147483648L));  // (2^31)
+    assertDoubleEquals(-2147483649D, $opt$noinline$LongToDouble(-2147483649L));  // -(2^31 + 1)
+    assertDoubleEquals(4294967296D, $opt$noinline$LongToDouble(4294967296L));  // (2^32)
+    assertDoubleEquals(-4294967296D, $opt$noinline$LongToDouble(-4294967296L));  // -(2^32)
+    assertDoubleEquals(140739635871745D, $opt$noinline$LongToDouble(140739635871745L));  // 1 + 2^15 + 2^31 + 2^47
+    assertDoubleEquals(-140739635871745D, $opt$noinline$LongToDouble(-140739635871745L));  // -(1 + 2^15 + 2^31 + 2^47)
+    assertDoubleEquals(9223372036854775807D, $opt$noinline$LongToDouble(9223372036854775807L));  // 2^63 - 1
+    assertDoubleEquals(-9223372036854775807D, $opt$noinline$LongToDouble(-9223372036854775807L));  // -(2^63 - 1)
+    assertDoubleEquals(-9223372036854775808D, $opt$noinline$LongToDouble(-9223372036854775808L));  // -(2^63)
   }
 
   private static void floatToInt() {
-    assertIntEquals(1, $opt$FloatToInt(1F));
-    assertIntEquals(0, $opt$FloatToInt(0F));
-    assertIntEquals(0, $opt$FloatToInt(-0F));
-    assertIntEquals(-1, $opt$FloatToInt(-1F));
-    assertIntEquals(51, $opt$FloatToInt(51F));
-    assertIntEquals(-51, $opt$FloatToInt(-51F));
-    assertIntEquals(0, $opt$FloatToInt(0.5F));
-    assertIntEquals(0, $opt$FloatToInt(0.4999999F));
-    assertIntEquals(0, $opt$FloatToInt(-0.4999999F));
-    assertIntEquals(0, $opt$FloatToInt(-0.5F));
-    assertIntEquals(42, $opt$FloatToInt(42.199F));
-    assertIntEquals(-42, $opt$FloatToInt(-42.199F));
-    assertIntEquals(2147483647, $opt$FloatToInt(2147483647F));  // 2^31 - 1
-    assertIntEquals(-2147483648, $opt$FloatToInt(-2147483647F));  // -(2^31 - 1)
-    assertIntEquals(-2147483648, $opt$FloatToInt(-2147483648F));  // -(2^31)
-    assertIntEquals(2147483647, $opt$FloatToInt(2147483648F));  // (2^31)
-    assertIntEquals(-2147483648, $opt$FloatToInt(-2147483649F));  // -(2^31 + 1)
-    assertIntEquals(2147483647, $opt$FloatToInt(9223372036854775807F));  // 2^63 - 1
-    assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775807F));  // -(2^63 - 1)
-    assertIntEquals(-2147483648, $opt$FloatToInt(-9223372036854775808F));  // -(2^63)
-    assertIntEquals(0, $opt$FloatToInt(Float.NaN));
-    assertIntEquals(2147483647, $opt$FloatToInt(Float.POSITIVE_INFINITY));
-    assertIntEquals(-2147483648, $opt$FloatToInt(Float.NEGATIVE_INFINITY));
+    assertIntEquals(1, $opt$noinline$FloatToInt(1F));
+    assertIntEquals(0, $opt$noinline$FloatToInt(0F));
+    assertIntEquals(0, $opt$noinline$FloatToInt(-0F));
+    assertIntEquals(-1, $opt$noinline$FloatToInt(-1F));
+    assertIntEquals(51, $opt$noinline$FloatToInt(51F));
+    assertIntEquals(-51, $opt$noinline$FloatToInt(-51F));
+    assertIntEquals(0, $opt$noinline$FloatToInt(0.5F));
+    assertIntEquals(0, $opt$noinline$FloatToInt(0.4999999F));
+    assertIntEquals(0, $opt$noinline$FloatToInt(-0.4999999F));
+    assertIntEquals(0, $opt$noinline$FloatToInt(-0.5F));
+    assertIntEquals(42, $opt$noinline$FloatToInt(42.199F));
+    assertIntEquals(-42, $opt$noinline$FloatToInt(-42.199F));
+    assertIntEquals(2147483647, $opt$noinline$FloatToInt(2147483647F));  // 2^31 - 1
+    assertIntEquals(-2147483648, $opt$noinline$FloatToInt(-2147483647F));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$noinline$FloatToInt(-2147483648F));  // -(2^31)
+    assertIntEquals(2147483647, $opt$noinline$FloatToInt(2147483648F));  // (2^31)
+    assertIntEquals(-2147483648, $opt$noinline$FloatToInt(-2147483649F));  // -(2^31 + 1)
+    assertIntEquals(2147483647, $opt$noinline$FloatToInt(9223372036854775807F));  // 2^63 - 1
+    assertIntEquals(-2147483648, $opt$noinline$FloatToInt(-9223372036854775807F));  // -(2^63 - 1)
+    assertIntEquals(-2147483648, $opt$noinline$FloatToInt(-9223372036854775808F));  // -(2^63)
+    assertIntEquals(0, $opt$noinline$FloatToInt(Float.NaN));
+    assertIntEquals(2147483647, $opt$noinline$FloatToInt(Float.POSITIVE_INFINITY));
+    assertIntEquals(-2147483648, $opt$noinline$FloatToInt(Float.NEGATIVE_INFINITY));
   }
 
   private static void floatToLong() {
-    assertLongEquals(1L, $opt$FloatToLong(1F));
-    assertLongEquals(0L, $opt$FloatToLong(0F));
-    assertLongEquals(0L, $opt$FloatToLong(-0F));
-    assertLongEquals(-1L, $opt$FloatToLong(-1F));
-    assertLongEquals(51L, $opt$FloatToLong(51F));
-    assertLongEquals(-51L, $opt$FloatToLong(-51F));
-    assertLongEquals(0L, $opt$FloatToLong(0.5F));
-    assertLongEquals(0L, $opt$FloatToLong(0.4999999F));
-    assertLongEquals(0L, $opt$FloatToLong(-0.4999999F));
-    assertLongEquals(0L, $opt$FloatToLong(-0.5F));
-    assertLongEquals(42L, $opt$FloatToLong(42.199F));
-    assertLongEquals(-42L, $opt$FloatToLong(-42.199F));
-    assertLongEquals(2147483648L, $opt$FloatToLong(2147483647F));  // 2^31 - 1
-    assertLongEquals(-2147483648L, $opt$FloatToLong(-2147483647F));  // -(2^31 - 1)
-    assertLongEquals(-2147483648L, $opt$FloatToLong(-2147483648F));  // -(2^31)
-    assertLongEquals(2147483648L, $opt$FloatToLong(2147483648F));  // (2^31)
-    assertLongEquals(-2147483648L, $opt$FloatToLong(-2147483649F));  // -(2^31 + 1)
-    assertLongEquals(9223372036854775807L, $opt$FloatToLong(9223372036854775807F));  // 2^63 - 1
-    assertLongEquals(-9223372036854775808L, $opt$FloatToLong(-9223372036854775807F));  // -(2^63 - 1)
-    assertLongEquals(-9223372036854775808L, $opt$FloatToLong(-9223372036854775808F));  // -(2^63)
-    assertLongEquals(0L, $opt$FloatToLong(Float.NaN));
-    assertLongEquals(9223372036854775807L, $opt$FloatToLong(Float.POSITIVE_INFINITY));
-    assertLongEquals(-9223372036854775808L, $opt$FloatToLong(Float.NEGATIVE_INFINITY));
+    assertLongEquals(1L, $opt$noinline$FloatToLong(1F));
+    assertLongEquals(0L, $opt$noinline$FloatToLong(0F));
+    assertLongEquals(0L, $opt$noinline$FloatToLong(-0F));
+    assertLongEquals(-1L, $opt$noinline$FloatToLong(-1F));
+    assertLongEquals(51L, $opt$noinline$FloatToLong(51F));
+    assertLongEquals(-51L, $opt$noinline$FloatToLong(-51F));
+    assertLongEquals(0L, $opt$noinline$FloatToLong(0.5F));
+    assertLongEquals(0L, $opt$noinline$FloatToLong(0.4999999F));
+    assertLongEquals(0L, $opt$noinline$FloatToLong(-0.4999999F));
+    assertLongEquals(0L, $opt$noinline$FloatToLong(-0.5F));
+    assertLongEquals(42L, $opt$noinline$FloatToLong(42.199F));
+    assertLongEquals(-42L, $opt$noinline$FloatToLong(-42.199F));
+    assertLongEquals(2147483648L, $opt$noinline$FloatToLong(2147483647F));  // 2^31 - 1
+    assertLongEquals(-2147483648L, $opt$noinline$FloatToLong(-2147483647F));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$noinline$FloatToLong(-2147483648F));  // -(2^31)
+    assertLongEquals(2147483648L, $opt$noinline$FloatToLong(2147483648F));  // (2^31)
+    assertLongEquals(-2147483648L, $opt$noinline$FloatToLong(-2147483649F));  // -(2^31 + 1)
+    assertLongEquals(9223372036854775807L, $opt$noinline$FloatToLong(9223372036854775807F));  // 2^63 - 1
+    assertLongEquals(-9223372036854775808L, $opt$noinline$FloatToLong(-9223372036854775807F));  // -(2^63 - 1)
+    assertLongEquals(-9223372036854775808L, $opt$noinline$FloatToLong(-9223372036854775808F));  // -(2^63)
+    assertLongEquals(0L, $opt$noinline$FloatToLong(Float.NaN));
+    assertLongEquals(9223372036854775807L, $opt$noinline$FloatToLong(Float.POSITIVE_INFINITY));
+    assertLongEquals(-9223372036854775808L, $opt$noinline$FloatToLong(Float.NEGATIVE_INFINITY));
   }
 
   private static void floatToDouble() {
-    assertDoubleEquals(1D, $opt$FloatToDouble(1F));
-    assertDoubleEquals(0D, $opt$FloatToDouble(0F));
-    assertDoubleEquals(0D, $opt$FloatToDouble(-0F));
-    assertDoubleEquals(-1D, $opt$FloatToDouble(-1F));
-    assertDoubleEquals(51D, $opt$FloatToDouble(51F));
-    assertDoubleEquals(-51D, $opt$FloatToDouble(-51F));
-    assertDoubleEquals(0.5D, $opt$FloatToDouble(0.5F));
-    assertDoubleEquals(0.49999991059303284D, $opt$FloatToDouble(0.4999999F));
-    assertDoubleEquals(-0.49999991059303284D, $opt$FloatToDouble(-0.4999999F));
-    assertDoubleEquals(-0.5D, $opt$FloatToDouble(-0.5F));
-    assertDoubleEquals(42.19900131225586D, $opt$FloatToDouble(42.199F));
-    assertDoubleEquals(-42.19900131225586D, $opt$FloatToDouble(-42.199F));
-    assertDoubleEquals(2147483648D, $opt$FloatToDouble(2147483647F));  // 2^31 - 1
-    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483647F));  // -(2^31 - 1)
-    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483648F));  // -(2^31)
-    assertDoubleEquals(2147483648D, $opt$FloatToDouble(2147483648F));  // (2^31)
-    assertDoubleEquals(-2147483648D, $opt$FloatToDouble(-2147483649F));  // -(2^31 + 1)
-    assertDoubleEquals(9223372036854775807D, $opt$FloatToDouble(9223372036854775807F));  // 2^63 - 1
-    assertDoubleEquals(-9223372036854775807D, $opt$FloatToDouble(-9223372036854775807F));  // -(2^63 - 1)
-    assertDoubleEquals(-9223372036854775808D, $opt$FloatToDouble(-9223372036854775808F));  // -(2^63)
-    assertDoubleIsNaN($opt$FloatToDouble(Float.NaN));
-    assertDoubleEquals(Double.POSITIVE_INFINITY, $opt$FloatToDouble(Float.POSITIVE_INFINITY));
-    assertDoubleEquals(Double.NEGATIVE_INFINITY, $opt$FloatToDouble(Float.NEGATIVE_INFINITY));
+    assertDoubleEquals(1D, $opt$noinline$FloatToDouble(1F));
+    assertDoubleEquals(0D, $opt$noinline$FloatToDouble(0F));
+    assertDoubleEquals(0D, $opt$noinline$FloatToDouble(-0F));
+    assertDoubleEquals(-1D, $opt$noinline$FloatToDouble(-1F));
+    assertDoubleEquals(51D, $opt$noinline$FloatToDouble(51F));
+    assertDoubleEquals(-51D, $opt$noinline$FloatToDouble(-51F));
+    assertDoubleEquals(0.5D, $opt$noinline$FloatToDouble(0.5F));
+    assertDoubleEquals(0.49999991059303284D, $opt$noinline$FloatToDouble(0.4999999F));
+    assertDoubleEquals(-0.49999991059303284D, $opt$noinline$FloatToDouble(-0.4999999F));
+    assertDoubleEquals(-0.5D, $opt$noinline$FloatToDouble(-0.5F));
+    assertDoubleEquals(42.19900131225586D, $opt$noinline$FloatToDouble(42.199F));
+    assertDoubleEquals(-42.19900131225586D, $opt$noinline$FloatToDouble(-42.199F));
+    assertDoubleEquals(2147483648D, $opt$noinline$FloatToDouble(2147483647F));  // 2^31 - 1
+    assertDoubleEquals(-2147483648D, $opt$noinline$FloatToDouble(-2147483647F));  // -(2^31 - 1)
+    assertDoubleEquals(-2147483648D, $opt$noinline$FloatToDouble(-2147483648F));  // -(2^31)
+    assertDoubleEquals(2147483648D, $opt$noinline$FloatToDouble(2147483648F));  // (2^31)
+    assertDoubleEquals(-2147483648D, $opt$noinline$FloatToDouble(-2147483649F));  // -(2^31 + 1)
+    assertDoubleEquals(9223372036854775807D, $opt$noinline$FloatToDouble(9223372036854775807F));  // 2^63 - 1
+    assertDoubleEquals(-9223372036854775807D, $opt$noinline$FloatToDouble(-9223372036854775807F));  // -(2^63 - 1)
+    assertDoubleEquals(-9223372036854775808D, $opt$noinline$FloatToDouble(-9223372036854775808F));  // -(2^63)
+    assertDoubleIsNaN($opt$noinline$FloatToDouble(Float.NaN));
+    assertDoubleEquals(Double.POSITIVE_INFINITY, $opt$noinline$FloatToDouble(Float.POSITIVE_INFINITY));
+    assertDoubleEquals(Double.NEGATIVE_INFINITY, $opt$noinline$FloatToDouble(Float.NEGATIVE_INFINITY));
   }
 
   private static void doubleToInt() {
-    assertIntEquals(1, $opt$DoubleToInt(1D));
-    assertIntEquals(0, $opt$DoubleToInt(0D));
-    assertIntEquals(0, $opt$DoubleToInt(-0D));
-    assertIntEquals(-1, $opt$DoubleToInt(-1D));
-    assertIntEquals(51, $opt$DoubleToInt(51D));
-    assertIntEquals(-51, $opt$DoubleToInt(-51D));
-    assertIntEquals(0, $opt$DoubleToInt(0.5D));
-    assertIntEquals(0, $opt$DoubleToInt(0.4999999D));
-    assertIntEquals(0, $opt$DoubleToInt(-0.4999999D));
-    assertIntEquals(0, $opt$DoubleToInt(-0.5D));
-    assertIntEquals(42, $opt$DoubleToInt(42.199D));
-    assertIntEquals(-42, $opt$DoubleToInt(-42.199D));
-    assertIntEquals(2147483647, $opt$DoubleToInt(2147483647D));  // 2^31 - 1
-    assertIntEquals(-2147483647, $opt$DoubleToInt(-2147483647D));  // -(2^31 - 1)
-    assertIntEquals(-2147483648, $opt$DoubleToInt(-2147483648D));  // -(2^31)
-    assertIntEquals(2147483647, $opt$DoubleToInt(2147483648D));  // (2^31)
-    assertIntEquals(-2147483648, $opt$DoubleToInt(-2147483649D));  // -(2^31 + 1)
-    assertIntEquals(2147483647, $opt$DoubleToInt(9223372036854775807D));  // 2^63 - 1
-    assertIntEquals(-2147483648, $opt$DoubleToInt(-9223372036854775807D));  // -(2^63 - 1)
-    assertIntEquals(-2147483648, $opt$DoubleToInt(-9223372036854775808D));  // -(2^63)
-    assertIntEquals(0, $opt$DoubleToInt(Double.NaN));
-    assertIntEquals(2147483647, $opt$DoubleToInt(Double.POSITIVE_INFINITY));
-    assertIntEquals(-2147483648, $opt$DoubleToInt(Double.NEGATIVE_INFINITY));
+    assertIntEquals(1, $opt$noinline$DoubleToInt(1D));
+    assertIntEquals(0, $opt$noinline$DoubleToInt(0D));
+    assertIntEquals(0, $opt$noinline$DoubleToInt(-0D));
+    assertIntEquals(-1, $opt$noinline$DoubleToInt(-1D));
+    assertIntEquals(51, $opt$noinline$DoubleToInt(51D));
+    assertIntEquals(-51, $opt$noinline$DoubleToInt(-51D));
+    assertIntEquals(0, $opt$noinline$DoubleToInt(0.5D));
+    assertIntEquals(0, $opt$noinline$DoubleToInt(0.4999999D));
+    assertIntEquals(0, $opt$noinline$DoubleToInt(-0.4999999D));
+    assertIntEquals(0, $opt$noinline$DoubleToInt(-0.5D));
+    assertIntEquals(42, $opt$noinline$DoubleToInt(42.199D));
+    assertIntEquals(-42, $opt$noinline$DoubleToInt(-42.199D));
+    assertIntEquals(2147483647, $opt$noinline$DoubleToInt(2147483647D));  // 2^31 - 1
+    assertIntEquals(-2147483647, $opt$noinline$DoubleToInt(-2147483647D));  // -(2^31 - 1)
+    assertIntEquals(-2147483648, $opt$noinline$DoubleToInt(-2147483648D));  // -(2^31)
+    assertIntEquals(2147483647, $opt$noinline$DoubleToInt(2147483648D));  // (2^31)
+    assertIntEquals(-2147483648, $opt$noinline$DoubleToInt(-2147483649D));  // -(2^31 + 1)
+    assertIntEquals(2147483647, $opt$noinline$DoubleToInt(9223372036854775807D));  // 2^63 - 1
+    assertIntEquals(-2147483648, $opt$noinline$DoubleToInt(-9223372036854775807D));  // -(2^63 - 1)
+    assertIntEquals(-2147483648, $opt$noinline$DoubleToInt(-9223372036854775808D));  // -(2^63)
+    assertIntEquals(0, $opt$noinline$DoubleToInt(Double.NaN));
+    assertIntEquals(2147483647, $opt$noinline$DoubleToInt(Double.POSITIVE_INFINITY));
+    assertIntEquals(-2147483648, $opt$noinline$DoubleToInt(Double.NEGATIVE_INFINITY));
   }
 
   private static void doubleToLong() {
-    assertLongEquals(1L, $opt$DoubleToLong(1D));
-    assertLongEquals(0L, $opt$DoubleToLong(0D));
-    assertLongEquals(0L, $opt$DoubleToLong(-0D));
-    assertLongEquals(-1L, $opt$DoubleToLong(-1D));
-    assertLongEquals(51L, $opt$DoubleToLong(51D));
-    assertLongEquals(-51L, $opt$DoubleToLong(-51D));
-    assertLongEquals(0L, $opt$DoubleToLong(0.5D));
-    assertLongEquals(0L, $opt$DoubleToLong(0.4999999D));
-    assertLongEquals(0L, $opt$DoubleToLong(-0.4999999D));
-    assertLongEquals(0L, $opt$DoubleToLong(-0.5D));
-    assertLongEquals(42L, $opt$DoubleToLong(42.199D));
-    assertLongEquals(-42L, $opt$DoubleToLong(-42.199D));
-    assertLongEquals(2147483647L, $opt$DoubleToLong(2147483647D));  // 2^31 - 1
-    assertLongEquals(-2147483647L, $opt$DoubleToLong(-2147483647D));  // -(2^31 - 1)
-    assertLongEquals(-2147483648L, $opt$DoubleToLong(-2147483648D));  // -(2^31)
-    assertLongEquals(2147483648L, $opt$DoubleToLong(2147483648D));  // (2^31)
-    assertLongEquals(-2147483649L, $opt$DoubleToLong(-2147483649D));  // -(2^31 + 1)
-    assertLongEquals(9223372036854775807L, $opt$DoubleToLong(9223372036854775807D));  // 2^63 - 1
-    assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(-9223372036854775807D));  // -(2^63 - 1)
-    assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(-9223372036854775808D));  // -(2^63)
-    assertLongEquals(0L, $opt$DoubleToLong(Double.NaN));
-    assertLongEquals(9223372036854775807L, $opt$DoubleToLong(Double.POSITIVE_INFINITY));
-    assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(Double.NEGATIVE_INFINITY));
+    assertLongEquals(1L, $opt$noinline$DoubleToLong(1D));
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(0D));
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(-0D));
+    assertLongEquals(-1L, $opt$noinline$DoubleToLong(-1D));
+    assertLongEquals(51L, $opt$noinline$DoubleToLong(51D));
+    assertLongEquals(-51L, $opt$noinline$DoubleToLong(-51D));
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(0.5D));
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(0.4999999D));
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(-0.4999999D));
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(-0.5D));
+    assertLongEquals(42L, $opt$noinline$DoubleToLong(42.199D));
+    assertLongEquals(-42L, $opt$noinline$DoubleToLong(-42.199D));
+    assertLongEquals(2147483647L, $opt$noinline$DoubleToLong(2147483647D));  // 2^31 - 1
+    assertLongEquals(-2147483647L, $opt$noinline$DoubleToLong(-2147483647D));  // -(2^31 - 1)
+    assertLongEquals(-2147483648L, $opt$noinline$DoubleToLong(-2147483648D));  // -(2^31)
+    assertLongEquals(2147483648L, $opt$noinline$DoubleToLong(2147483648D));  // (2^31)
+    assertLongEquals(-2147483649L, $opt$noinline$DoubleToLong(-2147483649D));  // -(2^31 + 1)
+    assertLongEquals(9223372036854775807L, $opt$noinline$DoubleToLong(9223372036854775807D));  // 2^63 - 1
+    assertLongEquals(-9223372036854775808L, $opt$noinline$DoubleToLong(-9223372036854775807D));  // -(2^63 - 1)
+    assertLongEquals(-9223372036854775808L, $opt$noinline$DoubleToLong(-9223372036854775808D));  // -(2^63)
+    assertLongEquals(0L, $opt$noinline$DoubleToLong(Double.NaN));
+    assertLongEquals(9223372036854775807L, $opt$noinline$DoubleToLong(Double.POSITIVE_INFINITY));
+    assertLongEquals(-9223372036854775808L, $opt$noinline$DoubleToLong(Double.NEGATIVE_INFINITY));
   }
 
   private static void doubleToFloat() {
-    assertFloatEquals(1F, $opt$DoubleToFloat(1D));
-    assertFloatEquals(0F, $opt$DoubleToFloat(0D));
-    assertFloatEquals(0F, $opt$DoubleToFloat(-0D));
-    assertFloatEquals(-1F, $opt$DoubleToFloat(-1D));
-    assertFloatEquals(51F, $opt$DoubleToFloat(51D));
-    assertFloatEquals(-51F, $opt$DoubleToFloat(-51D));
-    assertFloatEquals(0.5F, $opt$DoubleToFloat(0.5D));
-    assertFloatEquals(0.4999999F, $opt$DoubleToFloat(0.4999999D));
-    assertFloatEquals(-0.4999999F, $opt$DoubleToFloat(-0.4999999D));
-    assertFloatEquals(-0.5F, $opt$DoubleToFloat(-0.5D));
-    assertFloatEquals(42.199F, $opt$DoubleToFloat(42.199D));
-    assertFloatEquals(-42.199F, $opt$DoubleToFloat(-42.199D));
-    assertFloatEquals(2147483648F, $opt$DoubleToFloat(2147483647D));  // 2^31 - 1
-    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483647D));  // -(2^31 - 1)
-    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483648D));  // -(2^31)
-    assertFloatEquals(2147483648F, $opt$DoubleToFloat(2147483648D));  // (2^31)
-    assertFloatEquals(-2147483648F, $opt$DoubleToFloat(-2147483649D));  // -(2^31 + 1)
-    assertFloatEquals(9223372036854775807F, $opt$DoubleToFloat(9223372036854775807D));  // 2^63 - 1
-    assertFloatEquals(-9223372036854775807F, $opt$DoubleToFloat(-9223372036854775807D));  // -(2^63 - 1)
-    assertFloatEquals(-9223372036854775808F, $opt$DoubleToFloat(-9223372036854775808D));  // -(2^63)
-    assertFloatIsNaN($opt$DoubleToFloat(Float.NaN));
-    assertFloatEquals(Float.POSITIVE_INFINITY, $opt$DoubleToFloat(Double.POSITIVE_INFINITY));
-    assertFloatEquals(Float.NEGATIVE_INFINITY, $opt$DoubleToFloat(Double.NEGATIVE_INFINITY));
+    assertFloatEquals(1F, $opt$noinline$DoubleToFloat(1D));
+    assertFloatEquals(0F, $opt$noinline$DoubleToFloat(0D));
+    assertFloatEquals(0F, $opt$noinline$DoubleToFloat(-0D));
+    assertFloatEquals(-1F, $opt$noinline$DoubleToFloat(-1D));
+    assertFloatEquals(51F, $opt$noinline$DoubleToFloat(51D));
+    assertFloatEquals(-51F, $opt$noinline$DoubleToFloat(-51D));
+    assertFloatEquals(0.5F, $opt$noinline$DoubleToFloat(0.5D));
+    assertFloatEquals(0.4999999F, $opt$noinline$DoubleToFloat(0.4999999D));
+    assertFloatEquals(-0.4999999F, $opt$noinline$DoubleToFloat(-0.4999999D));
+    assertFloatEquals(-0.5F, $opt$noinline$DoubleToFloat(-0.5D));
+    assertFloatEquals(42.199F, $opt$noinline$DoubleToFloat(42.199D));
+    assertFloatEquals(-42.199F, $opt$noinline$DoubleToFloat(-42.199D));
+    assertFloatEquals(2147483648F, $opt$noinline$DoubleToFloat(2147483647D));  // 2^31 - 1
+    assertFloatEquals(-2147483648F, $opt$noinline$DoubleToFloat(-2147483647D));  // -(2^31 - 1)
+    assertFloatEquals(-2147483648F, $opt$noinline$DoubleToFloat(-2147483648D));  // -(2^31)
+    assertFloatEquals(2147483648F, $opt$noinline$DoubleToFloat(2147483648D));  // (2^31)
+    assertFloatEquals(-2147483648F, $opt$noinline$DoubleToFloat(-2147483649D));  // -(2^31 + 1)
+    assertFloatEquals(9223372036854775807F, $opt$noinline$DoubleToFloat(9223372036854775807D));  // 2^63 - 1
+    assertFloatEquals(-9223372036854775807F, $opt$noinline$DoubleToFloat(-9223372036854775807D));  // -(2^63 - 1)
+    assertFloatEquals(-9223372036854775808F, $opt$noinline$DoubleToFloat(-9223372036854775808D));  // -(2^63)
+    assertFloatIsNaN($opt$noinline$DoubleToFloat(Float.NaN));
+    assertFloatEquals(Float.POSITIVE_INFINITY, $opt$noinline$DoubleToFloat(Double.POSITIVE_INFINITY));
+    assertFloatEquals(Float.NEGATIVE_INFINITY, $opt$noinline$DoubleToFloat(Double.NEGATIVE_INFINITY));
   }
 
   private static void shortToByte() {
-    assertByteEquals((byte)1, $opt$ShortToByte((short)1));
-    assertByteEquals((byte)0, $opt$ShortToByte((short)0));
-    assertByteEquals((byte)-1, $opt$ShortToByte((short)-1));
-    assertByteEquals((byte)51, $opt$ShortToByte((short)51));
-    assertByteEquals((byte)-51, $opt$ShortToByte((short)-51));
-    assertByteEquals((byte)127, $opt$ShortToByte((short)127));  // 2^7 - 1
-    assertByteEquals((byte)-127, $opt$ShortToByte((short)-127));  // -(2^7 - 1)
-    assertByteEquals((byte)-128, $opt$ShortToByte((short)-128));  // -(2^7)
-    assertByteEquals((byte)-128, $opt$ShortToByte((short)128));  // 2^7
-    assertByteEquals((byte)127, $opt$ShortToByte((short)-129));  // -(2^7 + 1)
-    assertByteEquals((byte)-1, $opt$ShortToByte((short)32767));  // 2^15 - 1
-    assertByteEquals((byte)0, $opt$ShortToByte((short)-32768));  // -(2^15)
+    assertByteEquals((byte)1, $opt$noinline$ShortToByte((short)1));
+    assertByteEquals((byte)0, $opt$noinline$ShortToByte((short)0));
+    assertByteEquals((byte)-1, $opt$noinline$ShortToByte((short)-1));
+    assertByteEquals((byte)51, $opt$noinline$ShortToByte((short)51));
+    assertByteEquals((byte)-51, $opt$noinline$ShortToByte((short)-51));
+    assertByteEquals((byte)127, $opt$noinline$ShortToByte((short)127));  // 2^7 - 1
+    assertByteEquals((byte)-127, $opt$noinline$ShortToByte((short)-127));  // -(2^7 - 1)
+    assertByteEquals((byte)-128, $opt$noinline$ShortToByte((short)-128));  // -(2^7)
+    assertByteEquals((byte)-128, $opt$noinline$ShortToByte((short)128));  // 2^7
+    assertByteEquals((byte)127, $opt$noinline$ShortToByte((short)-129));  // -(2^7 + 1)
+    assertByteEquals((byte)-1, $opt$noinline$ShortToByte((short)32767));  // 2^15 - 1
+    assertByteEquals((byte)0, $opt$noinline$ShortToByte((short)-32768));  // -(2^15)
   }
 
   private static void intToByte() {
-    assertByteEquals((byte)1, $opt$IntToByte(1));
-    assertByteEquals((byte)0, $opt$IntToByte(0));
-    assertByteEquals((byte)-1, $opt$IntToByte(-1));
-    assertByteEquals((byte)51, $opt$IntToByte(51));
-    assertByteEquals((byte)-51, $opt$IntToByte(-51));
-    assertByteEquals((byte)127, $opt$IntToByte(127));  // 2^7 - 1
-    assertByteEquals((byte)-127, $opt$IntToByte(-127));  // -(2^7 - 1)
-    assertByteEquals((byte)-128, $opt$IntToByte(-128));  // -(2^7)
-    assertByteEquals((byte)-128, $opt$IntToByte(128));  // 2^7
-    assertByteEquals((byte)127, $opt$IntToByte(-129));  // -(2^7 + 1)
-    assertByteEquals((byte)-1, $opt$IntToByte(2147483647));  // 2^31 - 1
-    assertByteEquals((byte)0, $opt$IntToByte(-2147483648));  // -(2^31)
+    assertByteEquals((byte)1, $opt$noinline$IntToByte(1));
+    assertByteEquals((byte)0, $opt$noinline$IntToByte(0));
+    assertByteEquals((byte)-1, $opt$noinline$IntToByte(-1));
+    assertByteEquals((byte)51, $opt$noinline$IntToByte(51));
+    assertByteEquals((byte)-51, $opt$noinline$IntToByte(-51));
+    assertByteEquals((byte)127, $opt$noinline$IntToByte(127));  // 2^7 - 1
+    assertByteEquals((byte)-127, $opt$noinline$IntToByte(-127));  // -(2^7 - 1)
+    assertByteEquals((byte)-128, $opt$noinline$IntToByte(-128));  // -(2^7)
+    assertByteEquals((byte)-128, $opt$noinline$IntToByte(128));  // 2^7
+    assertByteEquals((byte)127, $opt$noinline$IntToByte(-129));  // -(2^7 + 1)
+    assertByteEquals((byte)-1, $opt$noinline$IntToByte(2147483647));  // 2^31 - 1
+    assertByteEquals((byte)0, $opt$noinline$IntToByte(-2147483648));  // -(2^31)
   }
 
   private static void charToByte() {
-    assertByteEquals((byte)1, $opt$CharToByte((char)1));
-    assertByteEquals((byte)0, $opt$CharToByte((char)0));
-    assertByteEquals((byte)51, $opt$CharToByte((char)51));
-    assertByteEquals((byte)127, $opt$CharToByte((char)127));  // 2^7 - 1
-    assertByteEquals((byte)-128, $opt$CharToByte((char)128));  // 2^7
-    assertByteEquals((byte)-1, $opt$CharToByte((char)32767));  // 2^15 - 1
-    assertByteEquals((byte)-1, $opt$CharToByte((char)65535));  // 2^16 - 1
-    assertByteEquals((byte)-1, $opt$CharToByte((char)-1));
-    assertByteEquals((byte)-51, $opt$CharToByte((char)-51));
-    assertByteEquals((byte)-127, $opt$CharToByte((char)-127));  // -(2^7 - 1)
-    assertByteEquals((byte)-128, $opt$CharToByte((char)-128));  // -(2^7)
-    assertByteEquals((byte)127, $opt$CharToByte((char)-129));  // -(2^7 + 1)
+    assertByteEquals((byte)1, $opt$noinline$CharToByte((char)1));
+    assertByteEquals((byte)0, $opt$noinline$CharToByte((char)0));
+    assertByteEquals((byte)51, $opt$noinline$CharToByte((char)51));
+    assertByteEquals((byte)127, $opt$noinline$CharToByte((char)127));  // 2^7 - 1
+    assertByteEquals((byte)-128, $opt$noinline$CharToByte((char)128));  // 2^7
+    assertByteEquals((byte)-1, $opt$noinline$CharToByte((char)32767));  // 2^15 - 1
+    assertByteEquals((byte)-1, $opt$noinline$CharToByte((char)65535));  // 2^16 - 1
+    assertByteEquals((byte)-1, $opt$noinline$CharToByte((char)-1));
+    assertByteEquals((byte)-51, $opt$noinline$CharToByte((char)-51));
+    assertByteEquals((byte)-127, $opt$noinline$CharToByte((char)-127));  // -(2^7 - 1)
+    assertByteEquals((byte)-128, $opt$noinline$CharToByte((char)-128));  // -(2^7)
+    assertByteEquals((byte)127, $opt$noinline$CharToByte((char)-129));  // -(2^7 + 1)
   }
 
   private static void byteToShort() {
-    assertShortEquals((short)1, $opt$ByteToShort((byte)1));
-    assertShortEquals((short)0, $opt$ByteToShort((byte)0));
-    assertShortEquals((short)-1, $opt$ByteToShort((byte)-1));
-    assertShortEquals((short)51, $opt$ByteToShort((byte)51));
-    assertShortEquals((short)-51, $opt$ByteToShort((byte)-51));
-    assertShortEquals((short)127, $opt$ByteToShort((byte)127));  // 2^7 - 1
-    assertShortEquals((short)-127, $opt$ByteToShort((byte)-127));  // -(2^7 - 1)
-    assertShortEquals((short)-128, $opt$ByteToShort((byte)-128));  // -(2^7)
+    assertShortEquals((short)1, $opt$noinline$ByteToShort((byte)1));
+    assertShortEquals((short)0, $opt$noinline$ByteToShort((byte)0));
+    assertShortEquals((short)-1, $opt$noinline$ByteToShort((byte)-1));
+    assertShortEquals((short)51, $opt$noinline$ByteToShort((byte)51));
+    assertShortEquals((short)-51, $opt$noinline$ByteToShort((byte)-51));
+    assertShortEquals((short)127, $opt$noinline$ByteToShort((byte)127));  // 2^7 - 1
+    assertShortEquals((short)-127, $opt$noinline$ByteToShort((byte)-127));  // -(2^7 - 1)
+    assertShortEquals((short)-128, $opt$noinline$ByteToShort((byte)-128));  // -(2^7)
   }
 
   private static void intToShort() {
-    assertShortEquals((short)1, $opt$IntToShort(1));
-    assertShortEquals((short)0, $opt$IntToShort(0));
-    assertShortEquals((short)-1, $opt$IntToShort(-1));
-    assertShortEquals((short)51, $opt$IntToShort(51));
-    assertShortEquals((short)-51, $opt$IntToShort(-51));
-    assertShortEquals((short)32767, $opt$IntToShort(32767));  // 2^15 - 1
-    assertShortEquals((short)-32767, $opt$IntToShort(-32767));  // -(2^15 - 1)
-    assertShortEquals((short)-32768, $opt$IntToShort(-32768));  // -(2^15)
-    assertShortEquals((short)-32768, $opt$IntToShort(32768));  // 2^15
-    assertShortEquals((short)32767, $opt$IntToShort(-32769));  // -(2^15 + 1)
-    assertShortEquals((short)-1, $opt$IntToShort(2147483647));  // 2^31 - 1
-    assertShortEquals((short)0, $opt$IntToShort(-2147483648));  // -(2^31)
+    assertShortEquals((short)1, $opt$noinline$IntToShort(1));
+    assertShortEquals((short)0, $opt$noinline$IntToShort(0));
+    assertShortEquals((short)-1, $opt$noinline$IntToShort(-1));
+    assertShortEquals((short)51, $opt$noinline$IntToShort(51));
+    assertShortEquals((short)-51, $opt$noinline$IntToShort(-51));
+    assertShortEquals((short)32767, $opt$noinline$IntToShort(32767));  // 2^15 - 1
+    assertShortEquals((short)-32767, $opt$noinline$IntToShort(-32767));  // -(2^15 - 1)
+    assertShortEquals((short)-32768, $opt$noinline$IntToShort(-32768));  // -(2^15)
+    assertShortEquals((short)-32768, $opt$noinline$IntToShort(32768));  // 2^15
+    assertShortEquals((short)32767, $opt$noinline$IntToShort(-32769));  // -(2^15 + 1)
+    assertShortEquals((short)-1, $opt$noinline$IntToShort(2147483647));  // 2^31 - 1
+    assertShortEquals((short)0, $opt$noinline$IntToShort(-2147483648));  // -(2^31)
   }
 
   private static void charToShort() {
-    assertShortEquals((short)1, $opt$CharToShort((char)1));
-    assertShortEquals((short)0, $opt$CharToShort((char)0));
-    assertShortEquals((short)51, $opt$CharToShort((char)51));
-    assertShortEquals((short)32767, $opt$CharToShort((char)32767));  // 2^15 - 1
-    assertShortEquals((short)-32768, $opt$CharToShort((char)32768));  // 2^15
-    assertShortEquals((short)-32767, $opt$CharToShort((char)32769));  // 2^15
-    assertShortEquals((short)-1, $opt$CharToShort((char)65535));  // 2^16 - 1
-    assertShortEquals((short)-1, $opt$CharToShort((char)-1));
-    assertShortEquals((short)-51, $opt$CharToShort((char)-51));
-    assertShortEquals((short)-32767, $opt$CharToShort((char)-32767));  // -(2^15 - 1)
-    assertShortEquals((short)-32768, $opt$CharToShort((char)-32768));  // -(2^15)
-    assertShortEquals((short)32767, $opt$CharToShort((char)-32769));  // -(2^15 + 1)
+    assertShortEquals((short)1, $opt$noinline$CharToShort((char)1));
+    assertShortEquals((short)0, $opt$noinline$CharToShort((char)0));
+    assertShortEquals((short)51, $opt$noinline$CharToShort((char)51));
+    assertShortEquals((short)32767, $opt$noinline$CharToShort((char)32767));  // 2^15 - 1
+    assertShortEquals((short)-32768, $opt$noinline$CharToShort((char)32768));  // 2^15
+    assertShortEquals((short)-32767, $opt$noinline$CharToShort((char)32769));  // 2^15
+    assertShortEquals((short)-1, $opt$noinline$CharToShort((char)65535));  // 2^16 - 1
+    assertShortEquals((short)-1, $opt$noinline$CharToShort((char)-1));
+    assertShortEquals((short)-51, $opt$noinline$CharToShort((char)-51));
+    assertShortEquals((short)-32767, $opt$noinline$CharToShort((char)-32767));  // -(2^15 - 1)
+    assertShortEquals((short)-32768, $opt$noinline$CharToShort((char)-32768));  // -(2^15)
+    assertShortEquals((short)32767, $opt$noinline$CharToShort((char)-32769));  // -(2^15 + 1)
   }
 
   private static void byteToChar() {
-    assertCharEquals((char)1, $opt$ByteToChar((byte)1));
-    assertCharEquals((char)0, $opt$ByteToChar((byte)0));
-    assertCharEquals((char)65535, $opt$ByteToChar((byte)-1));
-    assertCharEquals((char)51, $opt$ByteToChar((byte)51));
-    assertCharEquals((char)65485, $opt$ByteToChar((byte)-51));
-    assertCharEquals((char)127, $opt$ByteToChar((byte)127));  // 2^7 - 1
-    assertCharEquals((char)65409, $opt$ByteToChar((byte)-127));  // -(2^7 - 1)
-    assertCharEquals((char)65408, $opt$ByteToChar((byte)-128));  // -(2^7)
+    assertCharEquals((char)1, $opt$noinline$ByteToChar((byte)1));
+    assertCharEquals((char)0, $opt$noinline$ByteToChar((byte)0));
+    assertCharEquals((char)65535, $opt$noinline$ByteToChar((byte)-1));
+    assertCharEquals((char)51, $opt$noinline$ByteToChar((byte)51));
+    assertCharEquals((char)65485, $opt$noinline$ByteToChar((byte)-51));
+    assertCharEquals((char)127, $opt$noinline$ByteToChar((byte)127));  // 2^7 - 1
+    assertCharEquals((char)65409, $opt$noinline$ByteToChar((byte)-127));  // -(2^7 - 1)
+    assertCharEquals((char)65408, $opt$noinline$ByteToChar((byte)-128));  // -(2^7)
   }
 
   private static void shortToChar() {
-    assertCharEquals((char)1, $opt$ShortToChar((short)1));
-    assertCharEquals((char)0, $opt$ShortToChar((short)0));
-    assertCharEquals((char)65535, $opt$ShortToChar((short)-1));
-    assertCharEquals((char)51, $opt$ShortToChar((short)51));
-    assertCharEquals((char)65485, $opt$ShortToChar((short)-51));
-    assertCharEquals((char)32767, $opt$ShortToChar((short)32767));  // 2^15 - 1
-    assertCharEquals((char)32769, $opt$ShortToChar((short)-32767));  // -(2^15 - 1)
-    assertCharEquals((char)32768, $opt$ShortToChar((short)-32768));  // -(2^15)
+    assertCharEquals((char)1, $opt$noinline$ShortToChar((short)1));
+    assertCharEquals((char)0, $opt$noinline$ShortToChar((short)0));
+    assertCharEquals((char)65535, $opt$noinline$ShortToChar((short)-1));
+    assertCharEquals((char)51, $opt$noinline$ShortToChar((short)51));
+    assertCharEquals((char)65485, $opt$noinline$ShortToChar((short)-51));
+    assertCharEquals((char)32767, $opt$noinline$ShortToChar((short)32767));  // 2^15 - 1
+    assertCharEquals((char)32769, $opt$noinline$ShortToChar((short)-32767));  // -(2^15 - 1)
+    assertCharEquals((char)32768, $opt$noinline$ShortToChar((short)-32768));  // -(2^15)
   }
 
   private static void intToChar() {
-    assertCharEquals((char)1, $opt$IntToChar(1));
-    assertCharEquals((char)0, $opt$IntToChar(0));
-    assertCharEquals((char)65535, $opt$IntToChar(-1));
-    assertCharEquals((char)51, $opt$IntToChar(51));
-    assertCharEquals((char)65485, $opt$IntToChar(-51));
-    assertCharEquals((char)32767, $opt$IntToChar(32767));  // 2^15 - 1
-    assertCharEquals((char)32769, $opt$IntToChar(-32767));  // -(2^15 - 1)
-    assertCharEquals((char)32768, $opt$IntToChar(32768));  // 2^15
-    assertCharEquals((char)32768, $opt$IntToChar(-32768));  // -(2^15)
-    assertCharEquals((char)65535, $opt$IntToChar(65535));  // 2^16 - 1
-    assertCharEquals((char)1, $opt$IntToChar(-65535));  // -(2^16 - 1)
-    assertCharEquals((char)0, $opt$IntToChar(65536));  // 2^16
-    assertCharEquals((char)0, $opt$IntToChar(-65536));  // -(2^16)
-    assertCharEquals((char)65535, $opt$IntToChar(2147483647));  // 2^31 - 1
-    assertCharEquals((char)0, $opt$IntToChar(-2147483648));  // -(2^31)
+    assertCharEquals((char)1, $opt$noinline$IntToChar(1));
+    assertCharEquals((char)0, $opt$noinline$IntToChar(0));
+    assertCharEquals((char)65535, $opt$noinline$IntToChar(-1));
+    assertCharEquals((char)51, $opt$noinline$IntToChar(51));
+    assertCharEquals((char)65485, $opt$noinline$IntToChar(-51));
+    assertCharEquals((char)32767, $opt$noinline$IntToChar(32767));  // 2^15 - 1
+    assertCharEquals((char)32769, $opt$noinline$IntToChar(-32767));  // -(2^15 - 1)
+    assertCharEquals((char)32768, $opt$noinline$IntToChar(32768));  // 2^15
+    assertCharEquals((char)32768, $opt$noinline$IntToChar(-32768));  // -(2^15)
+    assertCharEquals((char)65535, $opt$noinline$IntToChar(65535));  // 2^16 - 1
+    assertCharEquals((char)1, $opt$noinline$IntToChar(-65535));  // -(2^16 - 1)
+    assertCharEquals((char)0, $opt$noinline$IntToChar(65536));  // 2^16
+    assertCharEquals((char)0, $opt$noinline$IntToChar(-65536));  // -(2^16)
+    assertCharEquals((char)65535, $opt$noinline$IntToChar(2147483647));  // 2^31 - 1
+    assertCharEquals((char)0, $opt$noinline$IntToChar(-2147483648));  // -(2^31)
   }
 
+  // A dummy value to defeat inlining of these routines.
+  static boolean doThrow = false;
 
   // These methods produce int-to-long Dex instructions.
-  static long $opt$ByteToLong(byte a) { return (long)a; }
-  static long $opt$ShortToLong(short a) { return (long)a; }
-  static long $opt$IntToLong(int a) { return (long)a; }
-  static long $opt$CharToLong(int a) { return (long)a; }
+  static long $opt$noinline$ByteToLong(byte a) { if (doThrow) throw new Error(); return (long)a; }
+  static long $opt$noinline$ShortToLong(short a) { if (doThrow) throw new Error(); return (long)a; }
+  static long $opt$noinline$IntToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
+  static long $opt$noinline$CharToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
 
   // These methods produce int-to-float Dex instructions.
-  static float $opt$ByteToFloat(byte a) { return (float)a; }
-  static float $opt$ShortToFloat(short a) { return (float)a; }
-  static float $opt$IntToFloat(int a) { return (float)a; }
-  static float $opt$CharToFloat(char a) { return (float)a; }
+  static float $opt$noinline$ByteToFloat(byte a) { if (doThrow) throw new Error(); return (float)a; }
+  static float $opt$noinline$ShortToFloat(short a) { if (doThrow) throw new Error(); return (float)a; }
+  static float $opt$noinline$IntToFloat(int a) { if (doThrow) throw new Error(); return (float)a; }
+  static float $opt$noinline$CharToFloat(char a) { if (doThrow) throw new Error(); return (float)a; }
 
   // These methods produce int-to-double Dex instructions.
-  static double $opt$ByteToDouble(byte a) { return (double)a; }
-  static double $opt$ShortToDouble(short a) { return (double)a; }
-  static double $opt$IntToDouble(int a) { return (double)a; }
-  static double $opt$CharToDouble(int a) { return (double)a; }
+  static double $opt$noinline$ByteToDouble(byte a) { if (doThrow) throw new Error(); return (double)a; }
+  static double $opt$noinline$ShortToDouble(short a) { if (doThrow) throw new Error(); return (double)a; }
+  static double $opt$noinline$IntToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
+  static double $opt$noinline$CharToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
 
   // These methods produce long-to-int Dex instructions.
-  static int $opt$LongToInt(long a) { return (int)a; }
-  static int $opt$LongLiteralToInt() { return (int)42L; }
+  static int $opt$noinline$LongToInt(long a) { if (doThrow) throw new Error(); return (int)a; }
+  static int $opt$noinline$LongLiteralToInt() { if (doThrow) throw new Error(); return (int)42L; }
 
   // This method produces a long-to-float Dex instruction.
-  static float $opt$LongToFloat(long a) { return (float)a; }
+  static float $opt$noinline$LongToFloat(long a) { if (doThrow) throw new Error(); return (float)a; }
 
   // This method produces a long-to-double Dex instruction.
-  static double $opt$LongToDouble(long a) { return (double)a; }
+  static double $opt$noinline$LongToDouble(long a) { if (doThrow) throw new Error(); return (double)a; }
 
   // This method produces a float-to-int Dex instruction.
-  static int $opt$FloatToInt(float a) { return (int)a; }
+  static int $opt$noinline$FloatToInt(float a) { if (doThrow) throw new Error(); return (int)a; }
 
   // This method produces a float-to-long Dex instruction.
-  static long $opt$FloatToLong(float a){ return (long)a; }
+  static long $opt$noinline$FloatToLong(float a){ if (doThrow) throw new Error(); return (long)a; }
 
   // This method produces a float-to-double Dex instruction.
-  static double $opt$FloatToDouble(float a) { return (double)a; }
+  static double $opt$noinline$FloatToDouble(float a) { if (doThrow) throw new Error(); return (double)a; }
 
   // This method produces a double-to-int Dex instruction.
-  static int $opt$DoubleToInt(double a){ return (int)a; }
+  static int $opt$noinline$DoubleToInt(double a){ if (doThrow) throw new Error(); return (int)a; }
 
   // This method produces a double-to-long Dex instruction.
-  static long $opt$DoubleToLong(double a){ return (long)a; }
+  static long $opt$noinline$DoubleToLong(double a){ if (doThrow) throw new Error(); return (long)a; }
 
   // This method produces a double-to-float Dex instruction.
-  static float $opt$DoubleToFloat(double a) { return (float)a; }
+  static float $opt$noinline$DoubleToFloat(double a) { if (doThrow) throw new Error(); return (float)a; }
 
   // These methods produce int-to-byte Dex instructions.
-  static byte $opt$ShortToByte(short a) { return (byte)a; }
-  static byte $opt$IntToByte(int a) { return (byte)a; }
-  static byte $opt$CharToByte(char a) { return (byte)a; }
+  static byte $opt$noinline$ShortToByte(short a) { if (doThrow) throw new Error(); return (byte)a; }
+  static byte $opt$noinline$IntToByte(int a) { if (doThrow) throw new Error(); return (byte)a; }
+  static byte $opt$noinline$CharToByte(char a) { if (doThrow) throw new Error(); return (byte)a; }
 
   // These methods produce int-to-short Dex instructions.
-  static short $opt$ByteToShort(byte a) { return (short)a; }
-  static short $opt$IntToShort(int a) { return (short)a; }
-  static short $opt$CharToShort(char a) { return (short)a; }
+  static short $opt$noinline$ByteToShort(byte a) { if (doThrow) throw new Error(); return (short)a; }
+  static short $opt$noinline$IntToShort(int a) { if (doThrow) throw new Error(); return (short)a; }
+  static short $opt$noinline$CharToShort(char a) { if (doThrow) throw new Error(); return (short)a; }
 
   // These methods produce int-to-char Dex instructions.
-  static char $opt$ByteToChar(byte a) { return (char)a; }
-  static char $opt$ShortToChar(short a) { return (char)a; }
-  static char $opt$IntToChar(int a) { return (char)a; }
+  static char $opt$noinline$ByteToChar(byte a) { if (doThrow) throw new Error(); return (char)a; }
+  static char $opt$noinline$ShortToChar(short a) { if (doThrow) throw new Error(); return (char)a; }
+  static char $opt$noinline$IntToChar(int a) { if (doThrow) throw new Error(); return (char)a; }
 }
diff --git a/test/441-checker-inliner/src/Main.java b/test/441-checker-inliner/src/Main.java
index 631b140..3899d7f 100644
--- a/test/441-checker-inliner/src/Main.java
+++ b/test/441-checker-inliner/src/Main.java
@@ -16,133 +16,133 @@
 
 public class Main {
 
-  // CHECK-START: void Main.InlineVoid() inliner (before)
-  // CHECK-DAG:     [[Const42:i\d+]] IntConstant 42
-  // CHECK-DAG:                      InvokeStaticOrDirect
-  // CHECK-DAG:                      InvokeStaticOrDirect [ [[Const42]] ]
+  /// CHECK-START: void Main.InlineVoid() inliner (before)
+  /// CHECK-DAG:     <<Const42:i\d+>> IntConstant 42
+  /// CHECK-DAG:                      InvokeStaticOrDirect
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Const42>>,{{[ij]\d+}}]
 
-  // CHECK-START: void Main.InlineVoid() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: void Main.InlineVoid() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
   public static void InlineVoid() {
     returnVoid();
     returnVoidWithOneParameter(42);
   }
 
-  // CHECK-START: int Main.InlineParameter(int) inliner (before)
-  // CHECK-DAG:     [[Param:i\d+]]  ParameterValue
-  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect [ [[Param]] ]
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  /// CHECK-START: int Main.InlineParameter(int) inliner (before)
+  /// CHECK-DAG:     <<Param:i\d+>>  ParameterValue
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect [<<Param>>,{{[ij]\d+}}]
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-  // CHECK-START: int Main.InlineParameter(int) inliner (after)
-  // CHECK-DAG:     [[Param:i\d+]]  ParameterValue
-  // CHECK-DAG:                     Return [ [[Param]] ]
+  /// CHECK-START: int Main.InlineParameter(int) inliner (after)
+  /// CHECK-DAG:     <<Param:i\d+>>  ParameterValue
+  /// CHECK-DAG:                     Return [<<Param>>]
 
   public static int InlineParameter(int a) {
     return returnParameter(a);
   }
 
-  // CHECK-START: long Main.InlineWideParameter(long) inliner (before)
-  // CHECK-DAG:     [[Param:j\d+]]  ParameterValue
-  // CHECK-DAG:     [[Result:j\d+]] InvokeStaticOrDirect [ [[Param]] ]
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  /// CHECK-START: long Main.InlineWideParameter(long) inliner (before)
+  /// CHECK-DAG:     <<Param:j\d+>>  ParameterValue
+  /// CHECK-DAG:     <<Result:j\d+>> InvokeStaticOrDirect [<<Param>>,{{[ij]\d+}}]
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-  // CHECK-START: long Main.InlineWideParameter(long) inliner (after)
-  // CHECK-DAG:     [[Param:j\d+]]  ParameterValue
-  // CHECK-DAG:                     Return [ [[Param]] ]
+  /// CHECK-START: long Main.InlineWideParameter(long) inliner (after)
+  /// CHECK-DAG:     <<Param:j\d+>>  ParameterValue
+  /// CHECK-DAG:                     Return [<<Param>>]
 
   public static long InlineWideParameter(long a) {
     return returnWideParameter(a);
   }
 
-  // CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (before)
-  // CHECK-DAG:     [[Param:l\d+]]  ParameterValue
-  // CHECK-DAG:     [[Result:l\d+]] InvokeStaticOrDirect [ [[Param]] ]
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  /// CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (before)
+  /// CHECK-DAG:     <<Param:l\d+>>  ParameterValue
+  /// CHECK-DAG:     <<Result:l\d+>> InvokeStaticOrDirect [<<Param>>,{{[ij]\d+}}]
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-  // CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (after)
-  // CHECK-DAG:     [[Param:l\d+]]  ParameterValue
-  // CHECK-DAG:                     Return [ [[Param]] ]
+  /// CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (after)
+  /// CHECK-DAG:     <<Param:l\d+>>  ParameterValue
+  /// CHECK-DAG:                     Return [<<Param>>]
 
   public static Object InlineReferenceParameter(Object o) {
     return returnReferenceParameter(o);
   }
 
-  // CHECK-START: int Main.InlineInt() inliner (before)
-  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  /// CHECK-START: int Main.InlineInt() inliner (before)
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-  // CHECK-START: int Main.InlineInt() inliner (after)
-  // CHECK-DAG:     [[Const4:i\d+]] IntConstant 4
-  // CHECK-DAG:                     Return [ [[Const4]] ]
+  /// CHECK-START: int Main.InlineInt() inliner (after)
+  /// CHECK-DAG:     <<Const4:i\d+>> IntConstant 4
+  /// CHECK-DAG:                     Return [<<Const4>>]
 
   public static int InlineInt() {
     return returnInt();
   }
 
-  // CHECK-START: long Main.InlineWide() inliner (before)
-  // CHECK-DAG:     [[Result:j\d+]] InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  /// CHECK-START: long Main.InlineWide() inliner (before)
+  /// CHECK-DAG:     <<Result:j\d+>> InvokeStaticOrDirect
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-  // CHECK-START: long Main.InlineWide() inliner (after)
-  // CHECK-DAG:     [[Const8:j\d+]] LongConstant 8
-  // CHECK-DAG:                     Return [ [[Const8]] ]
+  /// CHECK-START: long Main.InlineWide() inliner (after)
+  /// CHECK-DAG:     <<Const8:j\d+>> LongConstant 8
+  /// CHECK-DAG:                     Return [<<Const8>>]
 
   public static long InlineWide() {
     return returnWide();
   }
 
-  // CHECK-START: int Main.InlineAdd() inliner (before)
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Result:i\d+]] InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[Result]] ]
+  /// CHECK-START: int Main.InlineAdd() inliner (before)
+  /// CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  /// CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  /// CHECK-DAG:     <<Result:i\d+>> InvokeStaticOrDirect
+  /// CHECK-DAG:                     Return [<<Result>>]
 
-  // CHECK-START: int Main.InlineAdd() inliner (after)
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]    Add [ [[Const3]] [[Const5]] ]
-  // CHECK-DAG:                     Return [ [[Add]] ]
+  /// CHECK-START: int Main.InlineAdd() inliner (after)
+  /// CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  /// CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  /// CHECK-DAG:     <<Add:i\d+>>    Add [<<Const3>>,<<Const5>>]
+  /// CHECK-DAG:                     Return [<<Add>>]
 
   public static int InlineAdd() {
     return returnAdd(3, 5);
   }
 
-  // CHECK-START: int Main.InlineFieldAccess() inliner (before)
-  // CHECK-DAG:     [[After:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                     Return [ [[After]] ]
+  /// CHECK-START: int Main.InlineFieldAccess() inliner (before)
+  /// CHECK-DAG:     <<After:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                     Return [<<After>>]
 
-  // CHECK-START: int Main.InlineFieldAccess() inliner (after)
-  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
-  // CHECK-DAG:     [[Before:i\d+]] StaticFieldGet
-  // CHECK-DAG:     [[After:i\d+]]  Add [ [[Before]] [[Const1]] ]
-  // CHECK-DAG:                     StaticFieldSet [ {{l\d+}} [[After]] ]
-  // CHECK-DAG:                     Return [ [[After]] ]
+  /// CHECK-START: int Main.InlineFieldAccess() inliner (after)
+  /// CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
+  /// CHECK-DAG:     <<Before:i\d+>> StaticFieldGet
+  /// CHECK-DAG:     <<After:i\d+>>  Add [<<Before>>,<<Const1>>]
+  /// CHECK-DAG:                     StaticFieldSet [{{l\d+}},<<After>>]
+  /// CHECK-DAG:                     Return [<<After>>]
 
-  // CHECK-START: int Main.InlineFieldAccess() inliner (after)
-  // CHECK-NOT:                     InvokeStaticOrDirect
+  /// CHECK-START: int Main.InlineFieldAccess() inliner (after)
+  /// CHECK-NOT:                     InvokeStaticOrDirect
 
   public static int InlineFieldAccess() {
     return incCounter();
   }
 
-  // CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (before)
-  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]    InvokeStaticOrDirect [ [[Const1]] [[Const3]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]    InvokeStaticOrDirect [ [[Const5]] [[Const3]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]    Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                     Return [ [[Phi]] ]
+  /// CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (before)
+  /// CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
+  /// CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  /// CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  /// CHECK-DAG:     <<Add:i\d+>>    InvokeStaticOrDirect [<<Const1>>,<<Const3>>,{{[ij]\d+}}]
+  /// CHECK-DAG:     <<Sub:i\d+>>    InvokeStaticOrDirect [<<Const5>>,<<Const3>>,{{[ij]\d+}}]
+  /// CHECK-DAG:     <<Phi:i\d+>>    Phi [<<Add>>,<<Sub>>]
+  /// CHECK-DAG:                     Return [<<Phi>>]
 
-  // CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
-  // CHECK-DAG:     [[Const1:i\d+]] IntConstant 1
-  // CHECK-DAG:     [[Const3:i\d+]] IntConstant 3
-  // CHECK-DAG:     [[Const5:i\d+]] IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]    Add [ [[Const1]] [[Const3]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]    Sub [ [[Const5]] [[Const3]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]    Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                     Return [ [[Phi]] ]
+  /// CHECK-START: int Main.InlineWithControlFlow(boolean) inliner (after)
+  /// CHECK-DAG:     <<Const1:i\d+>> IntConstant 1
+  /// CHECK-DAG:     <<Const3:i\d+>> IntConstant 3
+  /// CHECK-DAG:     <<Const5:i\d+>> IntConstant 5
+  /// CHECK-DAG:     <<Add:i\d+>>    Add [<<Const1>>,<<Const3>>]
+  /// CHECK-DAG:     <<Sub:i\d+>>    Sub [<<Const5>>,<<Const3>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>    Phi [<<Add>>,<<Sub>>]
+  /// CHECK-DAG:                     Return [<<Phi>>]
 
   public static int InlineWithControlFlow(boolean cond) {
     int x, const1, const3, const5;
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 6b21fed..b7863be 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -16,6 +16,12 @@
 
 public class Main {
 
+  public static void assertFalse(boolean condition) {
+    if (condition) {
+      throw new Error();
+    }
+  }
+
   public static void assertIntEquals(int expected, int result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
@@ -28,19 +34,31 @@
     }
   }
 
+  public static void assertFloatEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertDoubleEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
   /**
    * Tiny three-register program exercising int constant folding
    * on negation.
    */
 
-  // CHECK-START: int Main.IntNegation() constant_folding (before)
-  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Const42]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.IntNegation() constant_folding (before)
+  /// CHECK-DAG:     <<Const42:i\d+>>  IntConstant 42
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Const42>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
-  // CHECK-START: int Main.IntNegation() constant_folding (after)
-  // CHECK-DAG:     [[ConstN42:i\d+]] IntConstant -42
-  // CHECK-DAG:                       Return [ [[ConstN42]] ]
+  /// CHECK-START: int Main.IntNegation() constant_folding (after)
+  /// CHECK-DAG:     <<ConstN42:i\d+>> IntConstant -42
+  /// CHECK-DAG:                       Return [<<ConstN42>>]
 
   public static int IntNegation() {
     int x, y;
@@ -54,15 +72,15 @@
    * on addition.
    */
 
-  // CHECK-START: int Main.IntAddition1() constant_folding (before)
-  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[Const1]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  /// CHECK-START: int Main.IntAddition1() constant_folding (before)
+  /// CHECK-DAG:     <<Const1:i\d+>>  IntConstant 1
+  /// CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  /// CHECK-DAG:     <<Add:i\d+>>     Add [<<Const1>>,<<Const2>>]
+  /// CHECK-DAG:                      Return [<<Add>>]
 
-  // CHECK-START: int Main.IntAddition1() constant_folding (after)
-  // CHECK-DAG:     [[Const3:i\d+]]  IntConstant 3
-  // CHECK-DAG:                      Return [ [[Const3]] ]
+  /// CHECK-START: int Main.IntAddition1() constant_folding (after)
+  /// CHECK-DAG:     <<Const3:i\d+>>  IntConstant 3
+  /// CHECK-DAG:                      Return [<<Const3>>]
 
   public static int IntAddition1() {
     int a, b, c;
@@ -77,19 +95,19 @@
   * on addition.
   */
 
-  // CHECK-START: int Main.IntAddition2() constant_folding (before)
-  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Const5:i\d+]]  IntConstant 5
-  // CHECK-DAG:     [[Const6:i\d+]]  IntConstant 6
-  // CHECK-DAG:     [[Add1:i\d+]]    Add [ [[Const1]] [[Const2]] ]
-  // CHECK-DAG:     [[Add2:i\d+]]    Add [ [[Const5]] [[Const6]] ]
-  // CHECK-DAG:     [[Add3:i\d+]]    Add [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                      Return [ [[Add3]] ]
+  /// CHECK-START: int Main.IntAddition2() constant_folding (before)
+  /// CHECK-DAG:     <<Const1:i\d+>>  IntConstant 1
+  /// CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  /// CHECK-DAG:     <<Const5:i\d+>>  IntConstant 5
+  /// CHECK-DAG:     <<Const6:i\d+>>  IntConstant 6
+  /// CHECK-DAG:     <<Add1:i\d+>>    Add [<<Const1>>,<<Const2>>]
+  /// CHECK-DAG:     <<Add2:i\d+>>    Add [<<Const5>>,<<Const6>>]
+  /// CHECK-DAG:     <<Add3:i\d+>>    Add [<<Add1>>,<<Add2>>]
+  /// CHECK-DAG:                      Return [<<Add3>>]
 
-  // CHECK-START: int Main.IntAddition2() constant_folding (after)
-  // CHECK-DAG:     [[Const14:i\d+]] IntConstant 14
-  // CHECK-DAG:                      Return [ [[Const14]] ]
+  /// CHECK-START: int Main.IntAddition2() constant_folding (after)
+  /// CHECK-DAG:     <<Const14:i\d+>> IntConstant 14
+  /// CHECK-DAG:                      Return [<<Const14>>]
 
   public static int IntAddition2() {
     int a, b, c;
@@ -108,15 +126,15 @@
    * on subtraction.
    */
 
-  // CHECK-START: int Main.IntSubtraction() constant_folding (before)
-  // CHECK-DAG:     [[Const6:i\d+]]  IntConstant 6
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[Const6]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Sub]] ]
+  /// CHECK-START: int Main.IntSubtraction() constant_folding (before)
+  /// CHECK-DAG:     <<Const6:i\d+>>  IntConstant 6
+  /// CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  /// CHECK-DAG:     <<Sub:i\d+>>     Sub [<<Const6>>,<<Const2>>]
+  /// CHECK-DAG:                      Return [<<Sub>>]
 
-  // CHECK-START: int Main.IntSubtraction() constant_folding (after)
-  // CHECK-DAG:     [[Const4:i\d+]]  IntConstant 4
-  // CHECK-DAG:                      Return [ [[Const4]] ]
+  /// CHECK-START: int Main.IntSubtraction() constant_folding (after)
+  /// CHECK-DAG:     <<Const4:i\d+>>  IntConstant 4
+  /// CHECK-DAG:                      Return [<<Const4>>]
 
   public static int IntSubtraction() {
     int a, b, c;
@@ -131,15 +149,15 @@
    * on addition.
    */
 
-  // CHECK-START: long Main.LongAddition() constant_folding (before)
-  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
-  // CHECK-DAG:     [[Const2:j\d+]]  LongConstant 2
-  // CHECK-DAG:     [[Add:j\d+]]     Add [ [[Const1]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  /// CHECK-START: long Main.LongAddition() constant_folding (before)
+  /// CHECK-DAG:     <<Const1:j\d+>>  LongConstant 1
+  /// CHECK-DAG:     <<Const2:j\d+>>  LongConstant 2
+  /// CHECK-DAG:     <<Add:j\d+>>     Add [<<Const1>>,<<Const2>>]
+  /// CHECK-DAG:                      Return [<<Add>>]
 
-  // CHECK-START: long Main.LongAddition() constant_folding (after)
-  // CHECK-DAG:     [[Const3:j\d+]]  LongConstant 3
-  // CHECK-DAG:                      Return [ [[Const3]] ]
+  /// CHECK-START: long Main.LongAddition() constant_folding (after)
+  /// CHECK-DAG:     <<Const3:j\d+>>  LongConstant 3
+  /// CHECK-DAG:                      Return [<<Const3>>]
 
   public static long LongAddition() {
     long a, b, c;
@@ -154,15 +172,15 @@
    * on subtraction.
    */
 
-  // CHECK-START: long Main.LongSubtraction() constant_folding (before)
-  // CHECK-DAG:     [[Const6:j\d+]]  LongConstant 6
-  // CHECK-DAG:     [[Const2:j\d+]]  LongConstant 2
-  // CHECK-DAG:     [[Sub:j\d+]]     Sub [ [[Const6]] [[Const2]] ]
-  // CHECK-DAG:                      Return [ [[Sub]] ]
+  /// CHECK-START: long Main.LongSubtraction() constant_folding (before)
+  /// CHECK-DAG:     <<Const6:j\d+>>  LongConstant 6
+  /// CHECK-DAG:     <<Const2:j\d+>>  LongConstant 2
+  /// CHECK-DAG:     <<Sub:j\d+>>     Sub [<<Const6>>,<<Const2>>]
+  /// CHECK-DAG:                      Return [<<Sub>>]
 
-  // CHECK-START: long Main.LongSubtraction() constant_folding (after)
-  // CHECK-DAG:     [[Const4:j\d+]]  LongConstant 4
-  // CHECK-DAG:                      Return [ [[Const4]] ]
+  /// CHECK-START: long Main.LongSubtraction() constant_folding (after)
+  /// CHECK-DAG:     <<Const4:j\d+>>  LongConstant 4
+  /// CHECK-DAG:                      Return [<<Const4>>]
 
   public static long LongSubtraction() {
     long a, b, c;
@@ -176,15 +194,15 @@
    * Three-register program with a constant (static) condition.
    */
 
-  // CHECK-START: int Main.StaticCondition() constant_folding (before)
-  // CHECK-DAG:     [[Const7:i\d+]]  IntConstant 7
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Cond:z\d+]]    GreaterThanOrEqual [ [[Const7]] [[Const2]] ]
-  // CHECK-DAG:                      If [ [[Cond]] ]
+  /// CHECK-START: int Main.StaticCondition() constant_folding (before)
+  /// CHECK-DAG:     <<Const7:i\d+>>  IntConstant 7
+  /// CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  /// CHECK-DAG:     <<Cond:z\d+>>    GreaterThanOrEqual [<<Const7>>,<<Const2>>]
+  /// CHECK-DAG:                      If [<<Cond>>]
 
-  // CHECK-START: int Main.StaticCondition() constant_folding (after)
-  // CHECK-DAG:     [[Const1:i\d+]]  IntConstant 1
-  // CHECK-DAG:                      If [ [[Const1]] ]
+  /// CHECK-START: int Main.StaticCondition() constant_folding (after)
+  /// CHECK-DAG:     <<Const1:i\d+>>  IntConstant 1
+  /// CHECK-DAG:                      If [<<Const1>>]
 
   public static int StaticCondition() {
     int a, b, c;
@@ -206,19 +224,19 @@
    * (forward) post-order traversal of the the dominator tree.
    */
 
-  // CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (before)
-  // CHECK-DAG:     [[Const2:i\d+]]  IntConstant 2
-  // CHECK-DAG:     [[Const5:i\d+]]  IntConstant 5
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[Const5]] [[Const2]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[Const5]] [[Const2]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  /// CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (before)
+  /// CHECK-DAG:     <<Const2:i\d+>>  IntConstant 2
+  /// CHECK-DAG:     <<Const5:i\d+>>  IntConstant 5
+  /// CHECK-DAG:     <<Add:i\d+>>     Add [<<Const5>>,<<Const2>>]
+  /// CHECK-DAG:     <<Sub:i\d+>>     Sub [<<Const5>>,<<Const2>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Add>>,<<Sub>>]
+  /// CHECK-DAG:                      Return [<<Phi>>]
 
-  // CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (after)
-  // CHECK-DAG:     [[Const3:i\d+]]  IntConstant 3
-  // CHECK-DAG:     [[Const7:i\d+]]  IntConstant 7
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Const7]] [[Const3]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  /// CHECK-START: int Main.JumpsAndConditionals(boolean) constant_folding (after)
+  /// CHECK-DAG:     <<Const3:i\d+>>  IntConstant 3
+  /// CHECK-DAG:     <<Const7:i\d+>>  IntConstant 7
+  /// CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Const7>>,<<Const3>>]
+  /// CHECK-DAG:                      Return [<<Phi>>]
 
   public static int JumpsAndConditionals(boolean cond) {
     int a, b, c;
@@ -235,178 +253,394 @@
    * Test optimizations of arithmetic identities yielding a constant result.
    */
 
-  // CHECK-START: int Main.And0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[And:i\d+]]      And [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[And]] ]
+  /// CHECK-START: int Main.And0(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<And:i\d+>>      And [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<And>>]
 
-  // CHECK-START: int Main.And0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-NOT:                       And
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: int Main.And0(int) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-NOT:                       And
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static int And0(int arg) {
     return arg & 0;
   }
 
-  // CHECK-START: long Main.Mul0(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Mul:j\d+]]      Mul [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Mul]] ]
+  /// CHECK-START: long Main.Mul0(long) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-DAG:     <<Mul:j\d+>>      Mul [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Mul>>]
 
-  // CHECK-START: long Main.Mul0(long) constant_folding (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-NOT:                       Mul
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: long Main.Mul0(long) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-NOT:                       Mul
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static long Mul0(long arg) {
     return arg * 0;
   }
 
-  // CHECK-START: int Main.OrAllOnes(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF:i\d+]]   IntConstant -1
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Arg]] [[ConstF]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.OrAllOnes(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstF:i\d+>>   IntConstant -1
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Arg>>,<<ConstF>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.OrAllOnes(int) constant_folding (after)
-  // CHECK-DAG:     [[ConstF:i\d+]]   IntConstant -1
-  // CHECK-NOT:                       Or
-  // CHECK-DAG:                       Return [ [[ConstF]] ]
+  /// CHECK-START: int Main.OrAllOnes(int) constant_folding (after)
+  /// CHECK-DAG:     <<ConstF:i\d+>>   IntConstant -1
+  /// CHECK-NOT:                       Or
+  /// CHECK-DAG:                       Return [<<ConstF>>]
 
   public static int OrAllOnes(int arg) {
     return arg | -1;
   }
 
-  // CHECK-START: long Main.Rem0(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]           ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]        LongConstant 0
-  // CHECK-DAG:     [[DivZeroCheck:j\d+]]  DivZeroCheck [ [[Arg]] ]
-  // CHECK-DAG:     [[Rem:j\d+]]           Rem [ [[Const0]] [[DivZeroCheck]] ]
-  // CHECK-DAG:                            Return [ [[Rem]] ]
+  /// CHECK-START: long Main.Rem0(long) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>           ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
+  /// CHECK-DAG:     <<DivZeroCheck:j\d+>>  DivZeroCheck [<<Arg>>]
+  /// CHECK-DAG:     <<Rem:j\d+>>           Rem [<<Const0>>,<<DivZeroCheck>>]
+  /// CHECK-DAG:                            Return [<<Rem>>]
 
-  // CHECK-START: long Main.Rem0(long) constant_folding (after)
-  // CHECK-DAG:     [[Const0:j\d+]]        LongConstant 0
-  // CHECK-NOT:                            Rem
-  // CHECK-DAG:                            Return [ [[Const0]] ]
+  /// CHECK-START: long Main.Rem0(long) constant_folding (after)
+  /// CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
+  /// CHECK-NOT:                            Rem
+  /// CHECK-DAG:                            Return [<<Const0>>]
 
   public static long Rem0(long arg) {
     return 0 % arg;
   }
 
-  // CHECK-START: int Main.Rem1(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Rem:i\d+]]      Rem [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       Return [ [[Rem]] ]
+  /// CHECK-START: int Main.Rem1(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Rem:i\d+>>      Rem [<<Arg>>,<<Const1>>]
+  /// CHECK-DAG:                       Return [<<Rem>>]
 
-  // CHECK-START: int Main.Rem1(int) constant_folding (after)
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-NOT:                       Rem
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: int Main.Rem1(int) constant_folding (after)
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-NOT:                       Rem
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static int Rem1(int arg) {
     return arg % 1;
   }
 
-  // CHECK-START: long Main.RemN1(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]           ParameterValue
-  // CHECK-DAG:     [[ConstN1:j\d+]]       LongConstant -1
-  // CHECK-DAG:     [[DivZeroCheck:j\d+]]  DivZeroCheck [ [[Arg]] ]
-  // CHECK-DAG:     [[Rem:j\d+]]           Rem [ [[Arg]] [[DivZeroCheck]] ]
-  // CHECK-DAG:                            Return [ [[Rem]] ]
+  /// CHECK-START: long Main.RemN1(long) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>           ParameterValue
+  /// CHECK-DAG:     <<ConstN1:j\d+>>       LongConstant -1
+  /// CHECK-DAG:     <<DivZeroCheck:j\d+>>  DivZeroCheck [<<ConstN1>>]
+  /// CHECK-DAG:     <<Rem:j\d+>>           Rem [<<Arg>>,<<DivZeroCheck>>]
+  /// CHECK-DAG:                            Return [<<Rem>>]
 
-  // CHECK-START: long Main.RemN1(long) constant_folding (after)
-  // CHECK-DAG:     [[Const0:j\d+]]        LongConstant 0
-  // CHECK-NOT:                            Rem
-  // CHECK-DAG:                            Return [ [[Const0]] ]
+  /// CHECK-START: long Main.RemN1(long) constant_folding (after)
+  /// CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
+  /// CHECK-NOT:                            Rem
+  /// CHECK-DAG:                            Return [<<Const0>>]
 
   public static long RemN1(long arg) {
     return arg % -1;
   }
 
-  // CHECK-START: int Main.Shl0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Shl:i\d+]]      Shl [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Shl]] ]
+  /// CHECK-START: int Main.Shl0(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Shl>>]
 
-  // CHECK-START: int Main.Shl0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-NOT:                       Shl
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: int Main.Shl0(int) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-NOT:                       Shl
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static int Shl0(int arg) {
     return 0 << arg;
   }
 
-  // CHECK-START: long Main.Shr0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Shr:j\d+]]      Shr [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Shr]] ]
+  /// CHECK-START: long Main.Shr0(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-DAG:     <<Shr:j\d+>>      Shr [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Shr>>]
 
-  // CHECK-START: long Main.Shr0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-NOT:                       Shr
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: long Main.Shr0(int) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-NOT:                       Shr
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static long Shr0(int arg) {
     return (long)0 >> arg;
   }
 
-  // CHECK-START: long Main.SubSameLong(long) constant_folding (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: long Main.SubSameLong(long) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Arg>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: long Main.SubSameLong(long) constant_folding (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-NOT:                       Sub
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: long Main.SubSameLong(long) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-NOT:                       Sub
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static long SubSameLong(long arg) {
     return arg - arg;
   }
 
-  // CHECK-START: int Main.UShr0(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[UShr:i\d+]]     UShr [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[UShr]] ]
+  /// CHECK-START: int Main.UShr0(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<UShr:i\d+>>     UShr [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<UShr>>]
 
-  // CHECK-START: int Main.UShr0(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-NOT:                       UShr
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: int Main.UShr0(int) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-NOT:                       UShr
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static int UShr0(int arg) {
     return 0 >>> arg;
   }
 
-  // CHECK-START: int Main.XorSameInt(int) constant_folding (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Xor:i\d+]]      Xor [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Xor]] ]
+  /// CHECK-START: int Main.XorSameInt(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Xor:i\d+>>      Xor [<<Arg>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Xor>>]
 
-  // CHECK-START: int Main.XorSameInt(int) constant_folding (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-NOT:                       Xor
-  // CHECK-DAG:                       Return [ [[Const0]] ]
+  /// CHECK-START: int Main.XorSameInt(int) constant_folding (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-NOT:                       Xor
+  /// CHECK-DAG:                       Return [<<Const0>>]
 
   public static int XorSameInt(int arg) {
     return arg ^ arg;
   }
 
+  /// CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstNan:f\d+>> FloatConstant nan
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:                       IntConstant 1
+  /// CHECK-DAG:     <<Cmp:i\d+>>      Compare [<<Arg>>,<<ConstNan>>]
+  /// CHECK-DAG:     <<Le:z\d+>>       LessThanOrEqual [<<Cmp>>,<<Const0>>]
+  /// CHECK-DAG:                       If [<<Le>>]
+
+  /// CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (after)
+  /// CHECK-DAG:                       ParameterValue
+  /// CHECK-DAG:                       FloatConstant nan
+  /// CHECK-DAG:                       IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:                       If [<<Const1>>]
+
+  /// CHECK-START: boolean Main.CmpFloatGreaterThanNaN(float) constant_folding (after)
+  /// CHECK-NOT:                       Compare
+  /// CHECK-NOT:                       LessThanOrEqual
+
+  public static boolean CmpFloatGreaterThanNaN(float arg) {
+    return arg > Float.NaN;
+  }
+
+  /// CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:d\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstNan:d\d+>> DoubleConstant nan
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:                       IntConstant 1
+  /// CHECK-DAG:     <<Cmp:i\d+>>      Compare [<<Arg>>,<<ConstNan>>]
+  /// CHECK-DAG:     <<Ge:z\d+>>       GreaterThanOrEqual [<<Cmp>>,<<Const0>>]
+  /// CHECK-DAG:                       If [<<Ge>>]
+
+  /// CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (after)
+  /// CHECK-DAG:                       ParameterValue
+  /// CHECK-DAG:                       DoubleConstant nan
+  /// CHECK-DAG:                       IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:                       If [<<Const1>>]
+
+  /// CHECK-START: boolean Main.CmpDoubleLessThanNaN(double) constant_folding (after)
+  /// CHECK-NOT:                       Compare
+  /// CHECK-NOT:                       GreaterThanOrEqual
+
+  public static boolean CmpDoubleLessThanNaN(double arg) {
+    return arg < Double.NaN;
+  }
+
+  /// CHECK-START: int Main.ReturnInt33() constant_folding (before)
+  /// CHECK-DAG:     <<Const33:j\d+>>  LongConstant 33
+  /// CHECK-DAG:     <<Convert:i\d+>>  TypeConversion [<<Const33>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: int Main.ReturnInt33() constant_folding (after)
+  /// CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  /// CHECK-DAG:                       Return [<<Const33>>]
+
+  public static int ReturnInt33() {
+    long imm = 33L;
+    return (int) imm;
+  }
+
+  /// CHECK-START: int Main.ReturnIntMax() constant_folding (before)
+  /// CHECK-DAG:     <<ConstMax:f\d+>> FloatConstant 1e+34
+  /// CHECK-DAG:     <<Convert:i\d+>>  TypeConversion [<<ConstMax>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: int Main.ReturnIntMax() constant_folding (after)
+  /// CHECK-DAG:     <<ConstMax:i\d+>> IntConstant 2147483647
+  /// CHECK-DAG:                       Return [<<ConstMax>>]
+
+  public static int ReturnIntMax() {
+    float imm = 1.0e34f;
+    return (int) imm;
+  }
+
+  /// CHECK-START: int Main.ReturnInt0() constant_folding (before)
+  /// CHECK-DAG:     <<ConstNaN:d\d+>> DoubleConstant nan
+  /// CHECK-DAG:     <<Convert:i\d+>>  TypeConversion [<<ConstNaN>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: int Main.ReturnInt0() constant_folding (after)
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:                       Return [<<Const0>>]
+
+  public static int ReturnInt0() {
+    double imm = Double.NaN;
+    return (int) imm;
+  }
+
+  /// CHECK-START: long Main.ReturnLong33() constant_folding (before)
+  /// CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  /// CHECK-DAG:     <<Convert:j\d+>>  TypeConversion [<<Const33>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: long Main.ReturnLong33() constant_folding (after)
+  /// CHECK-DAG:     <<Const33:j\d+>>  LongConstant 33
+  /// CHECK-DAG:                       Return [<<Const33>>]
+
+  public static long ReturnLong33() {
+    int imm = 33;
+    return (long) imm;
+  }
+
+  /// CHECK-START: long Main.ReturnLong34() constant_folding (before)
+  /// CHECK-DAG:     <<Const34:f\d+>>  FloatConstant 34
+  /// CHECK-DAG:     <<Convert:j\d+>>  TypeConversion [<<Const34>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: long Main.ReturnLong34() constant_folding (after)
+  /// CHECK-DAG:     <<Const34:j\d+>>  LongConstant 34
+  /// CHECK-DAG:                       Return [<<Const34>>]
+
+  public static long ReturnLong34() {
+    float imm = 34.0f;
+    return (long) imm;
+  }
+
+  /// CHECK-START: long Main.ReturnLong0() constant_folding (before)
+  /// CHECK-DAG:     <<ConstNaN:d\d+>> DoubleConstant nan
+  /// CHECK-DAG:     <<Convert:j\d+>>  TypeConversion [<<ConstNaN>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: long Main.ReturnLong0() constant_folding (after)
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-DAG:                       Return [<<Const0>>]
+
+  public static long ReturnLong0() {
+    double imm = -Double.NaN;
+    return (long) imm;
+  }
+
+  /// CHECK-START: float Main.ReturnFloat33() constant_folding (before)
+  /// CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  /// CHECK-DAG:     <<Convert:f\d+>>  TypeConversion [<<Const33>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: float Main.ReturnFloat33() constant_folding (after)
+  /// CHECK-DAG:     <<Const33:f\d+>>  FloatConstant 33
+  /// CHECK-DAG:                       Return [<<Const33>>]
+
+  public static float ReturnFloat33() {
+    int imm = 33;
+    return (float) imm;
+  }
+
+  /// CHECK-START: float Main.ReturnFloat34() constant_folding (before)
+  /// CHECK-DAG:     <<Const34:j\d+>>  LongConstant 34
+  /// CHECK-DAG:     <<Convert:f\d+>>  TypeConversion [<<Const34>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: float Main.ReturnFloat34() constant_folding (after)
+  /// CHECK-DAG:     <<Const34:f\d+>>  FloatConstant 34
+  /// CHECK-DAG:                       Return [<<Const34>>]
+
+  public static float ReturnFloat34() {
+    long imm = 34L;
+    return (float) imm;
+  }
+
+  /// CHECK-START: float Main.ReturnFloat99P25() constant_folding (before)
+  /// CHECK-DAG:     <<Const:d\d+>>    DoubleConstant 99.25
+  /// CHECK-DAG:     <<Convert:f\d+>>  TypeConversion [<<Const>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: float Main.ReturnFloat99P25() constant_folding (after)
+  /// CHECK-DAG:     <<Const:f\d+>>    FloatConstant 99.25
+  /// CHECK-DAG:                       Return [<<Const>>]
+
+  public static float ReturnFloat99P25() {
+    double imm = 99.25;
+    return (float) imm;
+  }
+
+  /// CHECK-START: double Main.ReturnDouble33() constant_folding (before)
+  /// CHECK-DAG:     <<Const33:i\d+>>  IntConstant 33
+  /// CHECK-DAG:     <<Convert:d\d+>>  TypeConversion [<<Const33>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: double Main.ReturnDouble33() constant_folding (after)
+  /// CHECK-DAG:     <<Const33:d\d+>>  DoubleConstant 33
+  /// CHECK-DAG:                       Return [<<Const33>>]
+
+  public static double ReturnDouble33() {
+    int imm = 33;
+    return (double) imm;
+  }
+
+  /// CHECK-START: double Main.ReturnDouble34() constant_folding (before)
+  /// CHECK-DAG:     <<Const34:j\d+>>  LongConstant 34
+  /// CHECK-DAG:     <<Convert:d\d+>>  TypeConversion [<<Const34>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: double Main.ReturnDouble34() constant_folding (after)
+  /// CHECK-DAG:     <<Const34:d\d+>>  DoubleConstant 34
+  /// CHECK-DAG:                       Return [<<Const34>>]
+
+  public static double ReturnDouble34() {
+    long imm = 34L;
+    return (double) imm;
+  }
+
+  /// CHECK-START: double Main.ReturnDouble99P25() constant_folding (before)
+  /// CHECK-DAG:     <<Const:f\d+>>    FloatConstant 99.25
+  /// CHECK-DAG:     <<Convert:d\d+>>  TypeConversion [<<Const>>]
+  /// CHECK-DAG:                       Return [<<Convert>>]
+
+  /// CHECK-START: double Main.ReturnDouble99P25() constant_folding (after)
+  /// CHECK-DAG:     <<Const:d\d+>>    DoubleConstant 99.25
+  /// CHECK-DAG:                       Return [<<Const>>]
+
+  public static double ReturnDouble99P25() {
+    float imm = 99.25f;
+    return (double) imm;
+  }
+
   public static void main(String[] args) {
     assertIntEquals(IntNegation(), -42);
     assertIntEquals(IntAddition1(), 3);
@@ -417,17 +651,31 @@
     assertIntEquals(StaticCondition(), 5);
     assertIntEquals(JumpsAndConditionals(true), 7);
     assertIntEquals(JumpsAndConditionals(false), 3);
-    int random = 123456;  // Chosen randomly.
-    assertIntEquals(And0(random), 0);
-    assertLongEquals(Mul0(random), 0);
-    assertIntEquals(OrAllOnes(random), -1);
-    assertLongEquals(Rem0(random), 0);
-    assertIntEquals(Rem1(random), 0);
-    assertLongEquals(RemN1(random), 0);
-    assertIntEquals(Shl0(random), 0);
-    assertLongEquals(Shr0(random), 0);
-    assertLongEquals(SubSameLong(random), 0);
-    assertIntEquals(UShr0(random), 0);
-    assertIntEquals(XorSameInt(random), 0);
+    int arbitrary = 123456;  // Value chosen arbitrarily.
+    assertIntEquals(And0(arbitrary), 0);
+    assertLongEquals(Mul0(arbitrary), 0);
+    assertIntEquals(OrAllOnes(arbitrary), -1);
+    assertLongEquals(Rem0(arbitrary), 0);
+    assertIntEquals(Rem1(arbitrary), 0);
+    assertLongEquals(RemN1(arbitrary), 0);
+    assertIntEquals(Shl0(arbitrary), 0);
+    assertLongEquals(Shr0(arbitrary), 0);
+    assertLongEquals(SubSameLong(arbitrary), 0);
+    assertIntEquals(UShr0(arbitrary), 0);
+    assertIntEquals(XorSameInt(arbitrary), 0);
+    assertFalse(CmpFloatGreaterThanNaN(arbitrary));
+    assertFalse(CmpDoubleLessThanNaN(arbitrary));
+    assertIntEquals(ReturnInt33(), 33);
+    assertIntEquals(ReturnIntMax(), 2147483647);
+    assertIntEquals(ReturnInt0(), 0);
+    assertLongEquals(ReturnLong33(), 33);
+    assertLongEquals(ReturnLong34(), 34);
+    assertLongEquals(ReturnLong0(), 0);
+    assertFloatEquals(ReturnFloat33(), 33);
+    assertFloatEquals(ReturnFloat34(), 34);
+    assertFloatEquals(ReturnFloat99P25(), 99.25f);
+    assertDoubleEquals(ReturnDouble33(), 33);
+    assertDoubleEquals(ReturnDouble34(), 34);
+    assertDoubleEquals(ReturnDouble99P25(), 99.25);
   }
 }
diff --git a/test/444-checker-nce/src/Main.java b/test/444-checker-nce/src/Main.java
index 501d79c..32122e4 100644
--- a/test/444-checker-nce/src/Main.java
+++ b/test/444-checker-nce/src/Main.java
@@ -16,63 +16,63 @@
 
 public class Main {
 
-  // CHECK-START: Main Main.keepTest(Main) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
-  // CHECK:         InvokeStaticOrDirect
+  /// CHECK-START: Main Main.keepTest(Main) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
+  /// CHECK:         InvokeStaticOrDirect
 
-  // CHECK-START: Main Main.keepTest(Main) instruction_simplifier_after_types (after)
-  // CHECK:         NullCheck
-  // CHECK:         InvokeStaticOrDirect
+  /// CHECK-START: Main Main.keepTest(Main) instruction_simplifier_after_types (after)
+  /// CHECK:         NullCheck
+  /// CHECK:         InvokeStaticOrDirect
   public Main keepTest(Main m) {
     return m.g();
   }
 
-  // CHECK-START: Main Main.thisTest() instruction_simplifier (before)
-  // CHECK:         NullCheck
-  // CHECK:         InvokeStaticOrDirect
+  /// CHECK-START: Main Main.thisTest() ssa_builder (after)
+  /// CHECK:         NullCheck
+  /// CHECK:         InvokeStaticOrDirect
 
-  // CHECK-START: Main Main.thisTest() instruction_simplifier (after)
-  // CHECK-NOT:     NullCheck
-  // CHECK:         InvokeStaticOrDirect
+  /// CHECK-START: Main Main.thisTest() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
+  /// CHECK:         InvokeStaticOrDirect
   public Main thisTest() {
     return g();
   }
 
-  // CHECK-START: Main Main.newInstanceRemoveTest() instruction_simplifier (before)
-  // CHECK:         NewInstance
-  // CHECK:         NullCheck
-  // CHECK:         InvokeStaticOrDirect
-  // CHECK:         NullCheck
-  // CHECK:         InvokeStaticOrDirect
+  /// CHECK-START: Main Main.newInstanceRemoveTest() ssa_builder (after)
+  /// CHECK:         NewInstance
+  /// CHECK:         NullCheck
+  /// CHECK:         InvokeStaticOrDirect
+  /// CHECK:         NullCheck
+  /// CHECK:         InvokeStaticOrDirect
 
-  // CHECK-START: Main Main.newInstanceRemoveTest() instruction_simplifier (after)
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: Main Main.newInstanceRemoveTest() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
   public Main newInstanceRemoveTest() {
     Main m = new Main();
     return m.g();
   }
 
-  // CHECK-START: Main Main.newArrayRemoveTest() instruction_simplifier (before)
-  // CHECK:         NewArray
-  // CHECK:         NullCheck
-  // CHECK:         ArrayGet
+  /// CHECK-START: Main Main.newArrayRemoveTest() ssa_builder (after)
+  /// CHECK:         NewArray
+  /// CHECK:         NullCheck
+  /// CHECK:         ArrayGet
 
-  // CHECK-START: Main Main.newArrayRemoveTest() instruction_simplifier (after)
-  // CHECK:         NewArray
-  // CHECK-NOT:     NullCheck
-  // CHECK:         ArrayGet
+  /// CHECK-START: Main Main.newArrayRemoveTest() instruction_simplifier_after_types (after)
+  /// CHECK:         NewArray
+  /// CHECK-NOT:     NullCheck
+  /// CHECK:         ArrayGet
   public Main newArrayRemoveTest() {
     Main[] ms = new Main[1];
     return ms[0];
   }
 
-  // CHECK-START: Main Main.ifRemoveTest(boolean) instruction_simplifier_after_types (before)
-  // CHECK:         NewInstance
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.ifRemoveTest(boolean) instruction_simplifier_after_types (before)
+  /// CHECK:         NewInstance
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.ifRemoveTest(boolean) instruction_simplifier_after_types (after)
-  // CHECK:         NewInstance
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: Main Main.ifRemoveTest(boolean) instruction_simplifier_after_types (after)
+  /// CHECK:         NewInstance
+  /// CHECK-NOT:     NullCheck
   public Main ifRemoveTest(boolean flag) {
     Main m = null;
     if (flag) {
@@ -83,13 +83,13 @@
     return m.g();
   }
 
-  // CHECK-START: Main Main.ifKeepTest(boolean) instruction_simplifier_after_types (before)
-  // CHECK:         NewInstance
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.ifKeepTest(boolean) instruction_simplifier_after_types (before)
+  /// CHECK:         NewInstance
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.ifKeepTest(boolean) instruction_simplifier_after_types (after)
-  // CHECK:         NewInstance
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.ifKeepTest(boolean) instruction_simplifier_after_types (after)
+  /// CHECK:         NewInstance
+  /// CHECK:         NullCheck
   public Main ifKeepTest(boolean flag) {
     Main m = null;
     if (flag) {
@@ -98,11 +98,11 @@
     return m.g();
   }
 
-  // CHECK-START: Main Main.forRemoveTest(int) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.forRemoveTest(int) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.forRemoveTest(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: Main Main.forRemoveTest(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
   public Main forRemoveTest(int count) {
     Main a = new Main();
     Main m = new Main();
@@ -114,11 +114,11 @@
     return m.g();
   }
 
-  // CHECK-START: Main Main.forKeepTest(int) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.forKeepTest(int) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.forKeepTest(int) instruction_simplifier_after_types (after)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.forKeepTest(int) instruction_simplifier_after_types (after)
+  /// CHECK:         NullCheck
   public Main forKeepTest(int count) {
     Main a = new Main();
     Main m = new Main();
@@ -132,11 +132,11 @@
     return m.g();
   }
 
-  // CHECK-START: Main Main.phiFlowRemoveTest(int) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.phiFlowRemoveTest(int) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.phiFlowRemoveTest(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: Main Main.phiFlowRemoveTest(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
   public Main phiFlowRemoveTest(int count) {
     Main a = new Main();
     Main m = new Main();
@@ -154,11 +154,11 @@
     return n.g();
   }
 
-  // CHECK-START: Main Main.phiFlowKeepTest(int) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.phiFlowKeepTest(int) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.phiFlowKeepTest(int) instruction_simplifier_after_types (after)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.phiFlowKeepTest(int) instruction_simplifier_after_types (after)
+  /// CHECK:         NullCheck
   public Main phiFlowKeepTest(int count) {
     Main a = new Main();
     Main m = new Main();
@@ -178,11 +178,11 @@
     return n.g();
   }
 
-  // CHECK-START: Main Main.scopeRemoveTest(int, Main) instruction_simplifier (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.scopeRemoveTest(int, Main) ssa_builder (after)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.scopeRemoveTest(int, Main) instruction_simplifier (after)
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: Main Main.scopeRemoveTest(int, Main) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
   public Main scopeRemoveTest(int count, Main a) {
     Main m = null;
     for (int i = 0; i < count; i++) {
@@ -196,11 +196,11 @@
     return m;
   }
 
-  // CHECK-START: Main Main.scopeKeepTest(int, Main) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.scopeKeepTest(int, Main) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.scopeKeepTest(int, Main) instruction_simplifier_after_types (after)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.scopeKeepTest(int, Main) instruction_simplifier_after_types (after)
+  /// CHECK:         NullCheck
   public Main scopeKeepTest(int count, Main a) {
     Main m = new Main();
     for (int i = 0; i < count; i++) {
@@ -214,11 +214,11 @@
     return m;
   }
 
-  // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
   public Main scopeIfNotNullRemove(Main m) {
     if (m != null) {
       return m.g();
@@ -226,11 +226,11 @@
     return m;
   }
 
-  // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
 
-  // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (after)
-  // CHECK:         NullCheck
+  /// CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (after)
+  /// CHECK:         NullCheck
   public Main scopeIfKeep(Main m) {
     if (m == null) {
       m = new Main();
@@ -258,12 +258,12 @@
 class ListElement {
   private ListElement next;
 
-  // CHECK-START: boolean ListElement.isShorter(ListElement, ListElement) instruction_simplifier_after_types (before)
-  // CHECK:         NullCheck
-  // CHECK:         NullCheck
+  /// CHECK-START: boolean ListElement.isShorter(ListElement, ListElement) instruction_simplifier_after_types (before)
+  /// CHECK:         NullCheck
+  /// CHECK:         NullCheck
 
-  // CHECK-START: boolean ListElement.isShorter(ListElement, ListElement) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     NullCheck
+  /// CHECK-START: boolean ListElement.isShorter(ListElement, ListElement) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     NullCheck
   static boolean isShorter(ListElement x, ListElement y) {
     ListElement xTail = x;
     ListElement yTail = y;
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index 91ac2ed..42f9a11 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -16,14 +16,14 @@
 
 public class Main {
 
-  // CHECK-START: int Main.div() licm (before)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.div() licm (before)
+  /// CHECK-DAG: Div loop:{{B\d+}}
 
-  // CHECK-START: int Main.div() licm (after)
-  // CHECK-NOT: Div ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.div() licm (after)
+  /// CHECK-NOT: Div loop:{{B\d+}}
 
-  // CHECK-START: int Main.div() licm (after)
-  // CHECK-DAG: Div ( loop_header:null )
+  /// CHECK-START: int Main.div() licm (after)
+  /// CHECK-DAG: Div loop:none
 
   public static int div() {
     int result = 0;
@@ -33,14 +33,14 @@
     return result;
   }
 
-  // CHECK-START: int Main.innerDiv() licm (before)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.innerDiv() licm (before)
+  /// CHECK-DAG: Div loop:{{B\d+}}
 
-  // CHECK-START: int Main.innerDiv() licm (after)
-  // CHECK-NOT: Div ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.innerDiv() licm (after)
+  /// CHECK-NOT: Div loop:{{B\d+}}
 
-  // CHECK-START: int Main.innerDiv() licm (after)
-  // CHECK-DAG: Div ( loop_header:null )
+  /// CHECK-START: int Main.innerDiv() licm (after)
+  /// CHECK-DAG: Div loop:none
 
   public static int innerDiv() {
     int result = 0;
@@ -52,11 +52,11 @@
     return result;
   }
 
-  // CHECK-START: int Main.innerDiv2() licm (before)
-  // CHECK-DAG: Mul ( loop_header:{{B4}} )
+  /// CHECK-START: int Main.innerDiv2() licm (before)
+  /// CHECK-DAG: Mul loop:B4
 
-  // CHECK-START: int Main.innerDiv2() licm (after)
-  // CHECK-DAG: Mul ( loop_header:{{B2}} )
+  /// CHECK-START: int Main.innerDiv2() licm (after)
+  /// CHECK-DAG: Mul loop:B2
 
   public static int innerDiv2() {
     int result = 0;
@@ -71,11 +71,11 @@
     return result;
   }
 
-  // CHECK-START: int Main.innerDiv3(int, int) licm (before)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.innerDiv3(int, int) licm (before)
+  /// CHECK-DAG: Div loop:{{B\d+}}
 
-  // CHECK-START: int Main.innerDiv3(int, int) licm (after)
-  // CHECK-DAG: Div ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.innerDiv3(int, int) licm (after)
+  /// CHECK-DAG: Div loop:{{B\d+}}
 
   public static int innerDiv3(int a, int b) {
     int result = 0;
@@ -87,17 +87,17 @@
     return result;
   }
 
-  // CHECK-START: int Main.arrayLength(int[]) licm (before)
-  // CHECK-DAG: [[NullCheck:l\d+]] NullCheck ( loop_header:{{B\d+}} )
-  // CHECK-DAG:                    ArrayLength [ [[NullCheck]] ] ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.arrayLength(int[]) licm (before)
+  /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:{{B\d+}}
+  /// CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:{{B\d+}}
 
-  // CHECK-START: int Main.arrayLength(int[]) licm (after)
-  // CHECK-NOT:                    NullCheck ( loop_header:{{B\d+}} )
-  // CHECK-NOT:                    ArrayLength ( loop_header:{{B\d+}} )
+  /// CHECK-START: int Main.arrayLength(int[]) licm (after)
+  /// CHECK-NOT:                    NullCheck loop:{{B\d+}}
+  /// CHECK-NOT:                    ArrayLength loop:{{B\d+}}
 
-  // CHECK-START: int Main.arrayLength(int[]) licm (after)
-  // CHECK-DAG: [[NullCheck:l\d+]] NullCheck ( loop_header:null )
-  // CHECK-DAG:                    ArrayLength [ [[NullCheck]] ] ( loop_header:null )
+  /// CHECK-START: int Main.arrayLength(int[]) licm (after)
+  /// CHECK-DAG: <<NullCheck:l\d+>> NullCheck loop:none
+  /// CHECK-DAG:                    ArrayLength [<<NullCheck>>] loop:none
 
   public static int arrayLength(int[] array) {
     int result = 0;
diff --git a/test/446-checker-inliner2/src/Main.java b/test/446-checker-inliner2/src/Main.java
index ecf071e..de00a09 100644
--- a/test/446-checker-inliner2/src/Main.java
+++ b/test/446-checker-inliner2/src/Main.java
@@ -16,16 +16,16 @@
 
 public class Main {
 
-  // CHECK-START: int Main.inlineInstanceCall(Main) inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.inlineInstanceCall(Main) inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
-  // CHECK-DAG:     [[Field:i\d+]]   InstanceFieldGet
-  // CHECK-DAG:                      Return [ [[Field]] ]
+  /// CHECK-START: int Main.inlineInstanceCall(Main) inliner (after)
+  /// CHECK-DAG:     <<Field:i\d+>>   InstanceFieldGet
+  /// CHECK-DAG:                      Return [<<Field>>]
 
   public static int inlineInstanceCall(Main m) {
     return m.foo();
@@ -37,16 +37,16 @@
 
   int field = 42;
 
-  // CHECK-START: int Main.inlineNestedCall() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.inlineNestedCall() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.inlineNestedCall() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineNestedCall() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineNestedCall() inliner (after)
-  // CHECK-DAG:     [[Const38:i\d+]] IntConstant 38
-  // CHECK-DAG:                      Return [ [[Const38]] ]
+  /// CHECK-START: int Main.inlineNestedCall() inliner (after)
+  /// CHECK-DAG:     <<Const38:i\d+>> IntConstant 38
+  /// CHECK-DAG:                      Return [<<Const38>>]
 
   public static int inlineNestedCall() {
     return nestedCall();
diff --git a/test/447-checker-inliner3/src/Main.java b/test/447-checker-inliner3/src/Main.java
index db4b236..e3fdffd 100644
--- a/test/447-checker-inliner3/src/Main.java
+++ b/test/447-checker-inliner3/src/Main.java
@@ -16,12 +16,12 @@
 
 public class Main {
 
-  // CHECK-START: int Main.inlineIfThenElse() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.inlineIfThenElse() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.inlineIfThenElse() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineIfThenElse() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
   public static int inlineIfThenElse() {
     return foo(true);
@@ -35,11 +35,11 @@
     }
   }
 
-  // CHECK-START: int Main.inlineInLoop() inliner (before)
-  // CHECK-DAG:     InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineInLoop() inliner (before)
+  /// CHECK-DAG:     InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineInLoop() inliner (after)
-  // CHECK-NOT:     InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineInLoop() inliner (after)
+  /// CHECK-NOT:     InvokeStaticOrDirect
 
   public static int inlineInLoop() {
     int result = 0;
@@ -49,11 +49,11 @@
     return result;
   }
 
-  // CHECK-START: int Main.inlineInLoopHeader() inliner (before)
-  // CHECK-DAG:     InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineInLoopHeader() inliner (before)
+  /// CHECK-DAG:     InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineInLoopHeader() inliner (after)
-  // CHECK-NOT:     InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineInLoopHeader() inliner (after)
+  /// CHECK-NOT:     InvokeStaticOrDirect
 
   public static int inlineInLoopHeader() {
     int result = 0;
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 7a45ce3..ed6fc1e 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -16,21 +16,21 @@
 
 public class Main {
 
-  // CHECK-START: int Main.sieve(int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: int Main.sieve(int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: int Main.sieve(int) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: int Main.sieve(int) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   static int sieve(int size) {
     int primeCount = 0;
@@ -47,25 +47,25 @@
   }
 
 
-  // CHECK-START: void Main.narrow(int[], int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.narrow(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.narrow(int[], int) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.narrow(int[], int) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   static void narrow(int[] array, int offset) {
     if (offset < 0) {
@@ -108,18 +108,18 @@
   }
 
 
-  // CHECK-START: void Main.constantIndexing1(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing1(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.constantIndexing1(int[]) BCE (after)
-  // CHECK-NOT: Deoptimize
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing1(int[]) BCE (after)
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static void constantIndexing1(int[] array) {
     array[5] = 1;
@@ -127,29 +127,29 @@
   }
 
 
-  // CHECK-START: void Main.constantIndexing2(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing2(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.constantIndexing2(int[]) BCE (after)
-  // CHECK: LessThanOrEqual
-  // CHECK: Deoptimize
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing2(int[]) BCE (after)
+  /// CHECK: LessThanOrEqual
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   static void constantIndexing2(int[] array) {
     array[1] = 1;
@@ -160,45 +160,45 @@
   }
 
 
-  // CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (after)
-  // CHECK: LessThanOrEqual
-  // CHECK: Deoptimize
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: LessThanOrEqual
-  // CHECK: Deoptimize
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (after)
+  /// CHECK: LessThanOrEqual
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: LessThanOrEqual
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static int[] constantIndexing3(int[] array1, int[] array2, boolean copy) {
     if (!copy) {
@@ -212,14 +212,14 @@
   }
 
 
-  // CHECK-START: void Main.constantIndexing4(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing4(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.constantIndexing4(int[]) BCE (after)
-  // CHECK-NOT: LessThanOrEqual
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing4(int[]) BCE (after)
+  /// CHECK-NOT: LessThanOrEqual
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   // There is only one array access. It's not beneficial
   // to create a compare with deoptimization instruction.
@@ -228,18 +228,18 @@
   }
 
 
-  // CHECK-START: void Main.constantIndexing5(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing5(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.constantIndexing5(int[]) BCE (after)
-  // CHECK-NOT: Deoptimize
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantIndexing5(int[]) BCE (after)
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   static void constantIndexing5(int[] array) {
     // We don't apply the deoptimization for very large constant index
@@ -249,37 +249,37 @@
     array[Integer.MAX_VALUE - 998] = 1;
   }
 
-  // CHECK-START: void Main.loopPattern1(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.loopPattern1(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.loopPattern1(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.loopPattern1(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static void loopPattern1(int[] array) {
     for (int i = 0; i < array.length; i++) {
@@ -316,33 +316,33 @@
   }
 
 
-  // CHECK-START: void Main.loopPattern2(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.loopPattern2(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.loopPattern2(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.loopPattern2(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static void loopPattern2(int[] array) {
     for (int i = array.length - 1; i >= 0; i--) {
@@ -372,13 +372,13 @@
   }
 
 
-  // CHECK-START: void Main.loopPattern3(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.loopPattern3(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.loopPattern3(int[]) BCE (after)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.loopPattern3(int[]) BCE (after)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   static void loopPattern3(int[] array) {
     java.util.Random random = new java.util.Random();
@@ -393,29 +393,29 @@
   }
 
 
-  // CHECK-START: void Main.constantNewArray() BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantNewArray() BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.constantNewArray() BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.constantNewArray() BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   static void constantNewArray() {
     int[] array = new int[10];
@@ -437,13 +437,13 @@
     return 1;
   }
 
-  // CHECK-START: void Main.circularBufferProducer() BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.circularBufferProducer() BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.circularBufferProducer() BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.circularBufferProducer() BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static void circularBufferProducer() {
     byte[] array = new byte[4096];
@@ -455,17 +455,17 @@
   }
 
 
-  // CHECK-START: void Main.pyramid1(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.pyramid1(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.pyramid1(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.pyramid1(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
   static void pyramid1(int[] array) {
@@ -476,17 +476,17 @@
   }
 
 
-  // CHECK-START: void Main.pyramid2(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.pyramid2(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.pyramid2(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.pyramid2(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
   static void pyramid2(int[] array) {
@@ -497,17 +497,17 @@
   }
 
 
-  // CHECK-START: void Main.pyramid3(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.pyramid3(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.pyramid3(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.pyramid3(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
   static void pyramid3(int[] array) {
@@ -518,17 +518,17 @@
   }
 
 
-  // CHECK-START: boolean Main.isPyramid(int[]) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: boolean Main.isPyramid(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: boolean Main.isPyramid(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: boolean Main.isPyramid(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
 
   static boolean isPyramid(int[] array) {
     int i = 0;
@@ -546,43 +546,43 @@
   }
 
 
-  // CHECK-START: void Main.bubbleSort(int[]) GVN (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.bubbleSort(int[]) GVN (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.bubbleSort(int[]) GVN (after)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: ArrayGet
-  // CHECK-NOT: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.bubbleSort(int[]) GVN (after)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: ArrayGet
+  /// CHECK-NOT: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.bubbleSort(int[]) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: ArrayGet
-  // CHECK-NOT: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.bubbleSort(int[]) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: ArrayGet
+  /// CHECK-NOT: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static void bubbleSort(int[] array) {
     for (int i = 0; i < array.length - 1; i++) {
@@ -610,28 +610,28 @@
 
   int sum;
 
-  // CHECK-START: void Main.foo1(int[], int, int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo1(int[], int, int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo1(int[], int, int) BCE (after)
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo1(int[], int, int) BCE (after)
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
 
   void foo1(int[] array, int start, int end) {
     // Three HDeoptimize will be added. One for
@@ -645,28 +645,28 @@
   }
 
 
-  // CHECK-START: void Main.foo2(int[], int, int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo2(int[], int, int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo2(int[], int, int) BCE (after)
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo2(int[], int, int) BCE (after)
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
 
   void foo2(int[] array, int start, int end) {
     // Three HDeoptimize will be added. One for
@@ -680,27 +680,27 @@
   }
 
 
-  // CHECK-START: void Main.foo3(int[], int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo3(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo3(int[], int) BCE (after)
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo3(int[], int) BCE (after)
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
 
   void foo3(int[] array, int end) {
     // Two HDeoptimize will be added. One for end < array.length,
@@ -713,27 +713,27 @@
   }
 
 
-  // CHECK-START: void Main.foo4(int[], int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo4(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo4(int[], int) BCE (after)
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo4(int[], int) BCE (after)
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
 
   void foo4(int[] array, int end) {
     // Two HDeoptimize will be added. One for end <= array.length,
@@ -746,35 +746,35 @@
   }
 
 
-  // CHECK-START: void Main.foo5(int[], int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo5(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo5(int[], int) BCE (after)
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo5(int[], int) BCE (after)
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
   //  array.length is defined before the loop header so no phi is needed.
-  // CHECK-NOT: Phi
-  // CHECK: Goto
+  /// CHECK-NOT: Phi
+  /// CHECK: Goto
 
   void foo5(int[] array, int end) {
     // Bounds check in this loop can be eliminated without deoptimization.
@@ -791,45 +791,45 @@
   }
 
 
-  // CHECK-START: void Main.foo6(int[], int, int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.foo6(int[], int, int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.foo6(int[], int, int) BCE (after)
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.foo6(int[], int, int) BCE (after)
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
-  // CHECK-NOT: Deoptimize
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
+  /// CHECK-NOT: Deoptimize
 
   void foo6(int[] array, int start, int end) {
     // Three HDeoptimize will be added. One for
@@ -842,28 +842,28 @@
   }
 
 
-  // CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (after)
-  // CHECK: Phi
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (after)
+  /// CHECK: Phi
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
 
   void foo7(int[] array, int start, int end, boolean lowEnd) {
     // Three HDeoptimize will be added. One for
@@ -882,32 +882,32 @@
   }
 
 
-  // CHECK-START: void Main.foo8(int[][], int, int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.foo8(int[][], int, int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.foo8(int[][], int, int) BCE (after)
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
-  // CHECK: Phi
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.foo8(int[][], int, int) BCE (after)
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
+  /// CHECK: Phi
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
   //  Added blocks for deoptimization.
-  // CHECK: If
-  // CHECK: Goto
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Goto
-  // CHECK: Phi
-  // CHECK: Goto
+  /// CHECK: If
+  /// CHECK: Goto
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Goto
+  /// CHECK: Phi
+  /// CHECK: Goto
 
   void foo8(int[][] matrix, int start, int end) {
     // Three HDeoptimize will be added for the outer loop.
@@ -924,21 +924,21 @@
   }
 
 
-  // CHECK-START: void Main.foo9(int[]) BCE (before)
-  // CHECK: NullCheck
-  // CHECK: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK-START: void Main.foo9(int[]) BCE (before)
+  /// CHECK: NullCheck
+  /// CHECK: BoundsCheck
+  /// CHECK: ArrayGet
 
-  // CHECK-START: void Main.foo9(int[]) BCE (after)
+  /// CHECK-START: void Main.foo9(int[]) BCE (after)
   //  The loop is guaranteed to be entered. No need to transform the
   //  loop for loop body entry test.
-  // CHECK: Deoptimize
-  // CHECK: Deoptimize
-  // CHECK-NOT: Deoptimize
-  // CHECK: Phi
-  // CHECK-NOT: NullCheck
-  // CHECK-NOT: BoundsCheck
-  // CHECK: ArrayGet
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: Phi
+  /// CHECK-NOT: NullCheck
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArrayGet
 
   void foo9(int[] array) {
     // Two HDeoptimize will be added. One for
@@ -949,14 +949,14 @@
   }
 
 
-  // CHECK-START: void Main.partialLooping(int[], int, int) BCE (before)
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.partialLooping(int[], int, int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
-  // CHECK-START: void Main.partialLooping(int[], int, int) BCE (after)
-  // CHECK-NOT: Deoptimize
-  // CHECK: BoundsCheck
-  // CHECK: ArraySet
+  /// CHECK-START: void Main.partialLooping(int[], int, int) BCE (after)
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   void partialLooping(int[] array, int start, int end) {
     // This loop doesn't cover the full range of [start, end) so
@@ -1102,8 +1102,8 @@
   }
 
   // Make sure this method is compiled with optimizing.
-  // CHECK-START: void Main.main(java.lang.String[]) register (after)
-  // CHECK: ParallelMove
+  /// CHECK-START: void Main.main(java.lang.String[]) register (after)
+  /// CHECK: ParallelMove
 
   public static void main(String[] args) {
     sieve(20);
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index 640aeb8..9070627 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -16,25 +16,25 @@
 
 
 interface Interface {
-  void f();
+  void $noinline$f();
 }
 
 class Super implements Interface {
-  public void f() {
+  public void $noinline$f() {
     throw new RuntimeException();
   }
 }
 
 class SubclassA extends Super {
-  public void f() {
+  public void $noinline$f() {
     throw new RuntimeException();
   }
 
-  public String h() {
+  public String $noinline$h() {
     throw new RuntimeException();
   }
 
-  void g() {
+  void $noinline$g() {
     throw new RuntimeException();
   }
 }
@@ -43,61 +43,61 @@
 }
 
 class SubclassB extends Super {
-  public void f() {
+  public void $noinline$f() {
     throw new RuntimeException();
   }
 
-  void g() {
+  void $noinline$g() {
     throw new RuntimeException();
   }
 }
 
 public class Main {
 
-  // CHECK-START: void Main.testSimpleRemove() instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testSimpleRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testSimpleRemove() instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testSimpleRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testSimpleRemove() {
     Super s = new SubclassA();
-    ((SubclassA)s).g();
+    ((SubclassA)s).$noinline$g();
   }
 
-  // CHECK-START: void Main.testSimpleKeep(Super) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testSimpleKeep(Super) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testSimpleKeep(Super) instruction_simplifier_after_types (after)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testSimpleKeep(Super) instruction_simplifier_after_types (after)
+  /// CHECK:         CheckCast
   public void testSimpleKeep(Super s) {
-    ((SubclassA)s).f();
+    ((SubclassA)s).$noinline$f();
   }
 
-  // CHECK-START: java.lang.String Main.testClassRemove() instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: java.lang.String Main.testClassRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: java.lang.String Main.testClassRemove() instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: java.lang.String Main.testClassRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public String testClassRemove() {
     Object s = SubclassA.class;
     return ((Class)s).getName();
   }
 
-  // CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier_after_types (after)
-  // CHECK:         CheckCast
+  /// CHECK-START: java.lang.String Main.testClassKeep() instruction_simplifier_after_types (after)
+  /// CHECK:         CheckCast
   public String testClassKeep() {
     Object s = SubclassA.class;
-    return ((SubclassA)s).h();
+    return ((SubclassA)s).$noinline$h();
   }
 
-  // CHECK-START: void Main.testIfRemove(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testIfRemove(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testIfRemove(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testIfRemove(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testIfRemove(int x) {
     Super s;
     if (x % 2 == 0) {
@@ -105,14 +105,14 @@
     } else {
       s = new SubclassC();
     }
-    ((SubclassA)s).g();
+    ((SubclassA)s).$noinline$g();
   }
 
-  // CHECK-START: void Main.testIfKeep(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testIfKeep(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testIfKeep(int) instruction_simplifier_after_types (after)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testIfKeep(int) instruction_simplifier_after_types (after)
+  /// CHECK:         CheckCast
   public void testIfKeep(int x) {
     Super s;
     if (x % 2 == 0) {
@@ -120,14 +120,14 @@
     } else {
       s = new SubclassB();
     }
-    ((SubclassA)s).g();
+    ((SubclassA)s).$noinline$g();
   }
 
-  // CHECK-START: void Main.testForRemove(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testForRemove(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testForRemove(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testForRemove(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testForRemove(int x) {
     Super s = new SubclassA();
     for (int i = 0 ; i < x; i++) {
@@ -135,14 +135,14 @@
         s = new SubclassC();
       }
     }
-    ((SubclassA)s).g();
+    ((SubclassA)s).$noinline$g();
   }
 
-  // CHECK-START: void Main.testForKeep(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testForKeep(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testForKeep(int) instruction_simplifier_after_types (after)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testForKeep(int) instruction_simplifier_after_types (after)
+  /// CHECK:         CheckCast
   public void testForKeep(int x) {
     Super s = new SubclassA();
     for (int i = 0 ; i < x; i++) {
@@ -150,14 +150,14 @@
         s = new SubclassC();
       }
     }
-    ((SubclassC)s).g();
+    ((SubclassC)s).$noinline$g();
   }
 
-  // CHECK-START: void Main.testPhiFromCall(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testPhiFromCall(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testPhiFromCall(int) instruction_simplifier_after_types (after)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testPhiFromCall(int) instruction_simplifier_after_types (after)
+  /// CHECK:         CheckCast
   public void testPhiFromCall(int i) {
     Object x;
     if (i % 2 == 0) {
@@ -165,61 +165,61 @@
     } else {
       x = newObject();  // this one will have an unknown type.
     }
-    ((SubclassC)x).g();
+    ((SubclassC)x).$noinline$g();
   }
 
-  // CHECK-START: void Main.testInstanceOf(java.lang.Object) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOf(java.lang.Object) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOf(java.lang.Object) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOf(java.lang.Object) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOf(Object o) {
     if (o instanceof SubclassC) {
-      ((SubclassC)o).g();
+      ((SubclassC)o).$noinline$g();
     }
     if (o instanceof SubclassB) {
-      ((SubclassB)o).g();
+      ((SubclassB)o).$noinline$g();
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfKeep(java.lang.Object) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfKeep(java.lang.Object) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfKeep(java.lang.Object) instruction_simplifier_after_types (after)
-  // CHECK:         CheckCast
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfKeep(java.lang.Object) instruction_simplifier_after_types (after)
+  /// CHECK:         CheckCast
+  /// CHECK:         CheckCast
   public void testInstanceOfKeep(Object o) {
     if (o instanceof SubclassC) {
-      ((SubclassB)o).g();
+      ((SubclassB)o).$noinline$g();
     }
     if (o instanceof SubclassB) {
-      ((SubclassA)o).g();
+      ((SubclassA)o).$noinline$g();
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfNested(java.lang.Object) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfNested(java.lang.Object) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfNested(java.lang.Object) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfNested(java.lang.Object) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfNested(Object o) {
     if (o instanceof SubclassC) {
       if (o instanceof SubclassB) {
-        ((SubclassB)o).g();
+        ((SubclassB)o).$noinline$g();
       } else {
-        ((SubclassC)o).g();
+        ((SubclassC)o).$noinline$g();
       }
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfWithPhi(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfWithPhi(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfWithPhi(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfWithPhi(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfWithPhi(int i) {
     Object o;
     if (i == 0) {
@@ -229,15 +229,15 @@
     }
 
     if (o instanceof SubclassB) {
-      ((SubclassB)o).g();
+      ((SubclassB)o).$noinline$g();
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfInFor(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfInFor(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfInFor(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfInFor(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfInFor(int n) {
     Object o = new SubclassA();
     for (int i = 0; i < n; i++) {
@@ -245,28 +245,28 @@
         o = new SubclassB();
       }
       if (o instanceof SubclassB) {
-        ((SubclassB)o).g();
+        ((SubclassB)o).$noinline$g();
       }
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfSubclass() instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfSubclass() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfSubclass() instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfSubclass() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfSubclass() {
     Object o = new SubclassA();
     if (o instanceof Super) {
-      ((SubclassA)o).g();
+      ((SubclassA)o).$noinline$g();
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfWithPhiSubclass(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfWithPhiSubclass(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfWithPhiSubclass(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfWithPhiSubclass(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfWithPhiSubclass(int i) {
     Object o;
     if (i == 0) {
@@ -276,15 +276,15 @@
     }
 
     if (o instanceof Super) {
-      ((SubclassA)o).g();
+      ((SubclassA)o).$noinline$g();
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfWithPhiTop(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfWithPhiTop(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfWithPhiTop(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfWithPhiTop(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfWithPhiTop(int i) {
     Object o;
     if (i == 0) {
@@ -294,20 +294,20 @@
     }
 
     if (o instanceof Super) {
-      ((Super)o).f();
+      ((Super)o).$noinline$f();
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfSubclassInFor(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfSubclassInFor(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfSubclassInFor(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfSubclassInFor(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfSubclassInFor(int n) {
     Object o = new SubclassA();
     for (int i = 0; i < n; i++) {
       if (o instanceof Super) {
-        ((SubclassA)o).g();
+        ((SubclassA)o).$noinline$g();
       }
       if (i / 2 == 0) {
         o = new SubclassC();
@@ -315,16 +315,16 @@
     }
   }
 
-  // CHECK-START: void Main.testInstanceOfTopInFor(int) instruction_simplifier_after_types (before)
-  // CHECK:         CheckCast
+  /// CHECK-START: void Main.testInstanceOfTopInFor(int) instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
 
-  // CHECK-START: void Main.testInstanceOfTopInFor(int) instruction_simplifier_after_types (after)
-  // CHECK-NOT:     CheckCast
+  /// CHECK-START: void Main.testInstanceOfTopInFor(int) instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
   public void testInstanceOfTopInFor(int n) {
     Object o = new SubclassA();
     for (int i = 0; i < n; i++) {
       if (o instanceof Super) {
-        ((Super)o).f();
+        ((Super)o).$noinline$f();
       }
       if (i / 2 == 0) {
         o = new Object();
@@ -340,6 +340,61 @@
     }
   }
 
+  public SubclassA a = new SubclassA();
+  public static SubclassA b = new SubclassA();
+
+  /// CHECK-START: void Main.testInstanceFieldGetSimpleRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+
+  /// CHECK-START: void Main.testInstanceFieldGetSimpleRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
+  public void testInstanceFieldGetSimpleRemove() {
+    Main m = new Main();
+    Super a = m.a;
+    ((SubclassA)a).$noinline$g();
+  }
+
+  /// CHECK-START: void Main.testStaticFieldGetSimpleRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+
+  /// CHECK-START: void Main.testStaticFieldGetSimpleRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
+  public void testStaticFieldGetSimpleRemove() {
+    Super b = Main.b;
+    ((SubclassA)b).$noinline$g();
+  }
+
+  public SubclassA $noinline$getSubclass() { throw new RuntimeException(); }
+
+  /// CHECK-START: void Main.testArraySimpleRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+
+  /// CHECK-START: void Main.testArraySimpleRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
+  public void testArraySimpleRemove() {
+    Super[] b = new SubclassA[10];
+    SubclassA[] c = (SubclassA[])b;
+  }
+
+  /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+
+  /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
+  public void testInvokeSimpleRemove() {
+    Super b = $noinline$getSubclass();
+    ((SubclassA)b).$noinline$g();
+  }
+  /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier_after_types (before)
+  /// CHECK:         CheckCast
+
+  /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier_after_types (after)
+  /// CHECK-NOT:     CheckCast
+  public void testArrayGetSimpleRemove() {
+    Super[] a = new SubclassA[10];
+    ((SubclassA)a[0]).$noinline$g();
+  }
+
   public static void main(String[] args) {
   }
 }
diff --git a/test/451-spill-splot/src/Main.java b/test/451-spill-splot/src/Main.java
index f631ebd..b2f39f3 100644
--- a/test/451-spill-splot/src/Main.java
+++ b/test/451-spill-splot/src/Main.java
@@ -48,37 +48,37 @@
     for (int count = 0; count < 2; count++) {
       System.out.println(aa + bb + cc + dd + ee + ff + gg + hh + ii + jj + kk + ll + mm + nn);
       System.out.println(a + b + c + d + e + f + g + h + i + j);
-      a = computeDouble();
-      b = computeDouble();
-      c = computeDouble();
-      d = computeDouble();
-      e = computeDouble();
-      f = computeDouble();
-      g = computeDouble();
-      h = computeDouble();
-      i = computeDouble();
-      j = computeDouble();
+      a = $noinline$computeDouble();
+      b = $noinline$computeDouble();
+      c = $noinline$computeDouble();
+      d = $noinline$computeDouble();
+      e = $noinline$computeDouble();
+      f = $noinline$computeDouble();
+      g = $noinline$computeDouble();
+      h = $noinline$computeDouble();
+      i = $noinline$computeDouble();
+      j = $noinline$computeDouble();
       System.out.println(a + b + c + d + e + f + g + h + i + j);
-      aa = computeFloat();
-      bb = computeFloat();
-      cc = computeFloat();
-      dd = computeFloat();
-      ee = computeFloat();
-      ff = computeFloat();
-      gg = computeFloat();
-      hh = computeFloat();
-      ii = computeFloat();
-      jj = computeFloat();
-      kk = computeFloat();
-      ll = computeFloat();
-      mm = computeFloat();
-      nn = computeFloat();
+      aa = $noinline$computeFloat();
+      bb = $noinline$computeFloat();
+      cc = $noinline$computeFloat();
+      dd = $noinline$computeFloat();
+      ee = $noinline$computeFloat();
+      ff = $noinline$computeFloat();
+      gg = $noinline$computeFloat();
+      hh = $noinline$computeFloat();
+      ii = $noinline$computeFloat();
+      jj = $noinline$computeFloat();
+      kk = $noinline$computeFloat();
+      ll = $noinline$computeFloat();
+      mm = $noinline$computeFloat();
+      nn = $noinline$computeFloat();
     }
   }
 
   static boolean doThrow = false;
 
-  public static double computeDouble() {
+  public static double $noinline$computeDouble() {
     if (doThrow) {
       // Try defeating inlining.
       throw new Error();
@@ -86,7 +86,7 @@
     return 2.0;
   }
 
-  public static float computeFloat() {
+  public static float $noinline$computeFloat() {
     if (doThrow) {
       // Try defeating inlining.
       throw new Error();
diff --git a/test/455-checker-gvn/src/Main.java b/test/455-checker-gvn/src/Main.java
index e94fc46..9824f27 100644
--- a/test/455-checker-gvn/src/Main.java
+++ b/test/455-checker-gvn/src/Main.java
@@ -19,15 +19,15 @@
     System.out.println(foo(3, 4));
   }
 
-  // CHECK-START: int Main.foo(int, int) GVN (before)
-  // CHECK: Add
-  // CHECK: Add
-  // CHECK: Add
+  /// CHECK-START: int Main.foo(int, int) GVN (before)
+  /// CHECK: Add
+  /// CHECK: Add
+  /// CHECK: Add
 
-  // CHECK-START: int Main.foo(int, int) GVN (after)
-  // CHECK: Add
-  // CHECK: Add
-  // CHECK-NOT: Add
+  /// CHECK-START: int Main.foo(int, int) GVN (after)
+  /// CHECK: Add
+  /// CHECK: Add
+  /// CHECK-NOT: Add
 
   public static int foo(int x, int y) {
     int sum1 = x + y;
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index efb7b83..aa4dda1 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -50,296 +50,296 @@
    * Tiny programs exercising optimizations of arithmetic identities.
    */
 
-  // CHECK-START: long Main.Add0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]  LongConstant 0
-  // CHECK-DAG:     [[Add:j\d+]]     Add [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  /// CHECK-START: long Main.Add0(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>  LongConstant 0
+  /// CHECK-DAG:     <<Add:j\d+>>     Add [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                      Return [<<Add>>]
 
-  // CHECK-START: long Main.Add0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  /// CHECK-START: long Main.Add0(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  /// CHECK-DAG:                      Return [<<Arg>>]
 
-  // CHECK-START: long Main.Add0(long) instruction_simplifier (after)
-  // CHECK-NOT:                        Add
+  /// CHECK-START: long Main.Add0(long) instruction_simplifier (after)
+  /// CHECK-NOT:                        Add
 
   public static long Add0(long arg) {
     return 0 + arg;
   }
 
-  // CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[ConstF:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[And:i\d+]]     And [ [[Arg]] [[ConstF]] ]
-  // CHECK-DAG:                      Return [ [[And]] ]
+  /// CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<ConstF:i\d+>>  IntConstant -1
+  /// CHECK-DAG:     <<And:i\d+>>     And [<<Arg>>,<<ConstF>>]
+  /// CHECK-DAG:                      Return [<<And>>]
 
-  // CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  /// CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  /// CHECK-DAG:                      Return [<<Arg>>]
 
-  // CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
-  // CHECK-NOT:                      And
+  /// CHECK-START: int Main.AndAllOnes(int) instruction_simplifier (after)
+  /// CHECK-NOT:                      And
 
   public static int AndAllOnes(int arg) {
     return arg & -1;
   }
 
-  // CHECK-START: long Main.Div1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
-  // CHECK-DAG:     [[Div:j\d+]]     Div [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                      Return [ [[Div]] ]
+  /// CHECK-START: long Main.Div1(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Const1:j\d+>>  LongConstant 1
+  /// CHECK-DAG:     <<Div:j\d+>>     Div [<<Arg>>,<<Const1>>]
+  /// CHECK-DAG:                      Return [<<Div>>]
 
-  // CHECK-START: long Main.Div1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  /// CHECK-START: long Main.Div1(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  /// CHECK-DAG:                      Return [<<Arg>>]
 
-  // CHECK-START: long Main.Div1(long) instruction_simplifier (after)
-  // CHECK-NOT:                      Div
+  /// CHECK-START: long Main.Div1(long) instruction_simplifier (after)
+  /// CHECK-NOT:                      Div
 
   public static long Div1(long arg) {
     return arg / 1;
   }
 
-  // CHECK-START: int Main.DivN1(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstN1:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[Div:i\d+]]      Div [ [[Arg]] [[ConstN1]] ]
-  // CHECK-DAG:                       Return [ [[Div]] ]
+  /// CHECK-START: int Main.DivN1(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstN1:i\d+>>  IntConstant -1
+  /// CHECK-DAG:     <<Div:i\d+>>      Div [<<Arg>>,<<ConstN1>>]
+  /// CHECK-DAG:                       Return [<<Div>>]
 
-  // CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
-  // CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Div
+  /// CHECK-START: int Main.DivN1(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Div
 
   public static int DivN1(int arg) {
     return arg / -1;
   }
 
-  // CHECK-START: long Main.Mul1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Const1:j\d+]]  LongConstant 1
-  // CHECK-DAG:     [[Mul:j\d+]]     Mul [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                      Return [ [[Mul]] ]
+  /// CHECK-START: long Main.Mul1(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Const1:j\d+>>  LongConstant 1
+  /// CHECK-DAG:     <<Mul:j\d+>>     Mul [<<Arg>>,<<Const1>>]
+  /// CHECK-DAG:                      Return [<<Mul>>]
 
-  // CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  /// CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>     ParameterValue
+  /// CHECK-DAG:                      Return [<<Arg>>]
 
-  // CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
-  // CHECK-NOT:                       Mul
+  /// CHECK-START: long Main.Mul1(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Mul
 
   public static long Mul1(long arg) {
     return arg * 1;
   }
 
-  // CHECK-START: int Main.MulN1(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstN1:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[Mul:i\d+]]      Mul [ [[Arg]] [[ConstN1]] ]
-  // CHECK-DAG:                       Return [ [[Mul]] ]
+  /// CHECK-START: int Main.MulN1(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstN1:i\d+>>  IntConstant -1
+  /// CHECK-DAG:     <<Mul:i\d+>>      Mul [<<Arg>>,<<ConstN1>>]
+  /// CHECK-DAG:                       Return [<<Mul>>]
 
-  // CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
-  // CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Mul
+  /// CHECK-START: int Main.MulN1(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Mul
 
   public static int MulN1(int arg) {
     return arg * -1;
   }
 
-  // CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:     [[Const128:j\d+]]  LongConstant 128
-  // CHECK-DAG:     [[Mul:j\d+]]       Mul [ [[Arg]] [[Const128]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  /// CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  /// CHECK-DAG:     <<Const128:j\d+>>  LongConstant 128
+  /// CHECK-DAG:     <<Mul:j\d+>>       Mul [<<Arg>>,<<Const128>>]
+  /// CHECK-DAG:                        Return [<<Mul>>]
 
-  // CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:     [[Const7:i\d+]]    IntConstant 7
-  // CHECK-DAG:     [[Shl:j\d+]]       Shl [ [[Arg]] [[Const7]] ]
-  // CHECK-DAG:                        Return [ [[Shl]] ]
+  /// CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  /// CHECK-DAG:     <<Const7:i\d+>>    IntConstant 7
+  /// CHECK-DAG:     <<Shl:j\d+>>       Shl [<<Arg>>,<<Const7>>]
+  /// CHECK-DAG:                        Return [<<Shl>>]
 
-  // CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
-  // CHECK-NOT:                        Mul
+  /// CHECK-START: long Main.MulPowerOfTwo128(long) instruction_simplifier (after)
+  /// CHECK-NOT:                        Mul
 
   public static long MulPowerOfTwo128(long arg) {
     return arg * 128;
   }
 
-  // CHECK-START: int Main.Or0(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.Or0(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.Or0(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: int Main.Or0(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: int Main.Or0(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Or
+  /// CHECK-START: int Main.Or0(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Or
 
   public static int Or0(int arg) {
     return arg | 0;
   }
 
-  // CHECK-START: long Main.OrSame(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:     [[Or:j\d+]]        Or [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                        Return [ [[Or]] ]
+  /// CHECK-START: long Main.OrSame(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  /// CHECK-DAG:     <<Or:j\d+>>        Or [<<Arg>>,<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Or>>]
 
-  // CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]       ParameterValue
-  // CHECK-DAG:                        Return [ [[Arg]] ]
+  /// CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>       ParameterValue
+  /// CHECK-DAG:                        Return [<<Arg>>]
 
-  // CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
-  // CHECK-NOT:                        Or
+  /// CHECK-START: long Main.OrSame(long) instruction_simplifier (after)
+  /// CHECK-NOT:                        Or
 
   public static long OrSame(long arg) {
     return arg | arg;
   }
 
-  // CHECK-START: int Main.Shl0(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Shl:i\d+]]      Shl [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Shl]] ]
+  /// CHECK-START: int Main.Shl0(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Shl>>]
 
-  // CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Shl
+  /// CHECK-START: int Main.Shl0(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Shl
 
   public static int Shl0(int arg) {
     return arg << 0;
   }
 
-  // CHECK-START: int Main.Shl1(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Shl:i\d+]]      Shl [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       Return [ [[Shl]] ]
+  /// CHECK-START: int Main.Shl1(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Shl:i\d+>>      Shl [<<Arg>>,<<Const1>>]
+  /// CHECK-DAG:                       Return [<<Shl>>]
 
-  // CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  /// CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Arg>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Add>>]
 
-  // CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Shl
+  /// CHECK-START: int Main.Shl1(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Shl
 
   public static int Shl1(int arg) {
     return arg << 1;
   }
 
-  // CHECK-START: long Main.Shr0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Shr:j\d+]]      Shr [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Shr]] ]
+  /// CHECK-START: long Main.Shr0(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Shr:j\d+>>      Shr [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Shr>>]
 
-  // CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
-  // CHECK-NOT:                       Shr
+  /// CHECK-START: long Main.Shr0(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Shr
 
   public static long Shr0(long arg) {
     return arg >> 0;
   }
 
-  // CHECK-START: long Main.Sub0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: long Main.Sub0(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
-  // CHECK-NOT:                       Sub
+  /// CHECK-START: long Main.Sub0(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Sub
 
   public static long Sub0(long arg) {
     return arg - 0;
   }
 
-  // CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
-  // CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Sub
+  /// CHECK-START: int Main.SubAliasNeg(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Sub
 
   public static int SubAliasNeg(int arg) {
     return 0 - arg;
   }
 
-  // CHECK-START: long Main.UShr0(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[UShr:j\d+]]     UShr [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[UShr]] ]
+  /// CHECK-START: long Main.UShr0(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<UShr:j\d+>>     UShr [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<UShr>>]
 
-  // CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
-  // CHECK-NOT:                       UShr
+  /// CHECK-START: long Main.UShr0(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       UShr
 
   public static long UShr0(long arg) {
     return arg >>> 0;
   }
 
-  // CHECK-START: int Main.Xor0(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Xor:i\d+]]      Xor [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Xor]] ]
+  /// CHECK-START: int Main.Xor0(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Xor:i\d+>>      Xor [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Xor>>]
 
-  // CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Xor
+  /// CHECK-START: int Main.Xor0(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Xor
 
   public static int Xor0(int arg) {
     return arg ^ 0;
   }
 
-  // CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF:i\d+]]   IntConstant -1
-  // CHECK-DAG:     [[Xor:i\d+]]      Xor [ [[Arg]] [[ConstF]] ]
-  // CHECK-DAG:                       Return [ [[Xor]] ]
+  /// CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstF:i\d+>>   IntConstant -1
+  /// CHECK-DAG:     <<Xor:i\d+>>      Xor [<<Arg>>,<<ConstF>>]
+  /// CHECK-DAG:                       Return [<<Xor>>]
 
-  // CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Not:i\d+]]      Not [ [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Not]] ]
+  /// CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Not:i\d+>>      Not [<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Not>>]
 
-  // CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Xor
+  /// CHECK-START: int Main.XorAllOnes(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Xor
 
   public static int XorAllOnes(int arg) {
     return arg ^ -1;
@@ -352,21 +352,21 @@
    * `InstructionSimplifierVisitor::TryMoveNegOnInputsAfterBinop`.
    */
 
-  // CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  /// CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:                       Return [<<Add>>]
 
-  // CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-NOT:                       Neg
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Add]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.AddNegs1(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-NOT:                       Neg
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Arg1>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Add>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
   public static int AddNegs1(int arg1, int arg2) {
     return -arg1 + -arg2;
@@ -383,35 +383,35 @@
    * increasing the register pressure by creating or extending live ranges.
    */
 
-  // CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Add2:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  /// CHECK-DAG:     <<Add1:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:     <<Add2:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Add1>>,<<Add2>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Add2:i\d+]]     Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-NOT:                       Neg
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.AddNegs2(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  /// CHECK-DAG:     <<Add1:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:     <<Add2:i\d+>>     Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-NOT:                       Neg
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Add1>>,<<Add2>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.AddNegs2(int, int) GVN (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Add]] [[Add]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.AddNegs2(int, int) GVN (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Arg2>>]
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Add>>,<<Add>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
   public static int AddNegs2(int arg1, int arg2) {
     int temp1 = -arg1;
@@ -427,30 +427,30 @@
    * the loop.
    */
 
-  // CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (before)
-  // -------------- Arguments and initial negation operations.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:j\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:j\d+]]     Neg [ [[Arg2]] ]
-  // CHECK:                           Goto
-  // -------------- Loop
-  // CHECK:                           SuspendCheck
-  // CHECK:         [[Add:j\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK:                           Goto
+  /// CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (before)
+  //  -------------- Arguments and initial negation operations.
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg1:j\d+>>     Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Neg2:j\d+>>     Neg [<<Arg2>>]
+  /// CHECK:                           Goto
+  //  -------------- Loop
+  /// CHECK:                           SuspendCheck
+  /// CHECK:         <<Add:j\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK:                           Goto
 
-  // CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (after)
-  // -------------- Arguments and initial negation operations.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg1:j\d+]]     Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Neg2:j\d+]]     Neg [ [[Arg2]] ]
-  // CHECK:                           Goto
-  // -------------- Loop
-  // CHECK:                           SuspendCheck
-  // CHECK:         [[Add:j\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-NOT:                       Neg
-  // CHECK:                           Goto
+  /// CHECK-START: long Main.AddNegs3(long, long) instruction_simplifier (after)
+  //  -------------- Arguments and initial negation operations.
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg1:j\d+>>     Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Neg2:j\d+>>     Neg [<<Arg2>>]
+  /// CHECK:                           Goto
+  //  -------------- Loop
+  /// CHECK:                           SuspendCheck
+  /// CHECK:         <<Add:j\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-NOT:                       Neg
+  /// CHECK:                           Goto
 
   public static long AddNegs3(long arg1, long arg2) {
     long res = 0;
@@ -468,22 +468,22 @@
    * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitAdd`.
    */
 
-  // CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Add:j\d+]]      Add [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  /// CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Add:j\d+>>      Add [<<Neg>>,<<Arg2>>]
+  /// CHECK-DAG:                       Return [<<Add>>]
 
-  // CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Arg2]] [[Arg1]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Arg2>>,<<Arg1>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
-  // CHECK-NOT:                       Neg
-  // CHECK-NOT:                       Add
+  /// CHECK-START: long Main.AddNeg1(long, long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Neg
+  /// CHECK-NOT:                       Add
 
   public static long AddNeg1(long arg1, long arg2) {
     return -arg1 + arg2;
@@ -498,26 +498,26 @@
    * increasing the register pressure by creating or extending live ranges.
    */
 
-  // CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Add2:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Res:j\d+]]      Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Res]] ]
+  /// CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg2>>]
+  /// CHECK-DAG:     <<Add1:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  /// CHECK-DAG:     <<Add2:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  /// CHECK-DAG:     <<Res:j\d+>>      Or [<<Add1>>,<<Add2>>]
+  /// CHECK-DAG:                       Return [<<Res>>]
 
-  // CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg2]] ]
-  // CHECK-DAG:     [[Add1:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Add2:j\d+]]     Add [ [[Arg1]] [[Neg]] ]
-  // CHECK-DAG:     [[Res:j\d+]]      Or [ [[Add1]] [[Add2]] ]
-  // CHECK-DAG:                       Return [ [[Res]] ]
+  /// CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg2>>]
+  /// CHECK-DAG:     <<Add1:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  /// CHECK-DAG:     <<Add2:j\d+>>     Add [<<Arg1>>,<<Neg>>]
+  /// CHECK-DAG:     <<Res:j\d+>>      Or [<<Add1>>,<<Add2>>]
+  /// CHECK-DAG:                       Return [<<Res>>]
 
-  // CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
-  // CHECK-NOT:                       Sub
+  /// CHECK-START: long Main.AddNeg2(long, long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Sub
 
   public static long AddNeg2(long arg1, long arg2) {
     long temp = -arg2;
@@ -529,18 +529,18 @@
    * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitNeg`.
    */
 
-  // CHECK-START: long Main.NegNeg1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg1:j\d+]]     Neg [ [[Arg]] ]
-  // CHECK-DAG:     [[Neg2:j\d+]]     Neg [ [[Neg1]] ]
-  // CHECK-DAG:                       Return [ [[Neg2]] ]
+  /// CHECK-START: long Main.NegNeg1(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Neg1:j\d+>>     Neg [<<Arg>>]
+  /// CHECK-DAG:     <<Neg2:j\d+>>     Neg [<<Neg1>>]
+  /// CHECK-DAG:                       Return [<<Neg2>>]
 
-  // CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
-  // CHECK-NOT:                       Neg
+  /// CHECK-START: long Main.NegNeg1(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Neg
 
   public static long NegNeg1(long arg) {
     return -(-arg);
@@ -553,27 +553,27 @@
    * and in `InstructionSimplifierVisitor::VisitAdd`.
    */
 
-  // CHECK-START: int Main.NegNeg2(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Arg]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Neg1]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  /// CHECK-START: int Main.NegNeg2(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Arg>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Neg1>>]
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:                       Return [<<Add>>]
 
-  // CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Neg
-  // CHECK-NOT:                       Add
+  /// CHECK-START: int Main.NegNeg2(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Neg
+  /// CHECK-NOT:                       Add
 
-  // CHECK-START: int Main.NegNeg2(int) constant_folding_after_inlining (after)
-  // CHECK:         [[Const0:i\d+]]   IntConstant 0
-  // CHECK-NOT:                       Neg
-  // CHECK-NOT:                       Add
-  // CHECK:                           Return [ [[Const0]] ]
+  /// CHECK-START: int Main.NegNeg2(int) constant_folding_after_inlining (after)
+  /// CHECK:         <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-NOT:                       Neg
+  /// CHECK-NOT:                       Add
+  /// CHECK:                           Return [<<Const0>>]
 
   public static int NegNeg2(int arg) {
     int temp = -arg;
@@ -587,20 +587,20 @@
    * and in `InstructionSimplifierVisitor::VisitSub`.
    */
 
-  // CHECK-START: long Main.NegNeg3(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:j\d+]]   LongConstant 0
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg]] ]
-  // CHECK-DAG:     [[Sub:j\d+]]      Sub [ [[Const0]] [[Neg]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: long Main.NegNeg3(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:j\d+>>   LongConstant 0
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg>>]
+  /// CHECK-DAG:     <<Sub:j\d+>>      Sub [<<Const0>>,<<Neg>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
-  // CHECK-NOT:                       Neg
-  // CHECK-NOT:                       Sub
+  /// CHECK-START: long Main.NegNeg3(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Neg
+  /// CHECK-NOT:                       Sub
 
   public static long NegNeg3(long arg) {
     return 0 - -arg;
@@ -612,21 +612,21 @@
    * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitNeg`.
    */
 
-  // CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Sub]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg1>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Sub>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
-  // CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg2]] [[Arg1]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg2>>,<<Arg1>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
-  // CHECK-NOT:                       Neg
+  /// CHECK-START: int Main.NegSub1(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Neg
 
   public static int NegSub1(int arg1, int arg2) {
     return -(arg1 - arg2);
@@ -642,23 +642,23 @@
    * increasing the register pressure by creating or extending live ranges.
    */
 
-  // CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg1>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Sub>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Sub>>]
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg1:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Neg2:i\d+]]     Neg [ [[Sub]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Neg1]] [[Neg2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.NegSub2(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Arg1>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Neg1:i\d+>>     Neg [<<Sub>>]
+  /// CHECK-DAG:     <<Neg2:i\d+>>     Neg [<<Sub>>]
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Neg1>>,<<Neg2>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
   public static int NegSub2(int arg1, int arg2) {
     int temp = arg1 - arg2;
@@ -670,40 +670,40 @@
    * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitNot`.
    */
 
-  // CHECK-START: long Main.NotNot1(long) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF1:j\d+]]  LongConstant -1
-  // CHECK-DAG:     [[Xor1:j\d+]]     Xor [ [[Arg]] [[ConstF1]] ]
-  // CHECK-DAG:     [[Xor2:j\d+]]     Xor [ [[Xor1]] [[ConstF1]] ]
-  // CHECK-DAG:                       Return [ [[Xor2]] ]
+  /// CHECK-START: long Main.NotNot1(long) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstF1:j\d+>>  LongConstant -1
+  /// CHECK-DAG:     <<Xor1:j\d+>>     Xor [<<Arg>>,<<ConstF1>>]
+  /// CHECK-DAG:     <<Xor2:j\d+>>     Xor [<<Xor1>>,<<ConstF1>>]
+  /// CHECK-DAG:                       Return [<<Xor2>>]
 
-  // CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:j\d+]]      ParameterValue
-  // CHECK-DAG:                       Return [ [[Arg]] ]
+  /// CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:                       Return [<<Arg>>]
 
-  // CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
-  // CHECK-NOT:                       Xor
+  /// CHECK-START: long Main.NotNot1(long) instruction_simplifier (after)
+  /// CHECK-NOT:                       Xor
 
   public static long NotNot1(long arg) {
     return ~~arg;
   }
 
-  // CHECK-START: int Main.NotNot2(int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[ConstF1:i\d+]]  IntConstant -1
-  // CHECK-DAG:     [[Xor1:i\d+]]     Xor [ [[Arg]] [[ConstF1]] ]
-  // CHECK-DAG:     [[Xor2:i\d+]]     Xor [ [[Xor1]] [[ConstF1]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Xor1]] [[Xor2]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  /// CHECK-START: int Main.NotNot2(int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstF1:i\d+>>  IntConstant -1
+  /// CHECK-DAG:     <<Xor1:i\d+>>     Xor [<<Arg>>,<<ConstF1>>]
+  /// CHECK-DAG:     <<Xor2:i\d+>>     Xor [<<Xor1>>,<<ConstF1>>]
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Xor1>>,<<Xor2>>]
+  /// CHECK-DAG:                       Return [<<Add>>]
 
-  // CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:i\d+]]      ParameterValue
-  // CHECK-DAG:     [[Not:i\d+]]      Not [ [[Arg]] ]
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Not]] [[Arg]] ]
-  // CHECK-DAG:                       Return [ [[Add]] ]
+  /// CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Not:i\d+>>      Not [<<Arg>>]
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Not>>,<<Arg>>]
+  /// CHECK-DAG:                       Return [<<Add>>]
 
-  // CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
-  // CHECK-NOT:                       Xor
+  /// CHECK-START: int Main.NotNot2(int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Xor
 
   public static int NotNot2(int arg) {
     int temp = ~arg;
@@ -715,22 +715,22 @@
    * The transformation tested is implemented in `InstructionSimplifierVisitor::VisitSub`.
    */
 
-  // CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]      Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:                       Return [ [[Sub]] ]
+  /// CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Sub:i\d+>>      Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK-DAG:                       Return [<<Sub>>]
 
-  // CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Add:i\d+]]      Add [ [[Arg1]] [[Arg2]] ]
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Add]] ]
-  // CHECK-DAG:                       Return [ [[Neg]] ]
+  /// CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Add:i\d+>>      Add [<<Arg1>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Add>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
 
-  // CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
-  // CHECK-NOT:                       Sub
+  /// CHECK-START: int Main.SubNeg1(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Sub
 
   public static int SubNeg1(int arg1, int arg2) {
     return -arg1 - arg2;
@@ -746,26 +746,26 @@
    * increasing the register pressure by creating or extending live ranges.
    */
 
-  // CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Sub1:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Sub2:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Sub1]] [[Sub2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Sub1:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Sub2:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Sub1>>,<<Sub2>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg1:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:i\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:i\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:     [[Sub1:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Sub2:i\d+]]     Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-DAG:     [[Or:i\d+]]       Or [ [[Sub1]] [[Sub2]] ]
-  // CHECK-DAG:                       Return [ [[Or]] ]
+  /// CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg1:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:i\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:i\d+>>      Neg [<<Arg1>>]
+  /// CHECK-DAG:     <<Sub1:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Sub2:i\d+>>     Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK-DAG:     <<Or:i\d+>>       Or [<<Sub1>>,<<Sub2>>]
+  /// CHECK-DAG:                       Return [<<Or>>]
 
-  // CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
-  // CHECK-NOT:                       Add
+  /// CHECK-START: int Main.SubNeg2(int, int) instruction_simplifier (after)
+  /// CHECK-NOT:                       Add
 
   public static int SubNeg2(int arg1, int arg2) {
     int temp = -arg1;
@@ -779,28 +779,28 @@
    * the loop.
    */
 
-  // CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (before)
-  // -------------- Arguments and initial negation operation.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg1]] ]
-  // CHECK:                           Goto
-  // -------------- Loop
-  // CHECK:                           SuspendCheck
-  // CHECK:         [[Sub:j\d+]]      Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK:                           Goto
+  /// CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (before)
+  //  -------------- Arguments and initial negation operation.
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg1>>]
+  /// CHECK:                           Goto
+  //  -------------- Loop
+  /// CHECK:                           SuspendCheck
+  /// CHECK:         <<Sub:j\d+>>      Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK:                           Goto
 
-  // CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (after)
-  // -------------- Arguments and initial negation operation.
-  // CHECK-DAG:     [[Arg1:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Arg2:j\d+]]     ParameterValue
-  // CHECK-DAG:     [[Neg:j\d+]]      Neg [ [[Arg1]] ]
-  // CHECK-DAG:                       Goto
-  // -------------- Loop
-  // CHECK:                           SuspendCheck
-  // CHECK:         [[Sub:j\d+]]      Sub [ [[Neg]] [[Arg2]] ]
-  // CHECK-NOT:                       Neg
-  // CHECK:                           Goto
+  /// CHECK-START: long Main.SubNeg3(long, long) instruction_simplifier (after)
+  //  -------------- Arguments and initial negation operation.
+  /// CHECK-DAG:     <<Arg1:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Arg2:j\d+>>     ParameterValue
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Arg1>>]
+  /// CHECK-DAG:                       Goto
+  //  -------------- Loop
+  /// CHECK:                           SuspendCheck
+  /// CHECK:         <<Sub:j\d+>>      Sub [<<Neg>>,<<Arg2>>]
+  /// CHECK-NOT:                       Neg
+  /// CHECK:                           Goto
 
   public static long SubNeg3(long arg1, long arg2) {
     long res = 0;
@@ -811,142 +811,172 @@
     return res;
   }
 
-  // CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Arg>>,<<Const1>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  /// CHECK-START: int Main.EqualTrueRhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:                       If [<<Arg>>]
 
   public static int EqualTrueRhs(boolean arg) {
     return (arg != true) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Const1]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Const1>>,<<Arg>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  /// CHECK-START: int Main.EqualTrueLhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:                       If [<<Arg>>]
 
   public static int EqualTrueLhs(boolean arg) {
     return (true != arg) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  /// CHECK-START: int Main.EqualFalseRhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  /// CHECK-DAG:                       If [<<NotArg>>]
 
   public static int EqualFalseRhs(boolean arg) {
     return (arg != false) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     Equal [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Cond:z\d+>>     Equal [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  /// CHECK-START: int Main.EqualFalseLhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  /// CHECK-DAG:                       If [<<NotArg>>]
 
   public static int EqualFalseLhs(boolean arg) {
     return (false != arg) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Arg]] [[Const1]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Arg>>,<<Const1>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  /// CHECK-START: int Main.NotEqualTrueRhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  /// CHECK-DAG:                       If [<<NotArg>>]
 
   public static int NotEqualTrueRhs(boolean arg) {
     return (arg == true) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Const1]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Const1>>,<<Arg>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]   BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                       If [ [[NotArg]] ]
+  /// CHECK-START: int Main.NotEqualTrueLhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<NotArg:z\d+>>   BooleanNot [<<Arg>>]
+  /// CHECK-DAG:                       If [<<NotArg>>]
 
   public static int NotEqualTrueLhs(boolean arg) {
     return (true == arg) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Arg]] [[Const0]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Arg>>,<<Const0>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  /// CHECK-START: int Main.NotEqualFalseRhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:                       If [<<Arg>>]
 
   public static int NotEqualFalseRhs(boolean arg) {
     return (arg == false) ? 3 : 5;
   }
 
-  // CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (before)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Cond:z\d+]]     NotEqual [ [[Const0]] [[Arg]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
+  /// CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<Const0>>,<<Arg>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
 
-  // CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (after)
-  // CHECK-DAG:     [[Arg:z\d+]]      ParameterValue
-  // CHECK-DAG:                       If [ [[Arg]] ]
+  /// CHECK-START: int Main.NotEqualFalseLhs(boolean) instruction_simplifier (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:                       If [<<Arg>>]
 
   public static int NotEqualFalseLhs(boolean arg) {
     return (false == arg) ? 3 : 5;
   }
 
+  /// CHECK-START: boolean Main.EqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<BoolNot:z\d+>>  BooleanNot [<<Arg>>]
+  /// CHECK-DAG:     <<Cond:z\d+>>     Equal [<<BoolNot>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<Cond>>]
+
+  /// CHECK-START: boolean Main.EqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-DAG:     <<False:i\d+>>    IntConstant 0
+  /// CHECK-DAG:                       Return [<<False>>]
+
+  public static boolean EqualBoolVsIntConst(boolean arg) {
+    return (arg ? 0 : 1) == 2;
+  }
+
+  /// CHECK-START: boolean Main.NotEqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>      ParameterValue
+  /// CHECK-DAG:     <<Const2:i\d+>>   IntConstant 2
+  /// CHECK-DAG:     <<BoolNot:z\d+>>  BooleanNot [<<Arg>>]
+  /// CHECK-DAG:     <<Cond:z\d+>>     NotEqual [<<BoolNot>>,<<Const2>>]
+  /// CHECK-DAG:                       Return [<<Cond>>]
+
+  /// CHECK-START: boolean Main.NotEqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-DAG:     <<True:i\d+>>     IntConstant 1
+  /// CHECK-DAG:                       Return [<<True>>]
+
+  public static boolean NotEqualBoolVsIntConst(boolean arg) {
+    return (arg ? 0 : 1) != 2;
+  }
+
   /*
    * Test simplification of double Boolean negation. Note that sometimes
    * both negations can be removed but we only expect the simplifier to
    * remove the second.
    */
 
-  // CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (before)
-  // CHECK-DAG:     [[Arg:z\d+]]       ParameterValue
-  // CHECK-DAG:     [[NotArg:z\d+]]    BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:     [[NotNotArg:z\d+]] BooleanNot [ [[NotArg]] ]
-  // CHECK-DAG:                        Return [ [[NotNotArg]] ]
+  /// CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_bce (before)
+  /// CHECK-DAG:     <<Arg:z\d+>>       ParameterValue
+  /// CHECK-DAG:     <<NotArg:z\d+>>    BooleanNot [<<Arg>>]
+  /// CHECK-DAG:     <<NotNotArg:z\d+>> BooleanNot [<<NotArg>>]
+  /// CHECK-DAG:                        Return [<<NotNotArg>>]
 
-  // CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (after)
-  // CHECK-DAG:     [[Arg:z\d+]]       ParameterValue
-  // CHECK-DAG:                        BooleanNot [ [[Arg]] ]
-  // CHECK-DAG:                        Return [ [[Arg]] ]
+  /// CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-DAG:     <<Arg:z\d+>>       ParameterValue
+  /// CHECK-DAG:                        BooleanNot [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Arg>>]
 
-  // CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_types (after)
-  // CHECK:                            BooleanNot
-  // CHECK-NOT:                        BooleanNot
+  /// CHECK-START: boolean Main.NotNotBool(boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:                            BooleanNot
+  /// CHECK-NOT:                        BooleanNot
 
   public static boolean NegateValue(boolean arg) {
     return !arg;
@@ -956,76 +986,76 @@
     return !(NegateValue(arg));
   }
 
-  // CHECK-START: float Main.Div2(float) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[Const2:f\d+]]   FloatConstant 2
-  // CHECK-DAG:      [[Div:f\d+]]      Div [ [[Arg]] [[Const2]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  /// CHECK-START: float Main.Div2(float) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Const2:f\d+>>   FloatConstant 2
+  /// CHECK-DAG:      <<Div:f\d+>>      Div [<<Arg>>,<<Const2>>]
+  /// CHECK-DAG:                        Return [<<Div>>]
 
-  // CHECK-START: float Main.Div2(float) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstP5:f\d+]]  FloatConstant 0.5
-  // CHECK-DAG:      [[Mul:f\d+]]      Mul [ [[Arg]] [[ConstP5]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  /// CHECK-START: float Main.Div2(float) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<ConstP5:f\d+>>  FloatConstant 0.5
+  /// CHECK-DAG:      <<Mul:f\d+>>      Mul [<<Arg>>,<<ConstP5>>]
+  /// CHECK-DAG:                        Return [<<Mul>>]
 
-  // CHECK-START: float Main.Div2(float) instruction_simplifier (after)
-  // CHECK-NOT:                        Div
+  /// CHECK-START: float Main.Div2(float) instruction_simplifier (after)
+  /// CHECK-NOT:                        Div
 
   public static float Div2(float arg) {
     return arg / 2.0f;
   }
 
-  // CHECK-START: double Main.Div2(double) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[Const2:d\d+]]   DoubleConstant 2
-  // CHECK-DAG:      [[Div:d\d+]]      Div [ [[Arg]] [[Const2]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  /// CHECK-START: double Main.Div2(double) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Const2:d\d+>>   DoubleConstant 2
+  /// CHECK-DAG:      <<Div:d\d+>>      Div [<<Arg>>,<<Const2>>]
+  /// CHECK-DAG:                        Return [<<Div>>]
 
-  // CHECK-START: double Main.Div2(double) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstP5:d\d+]]  DoubleConstant 0.5
-  // CHECK-DAG:      [[Mul:d\d+]]      Mul [ [[Arg]] [[ConstP5]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  /// CHECK-START: double Main.Div2(double) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  /// CHECK-DAG:      <<ConstP5:d\d+>>  DoubleConstant 0.5
+  /// CHECK-DAG:      <<Mul:d\d+>>      Mul [<<Arg>>,<<ConstP5>>]
+  /// CHECK-DAG:                        Return [<<Mul>>]
 
-  // CHECK-START: double Main.Div2(double) instruction_simplifier (after)
-  // CHECK-NOT:                        Div
+  /// CHECK-START: double Main.Div2(double) instruction_simplifier (after)
+  /// CHECK-NOT:                        Div
   public static double Div2(double arg) {
     return arg / 2.0;
   }
 
-  // CHECK-START: float Main.DivMP25(float) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstMP25:f\d+]]   FloatConstant -0.25
-  // CHECK-DAG:      [[Div:f\d+]]      Div [ [[Arg]] [[ConstMP25]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  /// CHECK-START: float Main.DivMP25(float) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<ConstMP25:f\d+>>   FloatConstant -0.25
+  /// CHECK-DAG:      <<Div:f\d+>>      Div [<<Arg>>,<<ConstMP25>>]
+  /// CHECK-DAG:                        Return [<<Div>>]
 
-  // CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstM4:f\d+]]  FloatConstant -4
-  // CHECK-DAG:      [[Mul:f\d+]]      Mul [ [[Arg]] [[ConstM4]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  /// CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<ConstM4:f\d+>>  FloatConstant -4
+  /// CHECK-DAG:      <<Mul:f\d+>>      Mul [<<Arg>>,<<ConstM4>>]
+  /// CHECK-DAG:                        Return [<<Mul>>]
 
-  // CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
-  // CHECK-NOT:                        Div
+  /// CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
+  /// CHECK-NOT:                        Div
 
   public static float DivMP25(float arg) {
     return arg / -0.25f;
   }
 
-  // CHECK-START: double Main.DivMP25(double) instruction_simplifier (before)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstMP25:d\d+]]   DoubleConstant -0.25
-  // CHECK-DAG:      [[Div:d\d+]]      Div [ [[Arg]] [[ConstMP25]] ]
-  // CHECK-DAG:                        Return [ [[Div]] ]
+  /// CHECK-START: double Main.DivMP25(double) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  /// CHECK-DAG:      <<ConstMP25:d\d+>>   DoubleConstant -0.25
+  /// CHECK-DAG:      <<Div:d\d+>>      Div [<<Arg>>,<<ConstMP25>>]
+  /// CHECK-DAG:                        Return [<<Div>>]
 
-  // CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
-  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
-  // CHECK-DAG:      [[ConstM4:d\d+]]  DoubleConstant -4
-  // CHECK-DAG:      [[Mul:d\d+]]      Mul [ [[Arg]] [[ConstM4]] ]
-  // CHECK-DAG:                        Return [ [[Mul]] ]
+  /// CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
+  /// CHECK-DAG:      <<ConstM4:d\d+>>  DoubleConstant -4
+  /// CHECK-DAG:      <<Mul:d\d+>>      Mul [<<Arg>>,<<ConstM4>>]
+  /// CHECK-DAG:                        Return [<<Mul>>]
 
-  // CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
-  // CHECK-NOT:                        Div
+  /// CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
+  /// CHECK-NOT:                        Div
   public static double DivMP25(double arg) {
     return arg / -0.25f;
   }
diff --git a/test/458-long-to-fpu/info.txt b/test/458-long-to-fpu/info.txt
index 7459cfb..cf51df5c 100644
--- a/test/458-long-to-fpu/info.txt
+++ b/test/458-long-to-fpu/info.txt
@@ -1,2 +1,2 @@
 Regression test for x86's code generator, which had a bug in
-the long-to-float and long-to-double  implementations.
+the long-to-float and long-to-double implementations.
diff --git a/test/458-long-to-fpu/src/Main.java b/test/458-long-to-fpu/src/Main.java
index a8b6e78..d1615dc 100644
--- a/test/458-long-to-fpu/src/Main.java
+++ b/test/458-long-to-fpu/src/Main.java
@@ -16,27 +16,30 @@
 
 public class Main {
   public static void main(String[] args) {
-    System.out.println(floatConvert(false));
-    System.out.println(doubleConvert(false));
+    System.out.println($noinline$FloatConvert(false));
+    System.out.println($noinline$DoubleConvert(false));
   }
 
-  public static long floatConvert(boolean flag) {
-    if (flag) {
-      // Try defeating inlining.
-      floatConvert(false);
+  // A dummy value to defeat inlining of these routines.
+  static boolean doThrow = false;
+
+  public static long $noinline$FloatConvert(boolean flag) {
+    // Try defeating inlining.
+    if (doThrow) {
+      throw new Error();
     }
     long l = myLong;
     myFloat = (float)l;
     return l;
   }
 
-  public static long doubleConvert(boolean flag) {
-    if (flag) {
-      // Try defeating inlining.
-      floatConvert(false);
+  public static long $noinline$DoubleConvert(boolean flag) {
+    // Try defeating inlining.
+    if (doThrow) {
+      throw new Error();
     }
     long l = myLong;
-    myFloat = (float)l;
+    myDouble = (double)l;
     return l;
   }
 
diff --git a/test/462-checker-inlining-across-dex-files/src/Main.java b/test/462-checker-inlining-across-dex-files/src/Main.java
index d5563b8..64979ca 100644
--- a/test/462-checker-inlining-across-dex-files/src/Main.java
+++ b/test/462-checker-inlining-across-dex-files/src/Main.java
@@ -21,132 +21,136 @@
 
 public class Main {
 
-  // CHECK-START: void Main.inlineEmptyMethod() inliner (before)
-  // CHECK-DAG:     [[Invoke:v\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      ReturnVoid
+  /// CHECK-START: void Main.inlineEmptyMethod() inliner (before)
+  /// CHECK-DAG:     <<Invoke:v\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      ReturnVoid
 
-  // CHECK-START: void Main.inlineEmptyMethod() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: void Main.inlineEmptyMethod() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
   public static void inlineEmptyMethod() {
     OtherDex.emptyMethod();
   }
 
-  // CHECK-START: int Main.inlineReturnIntMethod() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.inlineReturnIntMethod() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
-  // CHECK-DAG:     [[Const38:i\d+]] IntConstant 38
-  // CHECK-DAG:                      Return [ [[Const38]] ]
+  /// CHECK-START: int Main.inlineReturnIntMethod() inliner (after)
+  /// CHECK-DAG:     <<Const38:i\d+>> IntConstant 38
+  /// CHECK-DAG:                      Return [<<Const38>>]
 
   public static int inlineReturnIntMethod() {
     return OtherDex.returnIntMethod();
   }
 
-  // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
   public static int dontInlineOtherDexStatic() {
     return OtherDex.returnOtherDexStatic();
   }
 
-  // CHECK-START: int Main.inlineMainStatic() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.inlineMainStatic() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.inlineMainStatic() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineMainStatic() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineMainStatic() inliner (after)
-  // CHECK-DAG:     [[Static:i\d+]]  StaticFieldGet
-  // CHECK-DAG:                      Return [ [[Static]] ]
+  /// CHECK-START: int Main.inlineMainStatic() inliner (after)
+  /// CHECK-DAG:     <<Static:i\d+>>  StaticFieldGet
+  /// CHECK-DAG:                      Return [<<Static>>]
 
   public static int inlineMainStatic() {
     return OtherDex.returnMainStatic();
   }
 
-  // CHECK-START: int Main.dontInlineRecursiveCall() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.dontInlineRecursiveCall() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.dontInlineRecursiveCall() inliner (after)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.dontInlineRecursiveCall() inliner (after)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
   public static int dontInlineRecursiveCall() {
     return OtherDex.recursiveCall();
   }
 
-  // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (before)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
   public static String dontInlineReturnString() {
     return OtherDex.returnString();
   }
 
-  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
   public static Class dontInlineOtherDexClass() {
     return OtherDex.returnOtherDexClass();
   }
 
-  // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.Class Main.inlineMainClass() inliner (before)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
-  // CHECK-DAG:     [[Class:l\d+]]  LoadClass
-  // CHECK-DAG:                     Return [ [[Class]] ]
+  /// CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after)
+  /// CHECK-DAG:                     Return [<<Class:l\d+>>]
+  /// CHECK-DAG:     <<Class>>       LoadClass
+  // Note: There are two LoadClass instructions. We obtain the correct
+  //       instruction id by matching the Return's input list first.
 
   public static Class inlineMainClass() {
     return OtherDex.returnMainClass();
   }
 
-  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (before)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (after)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (after)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
   public static Class dontInlineOtherDexClassStaticCall() {
     return OtherDex.returnOtherDexClassStaticCall();
   }
 
-  // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (before)
-  // CHECK-DAG:     [[Invoke:l\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (before)
+  /// CHECK-DAG:     <<Invoke:l\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
-  // CHECK-DAG:     [[Class:l\d+]]  LoadClass
-  // CHECK-DAG:                     Return [ [[Class]] ]
+  /// CHECK-START: java.lang.Class Main.inlineOtherDexCallingMain() inliner (after)
+  /// CHECK-DAG:                     Return [<<Class:l\d+>>]
+  /// CHECK-DAG:     <<Class>>       LoadClass
+  // Note: There are two LoadClass instructions. We obtain the correct
+  //       instruction id by matching the Return's input list first.
 
   public static Class inlineOtherDexCallingMain() {
     return OtherDex.returnOtherDexCallingMain();
diff --git a/test/463-checker-boolean-simplifier/src/Main.java b/test/463-checker-boolean-simplifier/src/Main.java
index 4346103..0b75930 100644
--- a/test/463-checker-boolean-simplifier/src/Main.java
+++ b/test/463-checker-boolean-simplifier/src/Main.java
@@ -37,33 +37,33 @@
    * empty branches removed.
    */
 
-  // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:                       If [ [[Param]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  /// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
+  /// CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:                       If [<<Param>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const1>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Phi>>]
 
-  // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
-  // CHECK:                           Goto
-  // CHECK:                           Goto
-  // CHECK:                           Goto
-  // CHECK-NOT:                       Goto
+  /// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (before)
+  /// CHECK:                           Goto
+  /// CHECK:                           Goto
+  /// CHECK:                           Goto
+  /// CHECK-NOT:                       Goto
 
-  // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[NotParam:z\d+]] BooleanNot [ [[Param]] ]
-  // CHECK-DAG:                       Return [ [[NotParam]] ]
+  /// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
+  /// CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<NotParam:z\d+>> BooleanNot [<<Param>>]
+  /// CHECK-DAG:                       Return [<<NotParam>>]
 
-  // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
-  // CHECK-NOT:                       If
-  // CHECK-NOT:                       Phi
+  /// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
+  /// CHECK-NOT:                       If
+  /// CHECK-NOT:                       Phi
 
-  // CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
-  // CHECK:                           Goto
-  // CHECK-NOT:                       Goto
+  /// CHECK-START: boolean Main.BooleanNot(boolean) boolean_simplifier (after)
+  /// CHECK:                           Goto
+  /// CHECK-NOT:                       Goto
 
   public static boolean BooleanNot(boolean x) {
     return !x;
@@ -74,23 +74,23 @@
    * and 0 when False.
    */
 
-  // CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (before)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     GreaterThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const0]] [[Const1]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  /// CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (before)
+  /// CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     GreaterThan [<<ParamX>>,<<ParamY>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const0>>,<<Const1>>]
+  /// CHECK-DAG:                       Return [<<Phi>>]
 
-  // CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (after)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     GreaterThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       Return [ [[Cond]] ]
+  /// CHECK-START: boolean Main.GreaterThan(int, int) boolean_simplifier (after)
+  /// CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     GreaterThan [<<ParamX>>,<<ParamY>>]
+  /// CHECK-DAG:                       Return [<<Cond>>]
 
   public static boolean GreaterThan(int x, int y) {
     return (x <= y) ? false : true;
@@ -101,26 +101,26 @@
    * and 1 when False.
    */
 
-  // CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (before)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     GreaterThanOrEqual [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       If [ [[Cond]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  /// CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (before)
+  /// CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<Cond:z\d+>>     GreaterThanOrEqual [<<ParamX>>,<<ParamY>>]
+  /// CHECK-DAG:                       If [<<Cond>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const1>>,<<Const0>>]
+  /// CHECK-DAG:                       Return [<<Phi>>]
 
-  // CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Cond:z\d+]]     LessThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       Return [ [[Cond]] ]
+  /// CHECK-START: boolean Main.LessThan(int, int) boolean_simplifier (after)
+  /// CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// 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
+  /// 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;
@@ -131,57 +131,57 @@
    * Note that Phis are discovered retrospectively.
    */
 
-  // CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (before)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamZ:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[CondXY:z\d+]]   GreaterThan [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:                       If [ [[CondXY]] ]
-  // CHECK-DAG:     [[CondYZ:z\d+]]   GreaterThan [ [[ParamY]] [[ParamZ]] ]
-  // CHECK-DAG:                       If [ [[CondYZ]] ]
-  // CHECK-DAG:     [[CondXYZ:z\d+]]  NotEqual [ [[PhiXY:i\d+]] [[PhiYZ:i\d+]] ]
-  // CHECK-DAG:                       If [ [[CondXYZ]] ]
-  // CHECK-DAG:                       Return [ [[PhiXYZ:i\d+]] ]
-  // CHECK-DAG:     [[PhiXY]]         Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:     [[PhiYZ]]         Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:     [[PhiXYZ]]        Phi [ [[Const1]] [[Const0]] ]
+  /// CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (before)
+  /// CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamZ:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+  /// CHECK-DAG:     <<CondXY:z\d+>>   GreaterThan [<<ParamX>>,<<ParamY>>]
+  /// CHECK-DAG:                       If [<<CondXY>>]
+  /// CHECK-DAG:     <<CondYZ:z\d+>>   GreaterThan [<<ParamY>>,<<ParamZ>>]
+  /// CHECK-DAG:                       If [<<CondYZ>>]
+  /// CHECK-DAG:     <<CondXYZ:z\d+>>  NotEqual [<<PhiXY:i\d+>>,<<PhiYZ:i\d+>>]
+  /// CHECK-DAG:                       If [<<CondXYZ>>]
+  /// CHECK-DAG:                       Return [<<PhiXYZ:i\d+>>]
+  /// CHECK-DAG:     <<PhiXY>>         Phi [<<Const1>>,<<Const0>>]
+  /// CHECK-DAG:     <<PhiYZ>>         Phi [<<Const1>>,<<Const0>>]
+  /// CHECK-DAG:     <<PhiXYZ>>        Phi [<<Const1>>,<<Const0>>]
 
-  // CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (after)
-  // CHECK-DAG:     [[ParamX:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamY:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[ParamZ:i\d+]]   ParameterValue
-  // CHECK-DAG:     [[CmpXY:z\d+]]    LessThanOrEqual [ [[ParamX]] [[ParamY]] ]
-  // CHECK-DAG:     [[CmpYZ:z\d+]]    LessThanOrEqual [ [[ParamY]] [[ParamZ]] ]
-  // CHECK-DAG:     [[CmpXYZ:z\d+]]   Equal [ [[CmpXY]] [[CmpYZ]] ]
-  // CHECK-DAG:                       Return [ [[CmpXYZ]] ]
+  /// CHECK-START: boolean Main.ValuesOrdered(int, int, int) boolean_simplifier (after)
+  /// CHECK-DAG:     <<ParamX:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamY:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<ParamZ:i\d+>>   ParameterValue
+  /// CHECK-DAG:     <<CmpXY:z\d+>>    LessThanOrEqual [<<ParamX>>,<<ParamY>>]
+  /// CHECK-DAG:     <<CmpYZ:z\d+>>    LessThanOrEqual [<<ParamY>>,<<ParamZ>>]
+  /// CHECK-DAG:     <<CmpXYZ:z\d+>>   Equal [<<CmpXY>>,<<CmpYZ>>]
+  /// CHECK-DAG:                       Return [<<CmpXYZ>>]
 
   public static boolean ValuesOrdered(int x, int y, int z) {
     return (x <= y) == (y <= z);
   }
 
-  // CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (before)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
-  // CHECK-DAG:     [[Const43:i\d+]]  IntConstant 43
-  // CHECK-DAG:     [[NotParam:z\d+]] BooleanNot [ [[Param]] ]
-  // CHECK-DAG:                       If [ [[NotParam]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const42]] [[Const43]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  /// CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (before)
+  /// CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Const42:i\d+>>  IntConstant 42
+  /// CHECK-DAG:     <<Const43:i\d+>>  IntConstant 43
+  /// CHECK-DAG:     <<NotParam:z\d+>> BooleanNot [<<Param>>]
+  /// CHECK-DAG:                       If [<<NotParam>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const42>>,<<Const43>>]
+  /// CHECK-DAG:                       Return [<<Phi>>]
 
-  // CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Param:z\d+]]    ParameterValue
-  // CHECK-DAG:     [[Const42:i\d+]]  IntConstant 42
-  // CHECK-DAG:     [[Const43:i\d+]]  IntConstant 43
-  // CHECK-DAG:                       If [ [[Param]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const42]] [[Const43]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
+  /// CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (after)
+  /// CHECK-DAG:     <<Param:z\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Const42:i\d+>>  IntConstant 42
+  /// CHECK-DAG:     <<Const43:i\d+>>  IntConstant 43
+  /// CHECK-DAG:                       If [<<Param>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const42>>,<<Const43>>]
+  /// CHECK-DAG:                       Return [<<Phi>>]
 
   // Note: The fact that branches are swapped is verified by running the test.
 
-  // CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (after)
-  // CHECK-NOT:                       BooleanNot
+  /// CHECK-START: int Main.NegatedCondition(boolean) boolean_simplifier (after)
+  /// CHECK-NOT:                       BooleanNot
 
   public static int NegatedCondition(boolean x) {
     if (x != false) {
diff --git a/test/464-checker-inline-sharpen-calls/src/Main.java b/test/464-checker-inline-sharpen-calls/src/Main.java
index 1b25b42..876496f 100644
--- a/test/464-checker-inline-sharpen-calls/src/Main.java
+++ b/test/464-checker-inline-sharpen-calls/src/Main.java
@@ -19,27 +19,27 @@
   public void invokeVirtual() {
   }
 
-  // CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (before)
-  // CHECK-DAG:     [[Invoke:v\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      ReturnVoid
+  /// CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (before)
+  /// CHECK-DAG:     <<Invoke:v\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      ReturnVoid
 
-  // CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
   public static void inlineSharpenInvokeVirtual(Main m) {
     m.invokeVirtual();
   }
 
-  // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (before)
-  // CHECK-DAG:     [[Invoke:i\d+]]  InvokeStaticOrDirect
-  // CHECK-DAG:                      Return [ [[Invoke]] ]
+  /// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (before)
+  /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeStaticOrDirect
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-  // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
-  // CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-  // CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
-  // CHECK-DAG:     [[Field:i\d+]]   InstanceFieldGet
-  // CHECK-DAG:                      Return [ [[Field]] ]
+  /// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after)
+  /// CHECK-DAG:     <<Field:i\d+>>   InstanceFieldGet
+  /// CHECK-DAG:                      Return [<<Field>>]
 
   public static int inlineSharpenStringInvoke() {
     return "Foo".length();
diff --git a/test/465-checker-clinit-gvn/src/Main.java b/test/465-checker-clinit-gvn/src/Main.java
index dcaef6f..704e9fe 100644
--- a/test/465-checker-clinit-gvn/src/Main.java
+++ b/test/465-checker-clinit-gvn/src/Main.java
@@ -26,31 +26,31 @@
 
 public final class Main {
 
-  // CHECK-START: int Main.accessTwoStatics() GVN (before)
-  // CHECK-DAG:     [[Class1:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class1]] ]
-  // CHECK-DAG:     [[Class2:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class2]] ]
+  /// CHECK-START: int Main.accessTwoStatics() GVN (before)
+  /// CHECK-DAG:     <<Class1:l\d+>>  LoadClass
+  /// CHECK-DAG:                      ClinitCheck [<<Class1>>]
+  /// CHECK-DAG:     <<Class2:l\d+>>  LoadClass
+  /// CHECK-DAG:                      ClinitCheck [<<Class2>>]
 
-  // CHECK-START: int Main.accessTwoStatics() GVN (after)
-  // CHECK-DAG:     [[Class:l\d+]]   LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class]] ]
-  // CHECK-NOT:                      ClinitCheck
+  /// CHECK-START: int Main.accessTwoStatics() GVN (after)
+  /// CHECK-DAG:     <<Class:l\d+>>   LoadClass
+  /// CHECK-DAG:                      ClinitCheck [<<Class>>]
+  /// CHECK-NOT:                      ClinitCheck
 
   public static int accessTwoStatics() {
     return OtherClass.b - OtherClass.a;
   }
 
-  // CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (before)
-  // CHECK-DAG:     [[Class1:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class1]] ]
-  // CHECK-DAG:     [[Class2:l\d+]]  LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class2]] ]
+  /// CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (before)
+  /// CHECK-DAG:     <<Class1:l\d+>>  LoadClass
+  /// CHECK-DAG:                      ClinitCheck [<<Class1>>]
+  /// CHECK-DAG:     <<Class2:l\d+>>  LoadClass
+  /// CHECK-DAG:                      ClinitCheck [<<Class2>>]
 
-  // CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (after)
-  // CHECK-DAG:     [[Class:l\d+]]   LoadClass
-  // CHECK-DAG:                      ClinitCheck [ [[Class]] ]
-  // CHECK-NOT:                      ClinitCheck
+  /// CHECK-START: int Main.accessTwoStaticsCallInBetween() GVN (after)
+  /// CHECK-DAG:     <<Class:l\d+>>   LoadClass
+  /// CHECK-DAG:                      ClinitCheck [<<Class>>]
+  /// CHECK-NOT:                      ClinitCheck
 
   public static int accessTwoStaticsCallInBetween() {
     int b = OtherClass.b;
diff --git a/test/466-get-live-vreg/src/Main.java b/test/466-get-live-vreg/src/Main.java
index 3118085..851506b 100644
--- a/test/466-get-live-vreg/src/Main.java
+++ b/test/466-get-live-vreg/src/Main.java
@@ -53,18 +53,30 @@
   }
 
   public static void main(String[] args) {
-    if (testLiveArgument(42) != 42) {
-      throw new Error("Expected 42");
+    if (testLiveArgument(staticField3) != staticField3) {
+      throw new Error("Expected " + staticField3);
     }
 
-    if (testLiveArgument(42) != 42) {
-      throw new Error("Expected 42");
+    if (testLiveArgument(staticField3) != staticField3) {
+      throw new Error("Expected " + staticField3);
     }
 
-    testIntervalHole(1, true);
-    testIntervalHole(1, false);
+    testWrapperIntervalHole(1, true);
+    testWrapperIntervalHole(1, false);
+  }
+
+  // Wrapper method to avoid inlining, which affects liveness
+  // of dex registers.
+  static void testWrapperIntervalHole(int arg, boolean test) {
+    try {
+      Thread.sleep(0);
+      testIntervalHole(arg, test);
+    } catch (Exception e) {
+      throw new Error(e);
+    }
   }
 
   static int staticField1;
   static int staticField2;
+  static int staticField3 = 42;
 }
diff --git a/test/468-checker-bool-simplifier-regression/smali/TestCase.smali b/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
index f36304d..da1c5ec 100644
--- a/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
+++ b/test/468-checker-bool-simplifier-regression/smali/TestCase.smali
@@ -18,6 +18,19 @@
 
 .field public static value:Z
 
+## CHECK-START: boolean TestCase.testCase() boolean_simplifier (before)
+## CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+## CHECK-DAG:     <<Const1:i\d+>>   IntConstant 1
+## CHECK-DAG:     <<Value:z\d+>>    StaticFieldGet
+## CHECK-DAG:                       If [<<Value>>]
+## CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Const1>>,<<Const0>>]
+## CHECK-DAG:                       Return [<<Phi>>]
+
+## CHECK-START: boolean TestCase.testCase() boolean_simplifier (after)
+## CHECK-DAG:     <<Value:z\d+>>    StaticFieldGet
+## CHECK-DAG:     <<Not:z\d+>>      BooleanNot [<<Value>>]
+## CHECK-DAG:                       Return [<<Not>>]
+
 .method public static testCase()Z
     .registers 2
     sget-boolean v0, LTestCase;->value:Z
diff --git a/test/468-checker-bool-simplifier-regression/src/Main.java b/test/468-checker-bool-simplifier-regression/src/Main.java
index d45f3bf..8fe05c7 100644
--- a/test/468-checker-bool-simplifier-regression/src/Main.java
+++ b/test/468-checker-bool-simplifier-regression/src/Main.java
@@ -18,19 +18,6 @@
 
 public class Main {
 
-  // CHECK-START: boolean TestCase.testCase() boolean_simplifier (before)
-  // CHECK-DAG:     [[Const0:i\d+]]   IntConstant 0
-  // CHECK-DAG:     [[Const1:i\d+]]   IntConstant 1
-  // CHECK-DAG:     [[Value:z\d+]]    StaticFieldGet
-  // CHECK-DAG:                       If [ [[Value]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]      Phi [ [[Const1]] [[Const0]] ]
-  // CHECK-DAG:                       Return [ [[Phi]] ]
-
-  // CHECK-START: boolean TestCase.testCase() boolean_simplifier (after)
-  // CHECK-DAG:     [[Value:z\d+]]    StaticFieldGet
-  // CHECK-DAG:     [[Not:z\d+]]      BooleanNot [ [[Value]] ]
-  // CHECK-DAG:                       Return [ [[Not]] ]
-
   public static boolean runTest(boolean input) throws Exception {
     Class<?> c = Class.forName("TestCase");
     Method m = c.getMethod("testCase");
diff --git a/test/473-checker-inliner-constants/src/Main.java b/test/473-checker-inliner-constants/src/Main.java
index 79d89b0..85f6565 100644
--- a/test/473-checker-inliner-constants/src/Main.java
+++ b/test/473-checker-inliner-constants/src/Main.java
@@ -16,13 +16,13 @@
 
 public class Main {
 
-  // CHECK-START: java.lang.Object Main.InlineNullConstant() inliner (before)
-  // CHECK:         NullConstant
-  // CHECK-NOT:     NullConstant
+  /// CHECK-START: java.lang.Object Main.InlineNullConstant() inliner (before)
+  /// CHECK:         NullConstant
+  /// CHECK-NOT:     NullConstant
 
-  // CHECK-START: java.lang.Object Main.InlineNullConstant() inliner (after)
-  // CHECK:         NullConstant
-  // CHECK-NOT:     NullConstant
+  /// CHECK-START: java.lang.Object Main.InlineNullConstant() inliner (after)
+  /// CHECK:         NullConstant
+  /// CHECK-NOT:     NullConstant
 
   public static Object returnNullConstant(Object x) {
     return null;
@@ -32,13 +32,13 @@
     return returnNullConstant(null);
   }
 
-  // CHECK-START: int Main.InlineIntConstant() inliner (before)
-  // CHECK:         IntConstant 42
-  // CHECK-NOT:     IntConstant 42
+  /// CHECK-START: int Main.InlineIntConstant() inliner (before)
+  /// CHECK:         IntConstant 42
+  /// CHECK-NOT:     IntConstant 42
 
-  // CHECK-START: int Main.InlineIntConstant() inliner (after)
-  // CHECK:         IntConstant 42
-  // CHECK-NOT:     IntConstant 42
+  /// CHECK-START: int Main.InlineIntConstant() inliner (after)
+  /// CHECK:         IntConstant 42
+  /// CHECK-NOT:     IntConstant 42
 
   public static int returnIntConstant(int x) {
     return 42;
@@ -48,13 +48,13 @@
     return returnIntConstant(42);
   }
 
-  // CHECK-START: long Main.InlineLongConstant() inliner (before)
-  // CHECK:         LongConstant 42
-  // CHECK-NOT:     LongConstant 42
+  /// CHECK-START: long Main.InlineLongConstant() inliner (before)
+  /// CHECK:         LongConstant 42
+  /// CHECK-NOT:     LongConstant 42
 
-  // CHECK-START: long Main.InlineLongConstant() inliner (after)
-  // CHECK:         LongConstant 42
-  // CHECK-NOT:     LongConstant 42
+  /// CHECK-START: long Main.InlineLongConstant() inliner (after)
+  /// CHECK:         LongConstant 42
+  /// CHECK-NOT:     LongConstant 42
 
   public static long returnLongConstant(long x) {
     return 42L;
diff --git a/test/474-checker-boolean-input/src/Main.java b/test/474-checker-boolean-input/src/Main.java
index 9151986..86d0f7c 100644
--- a/test/474-checker-boolean-input/src/Main.java
+++ b/test/474-checker-boolean-input/src/Main.java
@@ -27,9 +27,9 @@
    * we implement a suitable type analysis.
    */
 
-  // CHECK-START: boolean Main.TestPhiAsBoolean(int) boolean_simplifier (after)
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi
-  // CHECK-DAG:                      BooleanNot [ [[Phi]] ]
+  /// CHECK-START: boolean Main.TestPhiAsBoolean(int) boolean_simplifier (after)
+  /// CHECK-DAG:     <<Phi:i\d+>>     Phi
+  /// CHECK-DAG:                      BooleanNot [<<Phi>>]
 
   public static boolean f1;
   public static boolean f2;
@@ -47,9 +47,9 @@
    * we implement a suitable type analysis.
    */
 
-  // CHECK-START: boolean Main.TestAndAsBoolean(boolean, boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[And:i\d+]]     And
-  // CHECK-DAG:                      BooleanNot [ [[And]] ]
+  /// CHECK-START: boolean Main.TestAndAsBoolean(boolean, boolean) boolean_simplifier (after)
+  /// CHECK-DAG:     <<And:i\d+>>     And
+  /// CHECK-DAG:                      BooleanNot [<<And>>]
 
   public static boolean InlineAnd(boolean x, boolean y) {
     return x & y;
@@ -64,9 +64,9 @@
    * we implement a suitable type analysis.
    */
 
-  // CHECK-START: boolean Main.TestOrAsBoolean(boolean, boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Or:i\d+]]      Or
-  // CHECK-DAG:                      BooleanNot [ [[Or]] ]
+  /// CHECK-START: boolean Main.TestOrAsBoolean(boolean, boolean) boolean_simplifier (after)
+  /// CHECK-DAG:     <<Or:i\d+>>      Or
+  /// CHECK-DAG:                      BooleanNot [<<Or>>]
 
   public static boolean InlineOr(boolean x, boolean y) {
     return x | y;
@@ -81,9 +81,9 @@
    * we implement a suitable type analysis.
    */
 
-  // CHECK-START: boolean Main.TestXorAsBoolean(boolean, boolean) boolean_simplifier (after)
-  // CHECK-DAG:     [[Xor:i\d+]]     Xor
-  // CHECK-DAG:                      BooleanNot [ [[Xor]] ]
+  /// CHECK-START: boolean Main.TestXorAsBoolean(boolean, boolean) boolean_simplifier (after)
+  /// CHECK-DAG:     <<Xor:i\d+>>     Xor
+  /// CHECK-DAG:                      BooleanNot [<<Xor>>]
 
   public static boolean InlineXor(boolean x, boolean y) {
     return x ^ y;
diff --git a/test/476-checker-ctor-memory-barrier/src/Main.java b/test/476-checker-ctor-memory-barrier/src/Main.java
index 10aa2ab..e709ba0 100644
--- a/test/476-checker-ctor-memory-barrier/src/Main.java
+++ b/test/476-checker-ctor-memory-barrier/src/Main.java
@@ -14,10 +14,11 @@
 * limitations under the License.
 */
 
+// TODO: Add more tests after we can inline functions with calls.
 
 class ClassWithoutFinals {
-  // CHECK-START: void ClassWithoutFinals.<init>() register (after)
-  // CHECK-NOT: MemoryBarrier {{StoreStore}}
+  /// CHECK-START: void ClassWithoutFinals.<init>() register (after)
+  /// CHECK-NOT: MemoryBarrier kind:StoreStore
   public ClassWithoutFinals() {}
 }
 
@@ -25,10 +26,9 @@
   public final int x;
   public ClassWithFinals obj;
 
-  // CHECK-START: void ClassWithFinals.<init>(boolean) register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  /// CHECK-START: void ClassWithFinals.<init>(boolean) register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
   public ClassWithFinals(boolean cond) {
     x = 0;
     if (cond) {
@@ -37,19 +37,17 @@
     }
   }
 
-  // CHECK-START: void ClassWithFinals.<init>() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  /// CHECK-START: void ClassWithFinals.<init>() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
   public ClassWithFinals() {
     x = 0;
   }
 
-  // CHECK-START: void ClassWithFinals.<init>(int) register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  /// CHECK-START: void ClassWithFinals.<init>(int) register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
   public ClassWithFinals(int x) {
     // This should have two barriers:
     //   - one for the constructor
@@ -60,88 +58,136 @@
 }
 
 class InheritFromClassWithFinals extends ClassWithFinals {
-  // CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  /// CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
 
-  // CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
+  /// CHECK-START: void InheritFromClassWithFinals.<init>() register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
   public InheritFromClassWithFinals() {
     // Should inline the super constructor.
   }
 
-  // CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
-  // CHECK:     InvokeStaticOrDirect
+  /// CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
+  /// CHECK:      InvokeStaticOrDirect
 
-  // CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
-  // CHECK-NOT: MemoryBarrier {{StoreStore}}
+  /// CHECK-START: void InheritFromClassWithFinals.<init>(boolean) register (after)
+  /// CHECK-NOT:  MemoryBarrier kind:StoreStore
   public InheritFromClassWithFinals(boolean cond) {
     super(cond);
     // should not inline the super constructor
   }
+
+  /// CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK:      ReturnVoid
+
+  /// CHECK-START: void InheritFromClassWithFinals.<init>(int) register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
+  public InheritFromClassWithFinals(int unused) {
+    // Should inline the super constructor and insert a memory barrier.
+
+    // Should inline the new instance call and insert another memory barrier.
+    new InheritFromClassWithFinals();
+  }
 }
 
 class HaveFinalsAndInheritFromClassWithFinals extends ClassWithFinals {
   final int y;
 
-  // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  /// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
 
-  // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
+  /// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>() register (after)
+  /// CHECK-NOT: InvokeStaticOrDirect
   public HaveFinalsAndInheritFromClassWithFinals() {
-    // Should inline the super constructor.
+    // Should inline the super constructor and remove the memory barrier.
     y = 0;
   }
 
-  // CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(boolean) register (after)
-  // CHECK:     InvokeStaticOrDirect
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     ReturnVoid
+  /// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(boolean) register (after)
+  /// CHECK:      InvokeStaticOrDirect
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
   public HaveFinalsAndInheritFromClassWithFinals(boolean cond) {
     super(cond);
     // should not inline the super constructor
     y = 0;
   }
+
+  /// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
+
+  /// CHECK-START: void HaveFinalsAndInheritFromClassWithFinals.<init>(int) register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
+  public HaveFinalsAndInheritFromClassWithFinals(int unused) {
+    // Should inline the super constructor and keep just one memory barrier.
+    y = 0;
+
+    // Should inline new instance and keep one barrier.
+    new HaveFinalsAndInheritFromClassWithFinals();
+    // Should inline new instance and keep one barrier.
+    new InheritFromClassWithFinals();
+  }
 }
 
 public class Main {
 
-  // CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
-  // CHECK:     InvokeStaticOrDirect
+  /// CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
+  /// CHECK:      InvokeStaticOrDirect
 
-  // CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
-  // CHECK-NOT: MemoryBarrier {{StoreStore}}
+  /// CHECK-START: ClassWithFinals Main.noInlineNoConstructorBarrier() register (after)
+  /// CHECK-NOT:  MemoryBarrier kind:StoreStore
   public static ClassWithFinals noInlineNoConstructorBarrier() {
     return new ClassWithFinals(false);
   }
 
-  // CHECK-START: ClassWithFinals Main.inlineConstructorBarrier() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     Return
+  /// CHECK-START: void Main.inlineNew() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
 
-  // CHECK-START: ClassWithFinals Main.inlineConstructorBarrier() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
-  public static ClassWithFinals inlineConstructorBarrier() {
-    return new ClassWithFinals();
+  /// CHECK-START: void Main.inlineNew() register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew() {
+    new ClassWithFinals();
   }
 
-  // CHECK-START: InheritFromClassWithFinals Main.doubleInlineConstructorBarrier() register (after)
-  // CHECK:     MemoryBarrier {{StoreStore}}
-  // CHECK-NOT: {{.*}}
-  // CHECK:     Return
+  /// CHECK-START: void Main.inlineNew1() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
 
-  // CHECK-START: InheritFromClassWithFinals Main.doubleInlineConstructorBarrier() register (after)
-  // CHECK-NOT: InvokeStaticOrDirect
-  public static InheritFromClassWithFinals doubleInlineConstructorBarrier() {
-    return new InheritFromClassWithFinals();
+  /// CHECK-START: void Main.inlineNew1() register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew1() {
+    new InheritFromClassWithFinals();
   }
 
-  public static void main(String[] args) {  }
+  /// CHECK-START: void Main.inlineNew2() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
+
+  /// CHECK-START: void Main.inlineNew2() register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew2() {
+    new HaveFinalsAndInheritFromClassWithFinals();
+  }
+
+  /// CHECK-START: void Main.inlineNew3() register (after)
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK:      MemoryBarrier kind:StoreStore
+  /// CHECK-NEXT: ReturnVoid
+
+  /// CHECK-START: void Main.inlineNew3() register (after)
+  /// CHECK-NOT:  InvokeStaticOrDirect
+  public static void inlineNew3() {
+    new HaveFinalsAndInheritFromClassWithFinals();
+    new HaveFinalsAndInheritFromClassWithFinals();
+  }
+
+  public static void main(String[] args) {}
 }
diff --git a/test/477-checker-bound-type/src/Main.java b/test/477-checker-bound-type/src/Main.java
index b30028d..fe52e83 100644
--- a/test/477-checker-bound-type/src/Main.java
+++ b/test/477-checker-bound-type/src/Main.java
@@ -17,8 +17,8 @@
 
 public class Main {
 
-  // CHECK-START: java.lang.Object Main.boundTypeForIf(java.lang.Object) reference_type_propagation (after)
-  // CHECK:     BoundType
+  /// CHECK-START: java.lang.Object Main.boundTypeForIf(java.lang.Object) reference_type_propagation (after)
+  /// CHECK:     BoundType
   public static Object boundTypeForIf(Object a) {
     if (a != null) {
       return a.toString();
@@ -27,8 +27,8 @@
     }
   }
 
-  // CHECK-START: java.lang.Object Main.boundTypeForInstanceOf(java.lang.Object) reference_type_propagation (after)
-  // CHECK:     BoundType
+  /// CHECK-START: java.lang.Object Main.boundTypeForInstanceOf(java.lang.Object) reference_type_propagation (after)
+  /// CHECK:     BoundType
   public static Object boundTypeForInstanceOf(Object a) {
     if (a instanceof Main) {
       return (Main)a;
@@ -37,8 +37,8 @@
     }
   }
 
-  // CHECK-START: java.lang.Object Main.noBoundTypeForIf(java.lang.Object) reference_type_propagation (after)
-  // CHECK-NOT: BoundType
+  /// CHECK-START: java.lang.Object Main.noBoundTypeForIf(java.lang.Object) reference_type_propagation (after)
+  /// CHECK-NOT: BoundType
   public static Object noBoundTypeForIf(Object a) {
     if (a == null) {
       return new Object();
@@ -47,8 +47,8 @@
     }
   }
 
-  // CHECK-START: java.lang.Object Main.noBoundTypeForInstanceOf(java.lang.Object) reference_type_propagation (after)
-  // CHECK-NOT: BoundType
+  /// CHECK-START: java.lang.Object Main.noBoundTypeForInstanceOf(java.lang.Object) reference_type_propagation (after)
+  /// CHECK-NOT: BoundType
   public static Object noBoundTypeForInstanceOf(Object a) {
     if (a instanceof Main) {
       return new Object();
diff --git a/test/477-long-to-float-conversion-precision/info.txt b/test/477-long-to-float-conversion-precision/info.txt
index d9d41d7..1e07cf3 100644
--- a/test/477-long-to-float-conversion-precision/info.txt
+++ b/test/477-long-to-float-conversion-precision/info.txt
@@ -1 +1 @@
-Tests for type conversions precision.
+Regression test for type conversion precision.
diff --git a/test/477-long-to-float-conversion-precision/src/Main.java b/test/477-long-to-float-conversion-precision/src/Main.java
index bc17053..cd97039 100644
--- a/test/477-long-to-float-conversion-precision/src/Main.java
+++ b/test/477-long-to-float-conversion-precision/src/Main.java
@@ -30,9 +30,8 @@
   }
 
   private static void longToFloat() {
-    // The result for this test case is slightly less accurate on ARM,
-    // due to the implementation of long-to-float type conversions for
-    // this architecture (both in Quick and Optimizing).
+    // The result for this test case used to be slightly less accurate
+    // on ARM (both in Quick and Optimizing).
     assertFloatEquals(Float.intBitsToFloat(-555858671), $opt$LongToFloat(-8008112895877447681L));
   }
 
diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java
index 6da8945..e6aab63 100644
--- a/test/478-checker-clinit-check-pruning/src/Main.java
+++ b/test/478-checker-clinit-check-pruning/src/Main.java
@@ -23,17 +23,17 @@
    * removed before register allocation & code generation.
    */
 
-  // CHECK-START: void Main.invokeStaticInlined() builder (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
-  // CHECK-DAG:                           InvokeStaticOrDirect [ [[ClinitCheck]] ]
+  /// CHECK-START: void Main.invokeStaticInlined() builder (after)
+  /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  /// CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
+  /// CHECK-DAG:                           InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
 
-  // CHECK-START: void Main.invokeStaticInlined() inliner (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
+  /// CHECK-START: void Main.invokeStaticInlined() inliner (after)
+  /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  /// CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
 
-  // CHECK-START: void Main.invokeStaticInlined() inliner (after)
-  // CHECK-NOT:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main.invokeStaticInlined() inliner (after)
+  /// CHECK-NOT:                           InvokeStaticOrDirect
 
   // The following checks ensure the clinit check instruction added by
   // the builder is pruned by the PrepareForRegisterAllocation, while
@@ -41,12 +41,12 @@
   // graph is not dumped after (nor before) this step, we check the
   // CFG as it is before the next pass (liveness analysis) instead.
 
-  // CHECK-START: void Main.invokeStaticInlined() liveness (before)
-  // CHECK-DAG:                           LoadClass
+  /// CHECK-START: void Main.invokeStaticInlined() liveness (before)
+  /// CHECK-DAG:                           LoadClass gen_clinit_check:true
 
-  // CHECK-START: void Main.invokeStaticInlined() liveness (before)
-  // CHECK-NOT:                           ClinitCheck
-  // CHECK-NOT:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main.invokeStaticInlined() liveness (before)
+  /// CHECK-NOT:                           ClinitCheck
+  /// CHECK-NOT:                           InvokeStaticOrDirect
 
   static void invokeStaticInlined() {
     ClassWithClinit1.$opt$inline$StaticMethod();
@@ -66,15 +66,15 @@
    * initialization check of the called method's declaring class.
    */
 
-  // CHECK-START: void Main.invokeStaticNotInlined() builder (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
-  // CHECK-DAG:                           InvokeStaticOrDirect [ [[ClinitCheck]] ]
+  /// CHECK-START: void Main.invokeStaticNotInlined() builder (after)
+  /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  /// CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
+  /// CHECK-DAG:                           InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
 
-  // CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
-  // CHECK-DAG:     [[LoadClass:l\d+]]    LoadClass
-  // CHECK-DAG:     [[ClinitCheck:l\d+]]  ClinitCheck [ [[LoadClass]] ]
-  // CHECK-DAG:                           InvokeStaticOrDirect [ [[ClinitCheck]] ]
+  /// CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
+  /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  /// CHECK-DAG:     <<ClinitCheck:l\d+>>  ClinitCheck [<<LoadClass>>]
+  /// CHECK-DAG:                           InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
 
   // The following checks ensure the clinit check and load class
   // instructions added by the builder are pruned by the
@@ -82,15 +82,15 @@
   // dumped after (nor before) this step, we check the CFG as it is
   // before the next pass (liveness analysis) instead.
 
-  // CHECK-START: void Main.invokeStaticNotInlined() liveness (before)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main.invokeStaticNotInlined() liveness (before)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main.invokeStaticNotInlined() liveness (before)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main.invokeStaticNotInlined() liveness (before)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
   static void invokeStaticNotInlined() {
-    ClassWithClinit2.staticMethod();
+    ClassWithClinit2.$noinline$staticMethod();
   }
 
   static class ClassWithClinit2 {
@@ -100,7 +100,7 @@
 
     static boolean doThrow = false;
 
-    static void staticMethod() {
+    static void $noinline$staticMethod() {
       if (doThrow) {
         // Try defeating inlining.
         throw new Error();
@@ -114,17 +114,17 @@
    * explicit clinit check.
    */
 
-  // CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() builder (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
-  // CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() inliner (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
-  // CHECK-NOT:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$ClassWithClinit3.invokeStaticInlined() inliner (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
+  /// CHECK-NOT:                           InvokeStaticOrDirect
 
   static class ClassWithClinit3 {
     static void invokeStaticInlined() {
@@ -149,27 +149,27 @@
    * require an explicit clinit check.
    */
 
-  // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() builder (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
-  // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main$ClassWithClinit4.invokeStaticNotInlined() inliner (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
   static class ClassWithClinit4 {
     static void invokeStaticNotInlined() {
       // The invocation of invokeStaticNotInlined triggers the
       // initialization of ClassWithClinit4, meaning that the
-      // hereinbelow call to staticMethod does not need a clinit
+      // call to staticMethod below does not need a clinit
       // check.
-      staticMethod();
+      $noinline$staticMethod();
     }
 
     static {
@@ -178,7 +178,7 @@
 
     static boolean doThrow = false;
 
-    static void staticMethod() {
+    static void $noinline$staticMethod() {
       if (doThrow) {
         // Try defeating inlining.
         throw new Error();
@@ -192,17 +192,17 @@
    * explicit clinit check.
    */
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() builder (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
-  // CHECK-NOT:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$SubClassOfClassWithClinit5.invokeStaticInlined() inliner (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
+  /// CHECK-NOT:                           InvokeStaticOrDirect
 
   static class ClassWithClinit5 {
     static void $opt$inline$StaticMethod() {
@@ -225,24 +225,24 @@
    * explicit clinit check.
    */
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() builder (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
-  // CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
+  /// CHECK-DAG:                           InvokeStaticOrDirect
 
-  // CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
-  // CHECK-NOT:                           LoadClass
-  // CHECK-NOT:                           ClinitCheck
+  /// CHECK-START: void Main$SubClassOfClassWithClinit6.invokeStaticNotInlined() inliner (after)
+  /// CHECK-NOT:                           LoadClass
+  /// CHECK-NOT:                           ClinitCheck
 
   static class ClassWithClinit6 {
     static boolean doThrow = false;
 
-    static void staticMethod() {
+    static void $noinline$staticMethod() {
       if (doThrow) {
         // Try defeating inlining.
         throw new Error();
@@ -256,10 +256,48 @@
 
   static class SubClassOfClassWithClinit6 extends ClassWithClinit6 {
     static void invokeStaticNotInlined() {
-      ClassWithClinit6.staticMethod();
+      ClassWithClinit6.$noinline$staticMethod();
     }
   }
 
+
+  /*
+   * Verify that if we have a static call immediately after the load class
+   * we don't do generate a clinit check.
+   */
+
+  /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
+  /// CHECK-DAG:     <<IntConstant:i\d+>>  IntConstant 0
+  /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:false
+  /// CHECK-DAG:                           InvokeStaticOrDirect
+  /// CHECK-DAG:                           StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
+
+  /// CHECK-START: void Main.noClinitBecauseOfInvokeStatic() liveness (before)
+  /// CHECK-NOT:                           ClinitCheck
+
+  static void noClinitBecauseOfInvokeStatic() {
+    ClassWithClinit2.$noinline$staticMethod();
+    ClassWithClinit2.doThrow = false;
+  }
+
+  /*
+   * Verify that if the static call is after a field access, the load class
+   * will generate a clinit check.
+   */
+
+  /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
+  /// CHECK-DAG:     <<IntConstant:i\d+>>  IntConstant 0
+  /// CHECK-DAG:     <<LoadClass:l\d+>>    LoadClass gen_clinit_check:true
+  /// CHECK-DAG:                           StaticFieldSet [<<LoadClass>>,<<IntConstant>>]
+  /// CHECK-DAG:                           InvokeStaticOrDirect
+
+  /// CHECK-START: void Main.clinitBecauseOfFieldAccess() liveness (before)
+  /// CHECK-NOT:                           ClinitCheck
+  static void clinitBecauseOfFieldAccess() {
+    ClassWithClinit2.doThrow = false;
+    ClassWithClinit2.$noinline$staticMethod();
+  }
+
   // TODO: Add a test for the case of a static method whose declaring
   // class type index is not available (i.e. when `storage_index`
   // equals `DexFile::kDexNoIndex` in
diff --git a/test/478-checker-inliner-nested-loop/src/Main.java b/test/478-checker-inliner-nested-loop/src/Main.java
index df583d9..aa02349 100644
--- a/test/478-checker-inliner-nested-loop/src/Main.java
+++ b/test/478-checker-inliner-nested-loop/src/Main.java
@@ -33,12 +33,12 @@
     return result;
   }
 
-  // CHECK-START: int Main.NestedLoop(int, int) inliner (before)
-  // CHECK-NOT:     Mul
+  /// CHECK-START: int Main.NestedLoop(int, int) inliner (before)
+  /// CHECK-NOT:     Mul
 
-  // CHECK-START: int Main.NestedLoop(int, int) inliner (after)
-  // CHECK:         Mul
-  // CHECK-NOT:     Mul
+  /// CHECK-START: int Main.NestedLoop(int, int) inliner (after)
+  /// CHECK:         Mul
+  /// CHECK-NOT:     Mul
 
   public static int NestedLoop(int max_x, int max_y) {
     int total = 0;
diff --git a/test/480-checker-dead-blocks/src/Main.java b/test/480-checker-dead-blocks/src/Main.java
index 83dbb26..4cc1634 100644
--- a/test/480-checker-dead-blocks/src/Main.java
+++ b/test/480-checker-dead-blocks/src/Main.java
@@ -30,25 +30,25 @@
     return false;
   }
 
-  // CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (before)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
-  // CHECK-DAG:                      If
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  /// CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (before)
+  /// CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  /// CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
+  /// CHECK-DAG:                      If
+  /// CHECK-DAG:     <<Add:i\d+>>     Add [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:     <<Sub:i\d+>>     Sub [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Add>>,<<Sub>>]
+  /// CHECK-DAG:                      Return [<<Phi>>]
 
-  // CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:                      Return [ [[Add]] ]
+  /// CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
+  /// CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  /// CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Add:i\d+>>     Add [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:                      Return [<<Add>>]
 
-  // CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
-  // CHECK-NOT:                      If
-  // CHECK-NOT:                      Sub
-  // CHECK-NOT:                      Phi
+  /// CHECK-START: int Main.testTrueBranch(int, int) dead_code_elimination_final (after)
+  /// CHECK-NOT:                      If
+  /// CHECK-NOT:                      Sub
+  /// CHECK-NOT:                      Phi
 
   public static int testTrueBranch(int x, int y) {
     int z;
@@ -60,25 +60,25 @@
     return z;
   }
 
-  // CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (before)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
-  // CHECK-DAG:                      If
-  // CHECK-DAG:     [[Add:i\d+]]     Add [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:     [[Phi:i\d+]]     Phi [ [[Add]] [[Sub]] ]
-  // CHECK-DAG:                      Return [ [[Phi]] ]
+  /// CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (before)
+  /// CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  /// CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
+  /// CHECK-DAG:                      If
+  /// CHECK-DAG:     <<Add:i\d+>>     Add [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:     <<Sub:i\d+>>     Sub [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:     <<Phi:i\d+>>     Phi [<<Add>>,<<Sub>>]
+  /// CHECK-DAG:                      Return [<<Phi>>]
 
-  // CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[ArgX:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[ArgY:i\d+]]    ParameterValue
-  // CHECK-DAG:     [[Sub:i\d+]]     Sub [ [[ArgX]] [[ArgY]] ]
-  // CHECK-DAG:                      Return [ [[Sub]] ]
+  /// CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
+  /// CHECK-DAG:     <<ArgX:i\d+>>    ParameterValue
+  /// CHECK-DAG:     <<ArgY:i\d+>>    ParameterValue
+  /// CHECK-DAG:     <<Sub:i\d+>>     Sub [<<ArgX>>,<<ArgY>>]
+  /// CHECK-DAG:                      Return [<<Sub>>]
 
-  // CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
-  // CHECK-NOT:                      If
-  // CHECK-NOT:                      Add
-  // CHECK-NOT:                      Phi
+  /// CHECK-START: int Main.testFalseBranch(int, int) dead_code_elimination_final (after)
+  /// CHECK-NOT:                      If
+  /// CHECK-NOT:                      Add
+  /// CHECK-NOT:                      Phi
 
   public static int testFalseBranch(int x, int y) {
     int z;
@@ -90,11 +90,11 @@
     return z;
   }
 
-  // CHECK-START: int Main.testRemoveLoop(int) dead_code_elimination_final (before)
-  // CHECK:                          Mul
+  /// CHECK-START: int Main.testRemoveLoop(int) dead_code_elimination_final (before)
+  /// CHECK:                          Mul
 
-  // CHECK-START: int Main.testRemoveLoop(int) dead_code_elimination_final (after)
-  // CHECK-NOT:                      Mul
+  /// CHECK-START: int Main.testRemoveLoop(int) dead_code_elimination_final (after)
+  /// CHECK-NOT:                      Mul
 
   public static int testRemoveLoop(int x) {
     if (inlineFalse()) {
@@ -105,13 +105,13 @@
     return x;
   }
 
-  // CHECK-START: int Main.testInfiniteLoop(int) dead_code_elimination_final (before)
-  // CHECK-DAG:                      Return
-  // CHECK-DAG:                      Exit
+  /// CHECK-START: int Main.testInfiniteLoop(int) dead_code_elimination_final (before)
+  /// CHECK-DAG:                      Return
+  /// CHECK-DAG:                      Exit
 
-  // CHECK-START: int Main.testInfiniteLoop(int) dead_code_elimination_final (after)
-  // CHECK-NOT:                      Return
-  // CHECK-NOT:                      Exit
+  /// CHECK-START: int Main.testInfiniteLoop(int) dead_code_elimination_final (after)
+  /// CHECK-NOT:                      Return
+  /// CHECK-NOT:                      Exit
 
   public static int testInfiniteLoop(int x) {
     while (inlineTrue()) {
@@ -120,17 +120,17 @@
     return x;
   }
 
-  // CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (before)
-  // CHECK-DAG:                      If
-  // CHECK-DAG:                      Add
+  /// CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (before)
+  /// CHECK-DAG:                      If
+  /// CHECK-DAG:                      Add
 
-  // CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  /// CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  /// CHECK-DAG:                      Return [<<Arg>>]
 
-  // CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
-  // CHECK-NOT:                      If
-  // CHECK-NOT:                      Add
+  /// CHECK-START: int Main.testDeadLoop(int) dead_code_elimination_final (after)
+  /// CHECK-NOT:                      If
+  /// CHECK-NOT:                      Add
 
   public static int testDeadLoop(int x) {
     while (inlineFalse()) {
@@ -139,18 +139,18 @@
     return x;
   }
 
-  // CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (before)
-  // CHECK-DAG:                      If
-  // CHECK-DAG:                      If
-  // CHECK-DAG:                      Add
+  /// CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (before)
+  /// CHECK-DAG:                      If
+  /// CHECK-DAG:                      If
+  /// CHECK-DAG:                      Add
 
-  // CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
-  // CHECK-DAG:     [[Arg:i\d+]]     ParameterValue
-  // CHECK-DAG:                      Return [ [[Arg]] ]
+  /// CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
+  /// CHECK-DAG:     <<Arg:i\d+>>     ParameterValue
+  /// CHECK-DAG:                      Return [<<Arg>>]
 
-  // CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
-  // CHECK-NOT:                      If
-  // CHECK-NOT:                      Add
+  /// CHECK-START: int Main.testUpdateLoopInformation(int) dead_code_elimination_final (after)
+  /// CHECK-NOT:                      If
+  /// CHECK-NOT:                      Add
 
   public static int testUpdateLoopInformation(int x) {
     // Use of Or in the condition generates a dead loop where not all of its
@@ -161,16 +161,16 @@
     return x;
   }
 
-  // CHECK-START: int Main.testRemoveSuspendCheck(int, int) dead_code_elimination_final (before)
-  // CHECK:                          SuspendCheck
-  // CHECK:                          SuspendCheck
-  // CHECK:                          SuspendCheck
-  // CHECK-NOT:                      SuspendCheck
+  /// CHECK-START: int Main.testRemoveSuspendCheck(int, int) dead_code_elimination_final (before)
+  /// CHECK:                          SuspendCheck
+  /// CHECK:                          SuspendCheck
+  /// CHECK:                          SuspendCheck
+  /// CHECK-NOT:                      SuspendCheck
 
-  // CHECK-START: int Main.testRemoveSuspendCheck(int, int) dead_code_elimination_final (after)
-  // CHECK:                          SuspendCheck
-  // CHECK:                          SuspendCheck
-  // CHECK-NOT:                      SuspendCheck
+  /// CHECK-START: int Main.testRemoveSuspendCheck(int, int) dead_code_elimination_final (after)
+  /// CHECK:                          SuspendCheck
+  /// CHECK:                          SuspendCheck
+  /// CHECK-NOT:                      SuspendCheck
 
   public static int testRemoveSuspendCheck(int x, int y) {
     // Inner loop will leave behind the header with its SuspendCheck. DCE must
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 74184e8..18125fa 100644
--- a/test/482-checker-loop-back-edge-use/src/Main.java
+++ b/test/482-checker-loop-back-edge-use/src/Main.java
@@ -17,17 +17,17 @@
 
 public class Main {
 
-  // CHECK-START: void Main.loop1(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 22) }, uses: { 17 22 }
-  // CHECK:         Goto (liveness: 20)
+  /// CHECK-START: void Main.loop1(boolean) liveness (after)
+  /// CHECK:         ParameterValue  liveness:2  ranges:{[2,22)} uses:[17,22]
+  /// CHECK:         Goto            liveness:20
   public static void loop1(boolean incoming) {
     while (incoming) {}
   }
 
-  // CHECK-START: void Main.loop2(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 42) }, uses: { 33 38 42 }
-  // CHECK:         Goto (liveness: 36)
-  // CHECK:         Goto (liveness: 40)
+  /// CHECK-START: void Main.loop2(boolean) liveness (after)
+  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,44)} uses:[35,40,44]
+  /// CHECK:         Goto            liveness:38
+  /// CHECK:         Goto            liveness:42
   public static void loop2(boolean incoming) {
     while (true) {
       System.out.println("foo");
@@ -35,12 +35,12 @@
     }
   }
 
-  // CHECK-START: void Main.loop3(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 60) }, uses: { 56 60 }
-  // CHECK:         Goto (liveness: 58)
+  /// CHECK-START: void Main.loop3(boolean) liveness (after)
+  /// 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: 54)
+  // 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) {
@@ -50,10 +50,10 @@
   }
 
   // CHECK-START: void Main.loop4(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 22) }, uses: { 22 }
+  // CHECK:         ParameterValue  liveness:4  ranges:{[4,22)} uses:[22]
 
   // CHECK-START: void Main.loop4(boolean) liveness (after)
-  // CHECK-NOT:     Goto (liveness: 20)
+  // 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);
@@ -62,10 +62,10 @@
     }
   }
 
-  // CHECK-START: void Main.loop5(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 50) }, uses: { 33 42 46 50 }
-  // CHECK:         Goto (liveness: 44)
-  // CHECK:         Goto (liveness: 48)
+  /// CHECK-START: void Main.loop5(boolean) liveness (after)
+  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,54)} uses:[37,46,50,54]
+  /// CHECK:         Goto            liveness:48
+  /// CHECK:         Goto            liveness:52
   public static void loop5(boolean incoming) {
     // 'incoming' must have a use at both back edges.
     while (Runtime.getRuntime() != null) {
@@ -75,12 +75,12 @@
     }
   }
 
-  // CHECK-START: void Main.loop6(boolean) liveness (after)
-  // CHECK          ParameterValue (liveness: 2 ranges: { [2, 46) }, uses: { 24 46 }
-  // CHECK:         Goto (liveness: 44)
+  /// CHECK-START: void Main.loop6(boolean) liveness (after)
+  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,50)} uses:[26,50]
+  /// CHECK:         Goto            liveness:48
 
-  // CHECK-START: void Main.loop6(boolean) liveness (after)
-  // CHECK-NOT:     Goto (liveness: 22)
+  /// CHECK-START: void Main.loop6(boolean) liveness (after)
+  /// CHECK-NOT:     Goto            liveness:24
   public static void loop6(boolean incoming) {
     // 'incoming' must have a use only at the first loop's back edge.
     while (true) {
@@ -89,10 +89,10 @@
     }
   }
 
-  // CHECK-START: void Main.loop7(boolean) liveness (after)
-  // CHECK:         ParameterValue (liveness: 2 ranges: { [2, 50) }, uses: { 32 41 46 50 }
-  // CHECK:         Goto (liveness: 44)
-  // CHECK:         Goto (liveness: 48)
+  /// CHECK-START: void Main.loop7(boolean) liveness (after)
+  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,54)} uses:[36,45,50,54]
+  /// CHECK:         Goto            liveness:48
+  /// CHECK:         Goto            liveness:52
   public static void loop7(boolean incoming) {
     // 'incoming' must have a use at both back edges.
     while (Runtime.getRuntime() != null) {
@@ -101,10 +101,10 @@
     }
   }
 
-  // CHECK-START: void Main.loop8() liveness (after)
-  // CHECK:         StaticFieldGet (liveness: 12 ranges: { [12, 44) }, uses: { 35 40 44 }
-  // CHECK:         Goto (liveness: 38)
-  // CHECK:         Goto (liveness: 42)
+  /// CHECK-START: void Main.loop8() liveness (after)
+  /// CHECK:         StaticFieldGet  liveness:14 ranges:{[14,48)} uses:[39,44,48]
+  /// CHECK:         Goto            liveness:42
+  /// CHECK:         Goto            liveness:46
   public static void loop8() {
     // 'incoming' must have a use at both back edges.
     boolean incoming = field;
@@ -113,9 +113,9 @@
     }
   }
 
-  // CHECK-START: void Main.loop9() liveness (after)
-  // CHECK:         StaticFieldGet (liveness: 22 ranges: { [22, 36) }, uses: { 31 36 }
-  // CHECK:         Goto (liveness: 38)
+  /// CHECK-START: void Main.loop9() liveness (after)
+  /// CHECK:         StaticFieldGet  liveness:26 ranges:{[26,40)} uses:[35,40]
+  /// CHECK:         Goto            liveness:42
   public static void loop9() {
     while (Runtime.getRuntime() != null) {
       // 'incoming' must only have a use in the inner loop.
diff --git a/test/484-checker-register-hints/src/Main.java b/test/484-checker-register-hints/src/Main.java
index 33952d9..3715ca2 100644
--- a/test/484-checker-register-hints/src/Main.java
+++ b/test/484-checker-register-hints/src/Main.java
@@ -16,21 +16,21 @@
 
 public class Main {
 
-  // CHECK-START: void Main.test1(boolean, int, int, int, int, int) register (after)
-  // CHECK:       name "B0"
-  // CHECK-NOT:     ParallelMove
-  // CHECK:       name "B1"
-  // CHECK-NOT:   end_block
-  // CHECK:         If
-  // CHECK-NOT:     ParallelMove
-  // CHECK:       name "B3"
-  // CHECK-NOT:   end_block
-  // CHECK:         ArraySet
+  /// CHECK-START: void Main.test1(boolean, int, int, int, int, int) register (after)
+  /// CHECK:       name "B0"
+  /// CHECK-NOT:     ParallelMove
+  /// CHECK:       name "B1"
+  /// CHECK-NOT:   end_block
+  /// CHECK:         If
+  /// CHECK-NOT:     ParallelMove
+  /// CHECK:       name "B3"
+  /// CHECK-NOT:   end_block
+  /// CHECK:         ArraySet
   // We could check here that there is a parallel move, but it's only valid
   // for some architectures (for example x86), as other architectures may
   // not do move at all.
-  // CHECK:       end_block
-  // CHECK-NOT:     ParallelMove
+  /// CHECK:       end_block
+  /// CHECK-NOT:     ParallelMove
 
   public static void test1(boolean z, int a, int b, int c, int d, int m) {
     int e = live1;
@@ -51,21 +51,21 @@
     live1 = e + f + g;
   }
 
-  // CHECK-START: void Main.test2(boolean, int, int, int, int, int) register (after)
-  // CHECK:       name "B0"
-  // CHECK-NOT:     ParallelMove
-  // CHECK:       name "B1"
-  // CHECK-NOT:   end_block
-  // CHECK:         If
-  // CHECK-NOT:     ParallelMove
-  // CHECK:       name "B3"
-  // CHECK-NOT:   end_block
-  // CHECK:         ArraySet
+  /// CHECK-START: void Main.test2(boolean, int, int, int, int, int) register (after)
+  /// CHECK:       name "B0"
+  /// CHECK-NOT:     ParallelMove
+  /// CHECK:       name "B1"
+  /// CHECK-NOT:   end_block
+  /// CHECK:         If
+  /// CHECK-NOT:     ParallelMove
+  /// CHECK:       name "B3"
+  /// CHECK-NOT:   end_block
+  /// CHECK:         ArraySet
   // We could check here that there is a parallel move, but it's only valid
   // for some architectures (for example x86), as other architectures may
   // not do move at all.
-  // CHECK:       end_block
-  // CHECK-NOT:     ParallelMove
+  /// CHECK:       end_block
+  /// CHECK-NOT:     ParallelMove
 
   public static void test2(boolean z, int a, int b, int c, int d, int m) {
     int e = live1;
@@ -85,21 +85,21 @@
     live1 = e + f + g;
   }
 
-  // CHECK-START: void Main.test3(boolean, int, int, int, int, int) register (after)
-  // CHECK:       name "B0"
-  // CHECK-NOT:     ParallelMove
-  // CHECK:       name "B1"
-  // CHECK-NOT:   end_block
-  // CHECK:         If
-  // CHECK-NOT:     ParallelMove
-  // CHECK:       name "B6"
-  // CHECK-NOT:   end_block
-  // CHECK:         ArraySet
+  /// CHECK-START: void Main.test3(boolean, int, int, int, int, int) register (after)
+  /// CHECK:       name "B0"
+  /// CHECK-NOT:     ParallelMove
+  /// CHECK:       name "B1"
+  /// CHECK-NOT:   end_block
+  /// CHECK:         If
+  /// CHECK-NOT:     ParallelMove
+  /// CHECK:       name "B6"
+  /// CHECK-NOT:   end_block
+  /// CHECK:         ArraySet
   // We could check here that there is a parallel move, but it's only valid
   // for some architectures (for example x86), as other architectures may
   // not do move at all.
-  // CHECK:       end_block
-  // CHECK-NOT:     ParallelMove
+  /// CHECK:       end_block
+  /// CHECK-NOT:     ParallelMove
 
   public static void test3(boolean z, int a, int b, int c, int d, int m) {
     // Same version as test2, but with branches reversed, to ensure
diff --git a/test/485-checker-dce-loop-update/smali/TestCase.smali b/test/485-checker-dce-loop-update/smali/TestCase.smali
index 6a42a46..ab4afdb 100644
--- a/test/485-checker-dce-loop-update/smali/TestCase.smali
+++ b/test/485-checker-dce-loop-update/smali/TestCase.smali
@@ -23,27 +23,27 @@
 .end method
 
 
-# CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[Cst1]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX]] [[Cst5]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+## CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (before)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+## CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+## CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<Cst1>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Add5>>       Add [<<PhiX>>,<<Cst5>>]                    loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+## CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
-# CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[AddX:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[AddX]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+## CHECK-START: int TestCase.testSingleExit(int, boolean) dead_code_elimination_final (after)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+## CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<AddX:i\d+>>]               loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<AddX>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+## CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 .method public static testSingleExit(IZ)I
   .registers 3
@@ -73,31 +73,31 @@
 .end method
 
 
-# CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[Cst1]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX]] [[Cst5]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+## CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (before)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+## CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+## CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<ArgZ>>]                              loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<Cst1>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Add5>>       Add [<<PhiX>>,<<Cst5>>]                    loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+## CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
-# CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add7:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:null
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+## CHECK-START: int TestCase.testMultipleExits(int, boolean, boolean) dead_code_elimination_final (after)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+## CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add7:i\d+>>]               loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<ArgZ>>]                              loop:none
+## CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 .method public static testMultipleExits(IZZ)I
   .registers 4
@@ -129,37 +129,37 @@
 .end method
 
 
-# CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[Cst9:i\d+]]  IntConstant 9
-# CHECK-DAG:     [[PhiX1:i\d+]] Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Mul9:i\d+]]  Mul [ [[PhiX1]] [[Cst9]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:     [[PhiX2:i\d+]] Phi [ [[PhiX1]] [[Mul9]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[Cst1]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX2]] [[Cst5]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX1]] [[Cst7]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX2]] ]                         loop_header:null
+## CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (before)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+## CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+## CHECK-DAG:     <<Cst9:i\d+>>  IntConstant 9
+## CHECK-DAG:     <<PhiX1:i\d+>> Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<ArgZ>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Mul9:i\d+>>  Mul [<<PhiX1>>,<<Cst9>>]                   loop:<<HeaderY>>
+## CHECK-DAG:     <<PhiX2:i\d+>> Phi [<<PhiX1>>,<<Mul9>>]                   loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<Cst1>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Add5>>       Add [<<PhiX2>>,<<Cst5>>]                   loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX1>>,<<Cst7>>]                   loop:<<HeaderY>>
+## CHECK-DAG:                    Return [<<PhiX2>>]                         loop:none
 
-# CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
-# CHECK-DAG:     [[Cst9:i\d+]]  IntConstant 9
-# CHECK-DAG:     [[PhiX1:i\d+]] Phi [ [[ArgX]] [[Add7:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX1]] [[Cst7]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgZ]] ]                              loop_header:null
-# CHECK-DAG:     [[Mul9:i\d+]]  Mul [ [[PhiX1]] [[Cst9]] ]                   loop_header:null
-# CHECK-DAG:     [[PhiX2:i\d+]] Phi [ [[PhiX1]] [[Mul9]] ]                   loop_header:null
-# CHECK-DAG:                    Return [ [[PhiX2]] ]                         loop_header:null
+## CHECK-START: int TestCase.testExitPredecessors(int, boolean, boolean) dead_code_elimination_final (after)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
+## CHECK-DAG:     <<Cst9:i\d+>>  IntConstant 9
+## CHECK-DAG:     <<PhiX1:i\d+>> Phi [<<ArgX>>,<<Add7:i\d+>>]               loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX1>>,<<Cst7>>]                   loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<ArgZ>>]                              loop:none
+## CHECK-DAG:     <<Mul9:i\d+>>  Mul [<<PhiX1>>,<<Cst9>>]                   loop:none
+## CHECK-DAG:     <<PhiX2:i\d+>> Phi [<<PhiX1>>,<<Mul9>>]                   loop:none
+## CHECK-DAG:                    Return [<<PhiX2>>]                         loop:none
 
 .method public static testExitPredecessors(IZZ)I
   .registers 4
@@ -196,49 +196,48 @@
 .end method
 
 
-# CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (before)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst0:i\d+]]  IntConstant 0
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst5:i\d+]]  IntConstant 5
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
+## CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (before)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst0:i\d+>>  IntConstant 0
+## CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+## CHECK-DAG:     <<Cst5:i\d+>>  IntConstant 5
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
 #
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add5:i\d+]] [[Add7:i\d+]] ] loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:     [[PhiZ1:i\d+]] Phi [ [[ArgZ]] [[XorZ:i\d+]] [[PhiZ1]] ]     loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
+## CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add5:i\d+>>,<<Add7:i\d+>>] loop:<<HeaderY:B\d+>>
+## CHECK-DAG:     <<PhiZ1:i\d+>> Phi [<<ArgZ>>,<<XorZ:i\d+>>,<<PhiZ1>>]     loop:<<HeaderY>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
 #
-#                               ### Inner loop ###
-# CHECK-DAG:     [[PhiZ2:i\d+]] Phi [ [[PhiZ1]] [[XorZ]] ]                   loop_header:[[HeaderZ:B\d+]]
-# CHECK-DAG:     [[XorZ]]       Xor [ [[PhiZ2]] [[Cst1]] ]                   loop_header:[[HeaderZ]]
-# CHECK-DAG:     [[CondZ:z\d+]] Equal [ [[XorZ]] [[Cst0]] ]                  loop_header:[[HeaderZ]]
-# CHECK-DAG:                    If [ [[CondZ]] ]                             loop_header:[[HeaderZ]]
+#                                ### Inner loop ###
+## CHECK-DAG:     <<PhiZ2:i\d+>> Phi [<<PhiZ1>>,<<XorZ>>]                   loop:<<HeaderZ:B\d+>>
+## CHECK-DAG:     <<XorZ>>       Xor [<<PhiZ2>>,<<Cst1>>]                   loop:<<HeaderZ>>
+## CHECK-DAG:     <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>]                  loop:<<HeaderZ>>
+## CHECK-DAG:                    If [<<CondZ>>]                             loop:<<HeaderZ>>
 #
-# CHECK-DAG:     [[Add5]]       Add [ [[PhiX]] [[Cst5]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+## CHECK-DAG:     <<Add5>>       Add [<<PhiX>>,<<Cst5>>]                    loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
+## CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
-# CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (after)
-# CHECK-DAG:     [[ArgX:i\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgY:z\d+]]  ParameterValue
-# CHECK-DAG:     [[ArgZ:z\d+]]  ParameterValue
-# CHECK-DAG:     [[Cst0:i\d+]]  IntConstant 0
-# CHECK-DAG:     [[Cst1:i\d+]]  IntConstant 1
-# CHECK-DAG:     [[Cst7:i\d+]]  IntConstant 7
+## CHECK-START: int TestCase.testInnerLoop(int, boolean, boolean) dead_code_elimination_final (after)
+## CHECK-DAG:     <<ArgX:i\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgY:z\d+>>  ParameterValue
+## CHECK-DAG:     <<ArgZ:z\d+>>  ParameterValue
+## CHECK-DAG:     <<Cst0:i\d+>>  IntConstant 0
+## CHECK-DAG:     <<Cst1:i\d+>>  IntConstant 1
+## CHECK-DAG:     <<Cst7:i\d+>>  IntConstant 7
 #
-# CHECK-DAG:     [[PhiX:i\d+]]  Phi [ [[ArgX]] [[Add7:i\d+]] ]               loop_header:[[HeaderY:B\d+]]
-# CHECK-DAG:     [[PhiZ1:i\d+]] Phi [ [[ArgZ]] [[PhiZ1]] ]                   loop_header:[[HeaderY]]
-# CHECK-DAG:                    If [ [[ArgY]] ]                              loop_header:[[HeaderY]]
-# CHECK-DAG:     [[Add7]]       Add [ [[PhiX]] [[Cst7]] ]                    loop_header:[[HeaderY]]
+## CHECK-DAG:     <<PhiX:i\d+>>  Phi [<<ArgX>>,<<Add7:i\d+>>]               loop:<<HeaderY:B\d+>>
+## CHECK-DAG:                    If [<<ArgY>>]                              loop:<<HeaderY>>
+## CHECK-DAG:     <<Add7>>       Add [<<PhiX>>,<<Cst7>>]                    loop:<<HeaderY>>
 #
-#                               ### Inner loop ###
-# CHECK-DAG:     [[PhiZ2:i\d+]] Phi [ [[PhiZ1]] [[XorZ:i\d+]] ]              loop_header:[[HeaderZ:B\d+]]
-# CHECK-DAG:     [[XorZ]]       Xor [ [[PhiZ2]] [[Cst1]] ]                   loop_header:[[HeaderZ]]
-# CHECK-DAG:     [[CondZ:z\d+]] Equal [ [[XorZ]] [[Cst0]] ]                  loop_header:[[HeaderZ]]
-# CHECK-DAG:                    If [ [[CondZ]] ]                             loop_header:[[HeaderZ]]
+#                                ### Inner loop ###
+## CHECK-DAG:     <<PhiZ:i\d+>>  Phi [<<ArgZ>>,<<XorZ:i\d+>>]               loop:<<HeaderZ:B\d+>>
+## CHECK-DAG:     <<XorZ>>       Xor [<<PhiZ>>,<<Cst1>>]                    loop:<<HeaderZ>>
+## CHECK-DAG:     <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>]                  loop:<<HeaderZ>>
+## CHECK-DAG:                    If [<<CondZ>>]                             loop:<<HeaderZ>>
 #
-# CHECK-DAG:                    Return [ [[PhiX]] ]                          loop_header:null
+## CHECK-DAG:                    Return [<<PhiX>>]                          loop:none
 
 .method public static testInnerLoop(IZZ)I
   .registers 4
diff --git a/test/486-checker-must-do-null-check/expected.txt b/test/486-checker-must-do-null-check/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/486-checker-must-do-null-check/expected.txt
diff --git a/test/486-checker-must-do-null-check/info.txt b/test/486-checker-must-do-null-check/info.txt
new file mode 100644
index 0000000..494ff1c
--- /dev/null
+++ b/test/486-checker-must-do-null-check/info.txt
@@ -0,0 +1 @@
+Verifies MustDoNullCheck() on InstanceOf and CheckCast
diff --git a/test/486-checker-must-do-null-check/src/Main.java b/test/486-checker-must-do-null-check/src/Main.java
new file mode 100644
index 0000000..e8ff6a4
--- /dev/null
+++ b/test/486-checker-must-do-null-check/src/Main.java
@@ -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.
+ */
+
+public class Main {
+  /// CHECK-START: void Main.InstanceOfPreChecked(java.lang.Object) instruction_simplifier (after)
+  /// CHECK:       InstanceOf must_do_null_check:false
+  public void InstanceOfPreChecked(Object o) throws Exception {
+    o.toString();
+    if (o instanceof Main) {
+      throw new Exception();
+    }
+  }
+
+  /// CHECK-START: void Main.InstanceOf(java.lang.Object) instruction_simplifier (after)
+  /// CHECK:       InstanceOf must_do_null_check:true
+  public void InstanceOf(Object o) throws Exception {
+    if (o instanceof Main) {
+      throw new Exception();
+    }
+  }
+
+  /// CHECK-START: void Main.CheckCastPreChecked(java.lang.Object) instruction_simplifier (after)
+  /// CHECK:       CheckCast must_do_null_check:false
+  public void CheckCastPreChecked(Object o) {
+    o.toString();
+    ((Main)o).$noinline$Bar();
+  }
+
+  /// CHECK-START: void Main.CheckCast(java.lang.Object) instruction_simplifier (after)
+  /// CHECK:       CheckCast must_do_null_check:true
+  public void CheckCast(Object o) {
+    ((Main)o).$noinline$Bar();
+  }
+
+  void $noinline$Bar() {throw new RuntimeException();}
+
+  public static void main(String[] sa) {
+    Main t = new Main();
+  }
+}
diff --git a/test/487-checker-inline-calls/expected.txt b/test/487-checker-inline-calls/expected.txt
new file mode 100644
index 0000000..2230482
--- /dev/null
+++ b/test/487-checker-inline-calls/expected.txt
@@ -0,0 +1,6 @@
+java.lang.Error
+	at Main.inline3(Main.java:48)
+	at Main.inline2(Main.java:44)
+	at Main.inline1(Main.java:40)
+	at Main.doTopCall(Main.java:36)
+	at Main.main(Main.java:21)
diff --git a/test/487-checker-inline-calls/info.txt b/test/487-checker-inline-calls/info.txt
new file mode 100644
index 0000000..9f5df8b
--- /dev/null
+++ b/test/487-checker-inline-calls/info.txt
@@ -0,0 +1 @@
+Checker test for ensuring inlining preserves stack traces.
diff --git a/test/487-checker-inline-calls/src/Main.java b/test/487-checker-inline-calls/src/Main.java
new file mode 100644
index 0000000..70384d5
--- /dev/null
+++ b/test/487-checker-inline-calls/src/Main.java
@@ -0,0 +1,50 @@
+/*
+ * 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 main(String[] args) {
+    try {
+      doTopCall();
+    } catch (Error e) {
+      e.printStackTrace();
+    }
+  }
+
+  // We check that some inlining happened by checking the
+  // method index of the called method.
+
+  /// CHECK-START: void Main.doTopCall() inliner (before)
+  /// CHECK:     InvokeStaticOrDirect dex_file_index:2
+
+  /// CHECK-START: void Main.doTopCall() inliner (after)
+  /// CHECK:     InvokeStaticOrDirect dex_file_index:4
+  public static void doTopCall() {
+    inline1();
+  }
+
+  public static void inline1() {
+    inline2();
+  }
+
+  public static void inline2() {
+    inline3();
+  }
+
+  public static void inline3() {
+    throw new Error();
+  }
+}
diff --git a/test/488-checker-inline-recursive-calls/expected.txt b/test/488-checker-inline-recursive-calls/expected.txt
new file mode 100644
index 0000000..f615d3a
--- /dev/null
+++ b/test/488-checker-inline-recursive-calls/expected.txt
@@ -0,0 +1,7 @@
+java.lang.Error
+	at Main.inline3(Main.java:51)
+	at Main.doTopCall(Main.java:37)
+	at Main.inline2(Main.java:47)
+	at Main.inline1(Main.java:43)
+	at Main.doTopCall(Main.java:34)
+	at Main.main(Main.java:21)
diff --git a/test/488-checker-inline-recursive-calls/info.txt b/test/488-checker-inline-recursive-calls/info.txt
new file mode 100644
index 0000000..9abd93c
--- /dev/null
+++ b/test/488-checker-inline-recursive-calls/info.txt
@@ -0,0 +1 @@
+Checker test for inlining calls that in turn call the outer method.
diff --git a/test/488-checker-inline-recursive-calls/src/Main.java b/test/488-checker-inline-recursive-calls/src/Main.java
new file mode 100644
index 0000000..c1f25b3
--- /dev/null
+++ b/test/488-checker-inline-recursive-calls/src/Main.java
@@ -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.
+ */
+
+
+public class Main {
+  public static void main(String[] args) {
+    try {
+      doTopCall(true);
+    } catch (Error e) {
+      e.printStackTrace();
+    }
+  }
+
+  /// CHECK-START: void Main.doTopCall(boolean) inliner (before)
+  /// CHECK-NOT:   InvokeStaticOrDirect recursive:true
+
+  /// CHECK-START: void Main.doTopCall(boolean) inliner (after)
+  /// CHECK:       InvokeStaticOrDirect recursive:true
+  public static void doTopCall(boolean first_call) {
+    if (first_call) {
+      inline1();
+    } else {
+      while (true) {
+        inline3();
+      }
+    }
+  }
+
+  public static void inline1() {
+    inline2();
+  }
+
+  public static void inline2() {
+    doTopCall(false);
+  }
+
+  public static void inline3() {
+    throw new Error();
+  }
+}
diff --git a/test/489-current-method-regression/expected.txt b/test/489-current-method-regression/expected.txt
new file mode 100644
index 0000000..cced94c
--- /dev/null
+++ b/test/489-current-method-regression/expected.txt
@@ -0,0 +1 @@
+In bar
diff --git a/test/489-current-method-regression/info.txt b/test/489-current-method-regression/info.txt
new file mode 100644
index 0000000..da03a4f
--- /dev/null
+++ b/test/489-current-method-regression/info.txt
@@ -0,0 +1,2 @@
+Regression test for a crash due to the removal
+of HCurrentMethod from the optimizing graph.
diff --git a/test/489-current-method-regression/src/Main.java b/test/489-current-method-regression/src/Main.java
new file mode 100644
index 0000000..7d102f5
--- /dev/null
+++ b/test/489-current-method-regression/src/Main.java
@@ -0,0 +1,34 @@
+/*
+ * 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 main(String[] args) {
+    System.out.println(foo(1, 0));
+  }
+
+  public static String foo(int a, int b) {
+    if (a == 42) {
+      // The class loading will be seen as dead code by
+      // the optimizer.
+      Class c = Main.class;
+    }
+    return new Main().bar();
+  }
+
+  public String bar() {
+    return "In bar";
+  }
+}
diff --git a/test/490-checker-inline/expected.txt b/test/490-checker-inline/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/490-checker-inline/expected.txt
diff --git a/test/490-checker-inline/info.txt b/test/490-checker-inline/info.txt
new file mode 100644
index 0000000..0e42d77
--- /dev/null
+++ b/test/490-checker-inline/info.txt
@@ -0,0 +1 @@
+Check that we inline virtual and interface calls.
diff --git a/test/490-checker-inline/src/Main.java b/test/490-checker-inline/src/Main.java
new file mode 100644
index 0000000..21a0189
--- /dev/null
+++ b/test/490-checker-inline/src/Main.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+interface Itf {
+  public void invokeInterface();
+}
+
+public class Main implements Itf {
+
+  public void invokeInterface () {
+  }
+
+  public void invokeVirtual() {
+  }
+
+  public static Main createMain() {
+    return new Main();
+  }
+
+  public static Itf createItf() {
+    return new Main();
+  }
+
+  /// CHECK-START: void Main.testMethod() inliner (before)
+  /// CHECK-DAG:     InvokeVirtual
+  /// CHECK-DAG:     InvokeInterface
+
+  /// CHECK-START: void Main.testMethod() inliner (after)
+  /// CHECK-NOT:     Invoke{{.*}}
+
+  public static void testMethod() {
+    createMain().invokeVirtual();
+    createItf().invokeInterface();
+  }
+
+  public static void main(String[] args) {
+    testMethod();
+  }
+}
diff --git a/test/491-current-method/expected.txt b/test/491-current-method/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/491-current-method/expected.txt
diff --git a/test/491-current-method/info.txt b/test/491-current-method/info.txt
new file mode 100644
index 0000000..e9678da
--- /dev/null
+++ b/test/491-current-method/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to
+crash in the presence of slow paths with intrinsics.
diff --git a/test/491-current-method/src/Main.java b/test/491-current-method/src/Main.java
new file mode 100644
index 0000000..87ef052
--- /dev/null
+++ b/test/491-current-method/src/Main.java
@@ -0,0 +1,70 @@
+/*
+ * 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 Main {
+
+  // The code below is written in a way that will crash
+  // the generated code at the time of submission of this test.
+  // Therefore, changes to the register allocator may
+  // affect the reproducibility of the crash.
+  public static void $noinline$foo(int a, int b, int c) {
+    // The division on x86 will take EAX and EDX, leaving ECX
+    // to put the ART current method.
+    c = c / 42;
+    // We use the empty string for forcing the slow path.
+    // The slow path for charAt when it is intrinsified, will
+    // move the parameter to ECX, and therefore overwrite the ART
+    // current method.
+    "".charAt(c);
+
+    // Do more things in the method to prevent inlining.
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+    c = c / 42;
+    "".charAt(c);
+  }
+
+  public static void main(String[] args) {
+    boolean didThrow = false;
+    try {
+      $noinline$foo(1, 2, 3);
+    } catch (Throwable e) {
+      didThrow = true;
+    }
+
+    if (!didThrow) {
+      throw new Error("Expected an exception from charAt");
+    }
+  }
+}
diff --git a/test/492-checker-inline-invoke-interface/expected.txt b/test/492-checker-inline-invoke-interface/expected.txt
index e69de29..b0014d7 100644
--- a/test/492-checker-inline-invoke-interface/expected.txt
+++ b/test/492-checker-inline-invoke-interface/expected.txt
@@ -0,0 +1,5 @@
+Hello from clinit
+java.lang.Exception
+	at ForceStatic.<clinit>(Main.java:24)
+	at Main.$inline$foo(Main.java:31)
+	at Main.main(Main.java:48)
diff --git a/test/492-checker-inline-invoke-interface/src/Main.java b/test/492-checker-inline-invoke-interface/src/Main.java
index 9063af2..9a45485 100644
--- a/test/492-checker-inline-invoke-interface/src/Main.java
+++ b/test/492-checker-inline-invoke-interface/src/Main.java
@@ -18,10 +18,31 @@
   public void $inline$foo();
 }
 
+class ForceStatic {
+  static {
+    System.out.println("Hello from clinit");
+    new Exception().printStackTrace();
+  }
+  static int field;
+}
+
 public class Main implements Itf {
   public void $inline$foo() {
+    int a = ForceStatic.field;
   }
 
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
+  /// CHECK:           InvokeStaticOrDirect
+  /// CHECK:           InvokeStaticOrDirect
+
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
+  /// CHECK-NOT:       ClinitCheck
+
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+  /// CHECK-NOT:       InvokeStaticOrDirect
+
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+  /// CHECK:           ClinitCheck
   public static void main(String[] args) {
     Itf itf = new Main();
     itf.$inline$foo();
diff --git a/test/493-checker-inline-invoke-interface/expected.txt b/test/493-checker-inline-invoke-interface/expected.txt
new file mode 100644
index 0000000..93620a6
--- /dev/null
+++ b/test/493-checker-inline-invoke-interface/expected.txt
@@ -0,0 +1,5 @@
+Hello from clinit
+java.lang.Exception
+	at ForceStatic.<clinit>(Main.java:24)
+	at Main.foo(Main.java:31)
+	at Main.main(Main.java:42)
diff --git a/test/493-checker-inline-invoke-interface/info.txt b/test/493-checker-inline-invoke-interface/info.txt
new file mode 100644
index 0000000..bac9c82
--- /dev/null
+++ b/test/493-checker-inline-invoke-interface/info.txt
@@ -0,0 +1,2 @@
+Check that we can optimize interface calls without
+requiring the verifier to sharpen them.
diff --git a/test/493-checker-inline-invoke-interface/src/Main.java b/test/493-checker-inline-invoke-interface/src/Main.java
new file mode 100644
index 0000000..44b727f
--- /dev/null
+++ b/test/493-checker-inline-invoke-interface/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+interface Itf {
+  public void foo();
+}
+
+class ForceStatic {
+  static {
+    System.out.println("Hello from clinit");
+    new Exception().printStackTrace();
+  }
+  static int field;
+}
+
+public class Main implements Itf {
+  public void foo() {
+    int a = ForceStatic.field;
+  }
+
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
+  /// CHECK:           InvokeStaticOrDirect
+  /// CHECK:           InvokeInterface
+
+  /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+  /// CHECK-NOT:       Invoke{{.*}}
+  public static void main(String[] args) {
+    Itf itf = bar();
+    itf.foo();
+  }
+
+  public static Itf bar() {
+    return new Main();
+  }
+}
diff --git a/test/494-checker-instanceof-tests/expected.txt b/test/494-checker-instanceof-tests/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/494-checker-instanceof-tests/expected.txt
diff --git a/test/494-checker-instanceof-tests/info.txt b/test/494-checker-instanceof-tests/info.txt
new file mode 100644
index 0000000..59e20bd
--- /dev/null
+++ b/test/494-checker-instanceof-tests/info.txt
@@ -0,0 +1 @@
+Checker test for optimizations on instanceof.
diff --git a/test/494-checker-instanceof-tests/src/Main.java b/test/494-checker-instanceof-tests/src/Main.java
new file mode 100644
index 0000000..bff9c72
--- /dev/null
+++ b/test/494-checker-instanceof-tests/src/Main.java
@@ -0,0 +1,203 @@
+/*
+ * 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 $inline$classTypeTest(Object o) {
+    return o instanceof SubMain;
+  }
+
+  public static boolean $inline$interfaceTypeTest(Object o) {
+    return o instanceof Itf;
+  }
+
+  public static SubMain subMain;
+  public static Main mainField;
+  public static Unrelated unrelatedField;
+  public static FinalUnrelated finalUnrelatedField;
+
+  /// CHECK-START: boolean Main.classTypeTestNull() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean classTypeTestNull() {
+    return $inline$classTypeTest(null);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestExactMain() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean classTypeTestExactMain() {
+    return $inline$classTypeTest(new Main());
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestExactSubMain() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 1
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean classTypeTestExactSubMain() {
+    return $inline$classTypeTest(new SubMain());
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestSubMainOrNull() register (after)
+  /// CHECK-DAG: <<Value:z\d+>> NotEqual
+  /// CHECK-DAG:                Return [<<Value>>]
+  public static boolean classTypeTestSubMainOrNull() {
+    return $inline$classTypeTest(subMain);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestMainOrNull() register (after)
+  /// CHECK-DAG: <<Value:z\d+>> InstanceOf
+  /// CHECK-DAG:                Return [<<Value>>]
+  public static boolean classTypeTestMainOrNull() {
+    return $inline$classTypeTest(mainField);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestUnrelated() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean classTypeTestUnrelated() {
+    return $inline$classTypeTest(unrelatedField);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestFinalUnrelated() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean classTypeTestFinalUnrelated() {
+    return $inline$classTypeTest(finalUnrelatedField);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestNull() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean interfaceTypeTestNull() {
+    return $inline$interfaceTypeTest(null);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestExactMain() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean interfaceTypeTestExactMain() {
+    return $inline$interfaceTypeTest(new Main());
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestExactSubMain() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 1
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean interfaceTypeTestExactSubMain() {
+    return $inline$interfaceTypeTest(new SubMain());
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestSubMainOrNull() register (after)
+  /// CHECK-DAG: <<Value:z\d+>> NotEqual
+  /// CHECK-DAG:                Return [<<Value>>]
+  public static boolean interfaceTypeTestSubMainOrNull() {
+    return $inline$interfaceTypeTest(subMain);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestMainOrNull() register (after)
+  /// CHECK-DAG: <<Value:z\d+>> InstanceOf
+  /// CHECK-DAG:                Return [<<Value>>]
+  public static boolean interfaceTypeTestMainOrNull() {
+    return $inline$interfaceTypeTest(mainField);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestUnrelated() register (after)
+  /// CHECK-DAG: <<Value:z\d+>> InstanceOf
+  /// CHECK-DAG:                Return [<<Value>>]
+  public static boolean interfaceTypeTestUnrelated() {
+    // This method is the main difference between doing an instanceof on an interface
+    // or a class. We have to keep the instanceof in case a subclass of Unrelated
+    // implements the interface.
+    return $inline$interfaceTypeTest(unrelatedField);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestFinalUnrelated() register (after)
+  /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+  /// CHECK-DAG:                Return [<<Const>>]
+  public static boolean interfaceTypeTestFinalUnrelated() {
+    return $inline$interfaceTypeTest(finalUnrelatedField);
+  }
+
+  public static void expect(boolean expected, boolean actual) {
+    if (expected != actual) {
+      throw new Error("Unexpected result");
+    }
+  }
+
+  public static void main(String[] args) {
+    expect(false, classTypeTestNull());
+    expect(false, classTypeTestExactMain());
+    expect(true, classTypeTestExactSubMain());
+
+    subMain = null;
+    expect(false, classTypeTestSubMainOrNull());
+    subMain = new SubMain();
+    expect(true, classTypeTestSubMainOrNull());
+
+    mainField = null;
+    expect(false, classTypeTestMainOrNull());
+    mainField = new Main();
+    expect(false, classTypeTestMainOrNull());
+    mainField = new SubMain();
+    expect(true, classTypeTestMainOrNull());
+
+    unrelatedField = null;
+    expect(false, classTypeTestUnrelated());
+    unrelatedField = new Unrelated();
+    expect(false, classTypeTestUnrelated());
+
+    finalUnrelatedField = null;
+    expect(false, classTypeTestFinalUnrelated());
+    finalUnrelatedField = new FinalUnrelated();
+    expect(false, classTypeTestFinalUnrelated());
+
+    expect(false, interfaceTypeTestNull());
+    expect(false, interfaceTypeTestExactMain());
+    expect(true, interfaceTypeTestExactSubMain());
+
+    subMain = null;
+    expect(false, interfaceTypeTestSubMainOrNull());
+    subMain = new SubMain();
+    expect(true, interfaceTypeTestSubMainOrNull());
+
+    mainField = null;
+    expect(false, interfaceTypeTestMainOrNull());
+    mainField = new Main();
+    expect(false, interfaceTypeTestMainOrNull());
+    mainField = new SubMain();
+    expect(true, interfaceTypeTestMainOrNull());
+
+    unrelatedField = null;
+    expect(false, interfaceTypeTestUnrelated());
+    unrelatedField = new Unrelated();
+    expect(false, interfaceTypeTestUnrelated());
+
+    finalUnrelatedField = null;
+    expect(false, interfaceTypeTestFinalUnrelated());
+    finalUnrelatedField = new FinalUnrelated();
+    expect(false, interfaceTypeTestFinalUnrelated());
+  }
+}
+
+interface Itf {
+}
+
+class SubMain extends Main implements Itf {
+}
+
+class Unrelated {
+}
+
+final class FinalUnrelated {
+}
diff --git a/test/495-checker-checkcast-tests/expected.txt b/test/495-checker-checkcast-tests/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/495-checker-checkcast-tests/expected.txt
diff --git a/test/495-checker-checkcast-tests/info.txt b/test/495-checker-checkcast-tests/info.txt
new file mode 100644
index 0000000..4517b22
--- /dev/null
+++ b/test/495-checker-checkcast-tests/info.txt
@@ -0,0 +1 @@
+Checker tests for optimizations on checkcast.
diff --git a/test/495-checker-checkcast-tests/src/Main.java b/test/495-checker-checkcast-tests/src/Main.java
new file mode 100644
index 0000000..aa6d5a7
--- /dev/null
+++ b/test/495-checker-checkcast-tests/src/Main.java
@@ -0,0 +1,204 @@
+/*
+ * 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 $inline$classTypeTest(Object o) {
+    return ((SubMain)o) == o;
+  }
+
+  public static boolean $inline$interfaceTypeTest(Object o) {
+    return ((Itf)o) == o;
+  }
+
+  public static SubMain subMain;
+  public static Main mainField;
+  public static Unrelated unrelatedField;
+  public static FinalUnrelated finalUnrelatedField;
+
+  /// CHECK-START: boolean Main.classTypeTestNull() register (after)
+  /// CHECK-NOT: CheckCast
+  public static boolean classTypeTestNull() {
+    return $inline$classTypeTest(null);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestExactMain() register (after)
+  /// CHECK: CheckCast
+  public static boolean classTypeTestExactMain() {
+    return $inline$classTypeTest(new Main());
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestExactSubMain() register (after)
+  /// CHECK-NOT: CheckCast
+  public static boolean classTypeTestExactSubMain() {
+    return $inline$classTypeTest(new SubMain());
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestSubMainOrNull() register (after)
+  /// CHECK-NOT: CheckCast
+  public static boolean classTypeTestSubMainOrNull() {
+    return $inline$classTypeTest(subMain);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestMainOrNull() register (after)
+  /// CHECK: CheckCast
+  public static boolean classTypeTestMainOrNull() {
+    return $inline$classTypeTest(mainField);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestUnrelated() register (after)
+  /// CHECK: CheckCast
+  public static boolean classTypeTestUnrelated() {
+    return $inline$classTypeTest(unrelatedField);
+  }
+
+  /// CHECK-START: boolean Main.classTypeTestFinalUnrelated() register (after)
+  /// CHECK: CheckCast
+  public static boolean classTypeTestFinalUnrelated() {
+    return $inline$classTypeTest(finalUnrelatedField);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestNull() register (after)
+  /// CHECK-NOT: CheckCast
+  public static boolean interfaceTypeTestNull() {
+    return $inline$interfaceTypeTest(null);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestExactMain() register (after)
+  /// CHECK: CheckCast
+  public static boolean interfaceTypeTestExactMain() {
+    return $inline$interfaceTypeTest(new Main());
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestExactSubMain() register (after)
+  /// CHECK-NOT: CheckCast
+  public static boolean interfaceTypeTestExactSubMain() {
+    return $inline$interfaceTypeTest(new SubMain());
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestSubMainOrNull() register (after)
+  /// CHECK-NOT: CheckCast
+  public static boolean interfaceTypeTestSubMainOrNull() {
+    return $inline$interfaceTypeTest(subMain);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestMainOrNull() register (after)
+  /// CHECK: CheckCast
+  public static boolean interfaceTypeTestMainOrNull() {
+    return $inline$interfaceTypeTest(mainField);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestUnrelated() register (after)
+  /// CHECK: CheckCast
+  public static boolean interfaceTypeTestUnrelated() {
+    return $inline$interfaceTypeTest(unrelatedField);
+  }
+
+  /// CHECK-START: boolean Main.interfaceTypeTestFinalUnrelated() register (after)
+  /// CHECK: CheckCast
+  public static boolean interfaceTypeTestFinalUnrelated() {
+    return $inline$interfaceTypeTest(finalUnrelatedField);
+  }
+
+  public static void main(String[] args) {
+    classTypeTestNull();
+    try {
+      classTypeTestExactMain();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+    classTypeTestExactSubMain();
+
+    subMain = null;
+    classTypeTestSubMainOrNull();
+    subMain = new SubMain();
+    classTypeTestSubMainOrNull();
+
+    mainField = null;
+    classTypeTestMainOrNull();
+    mainField = new Main();
+    try {
+      classTypeTestMainOrNull();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+    mainField = new SubMain();
+    classTypeTestMainOrNull();
+
+    unrelatedField = null;
+    classTypeTestUnrelated();
+    unrelatedField = new Unrelated();
+    try {
+      classTypeTestUnrelated();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+
+    finalUnrelatedField = null;
+    classTypeTestFinalUnrelated();
+    finalUnrelatedField = new FinalUnrelated();
+    try {
+      classTypeTestFinalUnrelated();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+
+    interfaceTypeTestNull();
+    try {
+      interfaceTypeTestExactMain();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+    interfaceTypeTestExactSubMain();
+
+    subMain = null;
+    interfaceTypeTestSubMainOrNull();
+    subMain = new SubMain();
+    interfaceTypeTestSubMainOrNull();
+
+    mainField = null;
+    interfaceTypeTestMainOrNull();
+    mainField = new Main();
+    try {
+      interfaceTypeTestMainOrNull();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+    mainField = new SubMain();
+    interfaceTypeTestMainOrNull();
+
+    unrelatedField = null;
+    interfaceTypeTestUnrelated();
+    unrelatedField = new Unrelated();
+    try {
+      interfaceTypeTestUnrelated();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+
+    finalUnrelatedField = null;
+    interfaceTypeTestFinalUnrelated();
+    finalUnrelatedField = new FinalUnrelated();
+    try {
+      interfaceTypeTestFinalUnrelated();
+      throw new Error("ClassCastException expected");
+    } catch (ClassCastException e) {}
+  }
+}
+
+interface Itf {
+}
+
+class SubMain extends Main implements Itf {
+}
+
+class Unrelated {
+}
+
+final class FinalUnrelated {
+}
diff --git a/test/496-checker-inlining-and-class-loader/expected.txt b/test/496-checker-inlining-and-class-loader/expected.txt
new file mode 100644
index 0000000..312c28f
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/expected.txt
@@ -0,0 +1,4 @@
+Request for LoadedByMyClassLoader
+Request for FirstSeenByMyClassLoader
+In between the two calls.
+In $noinline$bar
diff --git a/test/496-checker-inlining-and-class-loader/info.txt b/test/496-checker-inlining-and-class-loader/info.txt
new file mode 100644
index 0000000..aa4b256
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/info.txt
@@ -0,0 +1,2 @@
+Regression test to ensure compilers preserve JLS
+semantics of class loading.
diff --git a/test/496-checker-inlining-and-class-loader/src/FirstSeenByMyClassLoader.java b/test/496-checker-inlining-and-class-loader/src/FirstSeenByMyClassLoader.java
new file mode 100644
index 0000000..e97b4e3
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/src/FirstSeenByMyClassLoader.java
@@ -0,0 +1,26 @@
+/*
+ * 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 FirstSeenByMyClassLoader {
+  public static void $inline$bar() {
+  }
+
+  public static void $noinline$bar() {
+    try {
+      System.out.println("In $noinline$bar");
+    } catch (Throwable t) { /* Ignore */ }
+  }
+}
diff --git a/test/496-checker-inlining-and-class-loader/src/Main.java b/test/496-checker-inlining-and-class-loader/src/Main.java
new file mode 100644
index 0000000..39c031a
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/src/Main.java
@@ -0,0 +1,116 @@
+/*
+ * 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.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+class MyClassLoader extends ClassLoader {
+  MyClassLoader() throws Exception {
+    super(MyClassLoader.class.getClassLoader());
+
+    // Some magic to get access to the pathList field of BaseDexClassLoader.
+    ClassLoader loader = getClass().getClassLoader();
+    Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
+    Field f = baseDexClassLoader.getDeclaredField("pathList");
+    f.setAccessible(true);
+    Object pathList = f.get(loader);
+
+    // Some magic to get access to the dexField field of pathList.
+    f = pathList.getClass().getDeclaredField("dexElements");
+    f.setAccessible(true);
+    dexElements = (Object[]) f.get(pathList);
+    dexFileField = dexElements[0].getClass().getDeclaredField("dexFile");
+    dexFileField.setAccessible(true);
+  }
+
+  Object[] dexElements;
+  Field dexFileField;
+
+  protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
+    System.out.println("Request for " + className);
+
+    // We're only going to handle LoadedByMyClassLoader.
+    if (className != "LoadedByMyClassLoader") {
+      return getParent().loadClass(className);
+    }
+
+    // Mimic what DexPathList.findClass is doing.
+    try {
+      for (Object element : dexElements) {
+        Object dex = dexFileField.get(element);
+        Method method = dex.getClass().getDeclaredMethod(
+            "loadClassBinaryName", String.class, ClassLoader.class, List.class);
+
+        if (dex != null) {
+          Class clazz = (Class)method.invoke(dex, className, this, null);
+          if (clazz != null) {
+            return clazz;
+          }
+        }
+      }
+    } catch (Exception e) { /* Ignore */ }
+    return null;
+  }
+}
+
+class LoadedByMyClassLoader {
+  /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (before)
+  /// CHECK:      LoadClass
+  /// CHECK-NEXT: ClinitCheck
+  /// CHECK-NEXT: InvokeStaticOrDirect
+  /// CHECK-NEXT: LoadClass
+  /// CHECK-NEXT: ClinitCheck
+  /// CHECK-NEXT: StaticFieldGet
+  /// CHECK-NEXT: LoadString
+  /// CHECK-NEXT: NullCheck
+  /// CHECK-NEXT: InvokeVirtual
+
+  /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (after)
+  /// CHECK:      LoadClass
+  /// CHECK-NEXT: ClinitCheck
+                /* We inlined FirstSeenByMyClassLoader.$inline$bar */
+  /// CHECK-NEXT: LoadClass
+  /// CHECK-NEXT: ClinitCheck
+  /// CHECK-NEXT: StaticFieldGet
+  /// CHECK-NEXT: LoadString
+  /// CHECK-NEXT: NullCheck
+  /// CHECK-NEXT: InvokeVirtual
+
+  /// CHECK-START: void LoadedByMyClassLoader.bar() register (before)
+                /* Load and initialize FirstSeenByMyClassLoader */
+  /// CHECK:      LoadClass gen_clinit_check:true
+                /* Load and initialize System */
+  /// CHECK-NEXT: LoadClass gen_clinit_check:true
+  /// CHECK-NEXT: StaticFieldGet
+  /// CHECK-NEXT: LoadString
+  /// CHECK-NEXT: NullCheck
+  /// CHECK-NEXT: InvokeVirtual
+  public static void bar() {
+    FirstSeenByMyClassLoader.$inline$bar();
+    System.out.println("In between the two calls.");
+    FirstSeenByMyClassLoader.$noinline$bar();
+  }
+}
+
+public class Main {
+  public static void main(String[] args) throws Exception {
+    MyClassLoader o = new MyClassLoader();
+    Class foo = o.loadClass("LoadedByMyClassLoader");
+    Method m = foo.getDeclaredMethod("bar");
+    m.invoke(null);
+  }
+}
diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc
new file mode 100644
index 0000000..f9b33a2
--- /dev/null
+++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc
@@ -0,0 +1,46 @@
+/*
+ * 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 "art_method-inl.h"
+#include "jni.h"
+#include "scoped_thread_state_change.h"
+#include "stack.h"
+#include "thread.h"
+
+namespace art {
+
+namespace {
+
+extern "C" JNIEXPORT jobject JNICALL Java_Main_cloneResolvedMethods(JNIEnv*, jclass, jclass cls) {
+  ScopedObjectAccess soa(Thread::Current());
+  return soa.Vm()->AddGlobalRef(
+      soa.Self(),
+      soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods()->Clone(soa.Self()));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_restoreResolvedMethods(
+    JNIEnv*, jclass, jclass cls, jobject old_cache) {
+  ScopedObjectAccess soa(Thread::Current());
+  mirror::PointerArray* now = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods();
+  mirror::PointerArray* old = soa.Decode<mirror::PointerArray*>(old_cache);
+  for (size_t i = 0, e = old->GetLength(); i < e; ++i) {
+    now->SetElementPtrSize(i, old->GetElementPtrSize<void*>(i, sizeof(void*)), sizeof(void*));
+  }
+}
+
+}  // namespace
+
+}  // namespace art
diff --git a/test/497-inlining-and-class-loader/expected.txt b/test/497-inlining-and-class-loader/expected.txt
new file mode 100644
index 0000000..3e1d85e
--- /dev/null
+++ b/test/497-inlining-and-class-loader/expected.txt
@@ -0,0 +1,7 @@
+java.lang.Exception
+	at Main.$noinline$bar(Main.java:127)
+	at Level2.$inline$bar(Level1.java:25)
+	at Level1.$inline$bar(Level1.java:19)
+	at LoadedByMyClassLoader.bar(Main.java:82)
+	at java.lang.reflect.Method.invoke(Native Method)
+	at Main.main(Main.java:101)
diff --git a/test/497-inlining-and-class-loader/info.txt b/test/497-inlining-and-class-loader/info.txt
new file mode 100644
index 0000000..e7f02aa
--- /dev/null
+++ b/test/497-inlining-and-class-loader/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing to ensure it is using
+the correct class loader when walking inlined frames.
diff --git a/test/497-inlining-and-class-loader/src/Level1.java b/test/497-inlining-and-class-loader/src/Level1.java
new file mode 100644
index 0000000..977af83
--- /dev/null
+++ b/test/497-inlining-and-class-loader/src/Level1.java
@@ -0,0 +1,27 @@
+/*
+ * 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 Level1 {
+  public static void $inline$bar() {
+    Level2.$inline$bar();
+  }
+}
+
+class Level2 {
+  public static void $inline$bar() {
+    Main.$noinline$bar();
+  }
+}
diff --git a/test/497-inlining-and-class-loader/src/Main.java b/test/497-inlining-and-class-loader/src/Main.java
new file mode 100644
index 0000000..0f7eb59
--- /dev/null
+++ b/test/497-inlining-and-class-loader/src/Main.java
@@ -0,0 +1,133 @@
+/*
+ * 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.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+class MyClassLoader extends ClassLoader {
+  MyClassLoader() throws Exception {
+    super(MyClassLoader.class.getClassLoader());
+
+    // Some magic to get access to the pathList field of BaseDexClassLoader.
+    ClassLoader loader = getClass().getClassLoader();
+    Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
+    Field f = baseDexClassLoader.getDeclaredField("pathList");
+    f.setAccessible(true);
+    Object pathList = f.get(loader);
+
+    // Some magic to get access to the dexField field of pathList.
+    f = pathList.getClass().getDeclaredField("dexElements");
+    f.setAccessible(true);
+    dexElements = (Object[]) f.get(pathList);
+    dexFileField = dexElements[0].getClass().getDeclaredField("dexFile");
+    dexFileField.setAccessible(true);
+  }
+
+  Object[] dexElements;
+  Field dexFileField;
+
+  static ClassLoader level1ClassLoader;
+
+  protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
+    if (this != level1ClassLoader) {
+      if (className.equals("Level1")) {
+        return level1ClassLoader.loadClass(className);
+      } else if (className.equals("Level2")) {
+        throw new ClassNotFoundException("None of my methods require Level2!");
+      } else if (!className.equals("LoadedByMyClassLoader")) {
+        // We're only going to handle LoadedByMyClassLoader.
+        return getParent().loadClass(className);
+      }
+    } else {
+      if (className != "Level1" && className != "Level2") {
+        return getParent().loadClass(className);
+      }
+    }
+
+    // Mimic what DexPathList.findClass is doing.
+    try {
+      for (Object element : dexElements) {
+        Object dex = dexFileField.get(element);
+        Method method = dex.getClass().getDeclaredMethod(
+            "loadClassBinaryName", String.class, ClassLoader.class, List.class);
+
+        if (dex != null) {
+          Class clazz = (Class)method.invoke(dex, className, this, null);
+          if (clazz != null) {
+            return clazz;
+          }
+        }
+      }
+    } catch (Exception e) { /* Ignore */ }
+    return null;
+  }
+}
+
+class LoadedByMyClassLoader {
+  public static void bar() {
+    Level1.$inline$bar();
+  }
+}
+
+class Main {
+  static {
+    System.loadLibrary("arttest");
+  }
+
+  public static void main(String[] args) throws Exception {
+    // Clone resolved methods, to restore the original version just
+    // before we walk the stack in $noinline$bar.
+    savedResolvedMethods = cloneResolvedMethods(Main.class);
+
+    MyClassLoader o = new MyClassLoader();
+    MyClassLoader.level1ClassLoader = new MyClassLoader();
+    Class foo = o.loadClass("LoadedByMyClassLoader");
+    Method m = foo.getDeclaredMethod("bar");
+    try {
+      m.invoke(null);
+    } catch (Error e) { /* Ignore */ }
+  }
+
+  public static void $inline$bar() {
+  }
+
+  public static void $noinline$bar() {
+    try {
+      // Be evil and clear all dex cache entries.
+      Field f = Class.class.getDeclaredField("dexCache");
+      f.setAccessible(true);
+      Object dexCache = f.get(Main.class);
+      f = dexCache.getClass().getDeclaredField("resolvedTypes");
+      f.setAccessible(true);
+      Object[] array = (Object[]) f.get(dexCache);
+      for (int i = 0; i < array.length; i++) {
+        array[i] = null;
+      }
+      restoreResolvedMethods(Main.class, savedResolvedMethods);
+    } catch (Throwable t) { /* Ignore */ }
+
+    // This will walk the stack, trying to resolve methods in it.
+    // Because we cleared dex cache entries, we will have to find
+    // classes again, which require to use the correct class loader
+    // in the presence of inlining.
+    new Exception().printStackTrace();
+  }
+  static Object savedResolvedMethods;
+
+  static native Object cloneResolvedMethods(Class<?> cls);
+  static native void restoreResolvedMethods(Class<?> cls, Object saved);
+}
diff --git a/test/500-instanceof/expected.txt b/test/500-instanceof/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/500-instanceof/expected.txt
diff --git a/test/500-instanceof/info.txt b/test/500-instanceof/info.txt
new file mode 100644
index 0000000..b28756a
--- /dev/null
+++ b/test/500-instanceof/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing which used to be
+too aggresive in removing instanceof checks.
diff --git a/test/500-instanceof/src/Main.java b/test/500-instanceof/src/Main.java
new file mode 100644
index 0000000..80fdb02
--- /dev/null
+++ b/test/500-instanceof/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+interface Itf {
+}
+
+class Foo {
+}
+
+class Main extends Foo implements Itf {
+  public static void main(String[] args) {
+    Itf parent = getParent();
+    if (!(parent instanceof Foo)) {
+      throw new Error("Instanceof should have succeeded");
+    }
+  }
+
+  static Itf getParent() { return new Main(); }
+}
diff --git a/test/507-referrer/src/Main.java b/test/507-referrer/src/Main.java
index d03e0b2..6393f39 100644
--- a/test/507-referrer/src/Main.java
+++ b/test/507-referrer/src/Main.java
@@ -18,7 +18,7 @@
 
 public class Main {
   public static void main(String[] args) {
-    int result = InPackage.foo();
+    int result = InPackage.$inline$foo();
     if (result != 42) {
       throw new Error("Expected 42, got " + result);
     }
diff --git a/test/507-referrer/src/p1/InPackage.java b/test/507-referrer/src/p1/InPackage.java
index 2b11427..162f055 100644
--- a/test/507-referrer/src/p1/InPackage.java
+++ b/test/507-referrer/src/p1/InPackage.java
@@ -17,7 +17,7 @@
 package p1;
 
 public class InPackage {
-  public static int foo() {
+  public static int $inline$foo() {
     return myField;
   }
 
diff --git a/test/508-checker-disassembly/expected.txt b/test/508-checker-disassembly/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/508-checker-disassembly/expected.txt
diff --git a/test/508-checker-disassembly/info.txt b/test/508-checker-disassembly/info.txt
new file mode 100644
index 0000000..4a25b21
--- /dev/null
+++ b/test/508-checker-disassembly/info.txt
@@ -0,0 +1 @@
+Check that inlining disassembly in the .cfg works correctly.
diff --git a/test/508-checker-disassembly/src/Main.java b/test/508-checker-disassembly/src/Main.java
new file mode 100644
index 0000000..29c9374
--- /dev/null
+++ b/test/508-checker-disassembly/src/Main.java
@@ -0,0 +1,29 @@
+/*
+* 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 {
+  // A very simple check that disassembly information has been added to the
+  // graph. We check that sections have been added for the frame entry and a
+  // slow path.
+  /// CHECK-START: int Main.DisassembledFunction(int) disassembly (after)
+  /// CHECK:       FrameEntry
+  /// CHECK:       DivZeroCheckSlowPath{{.*}}
+  public int DisassembledFunction(int arg) {
+    return 7 / arg;
+  }
+
+  public static void main(String[] args) {}
+}
diff --git a/test/510-checker-try-catch/expected.txt b/test/510-checker-try-catch/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/510-checker-try-catch/expected.txt
diff --git a/test/510-checker-try-catch/info.txt b/test/510-checker-try-catch/info.txt
new file mode 100644
index 0000000..9ffcb19
--- /dev/null
+++ b/test/510-checker-try-catch/info.txt
@@ -0,0 +1 @@
+Tests the generation of try/catch blocks in Optimizing.
\ No newline at end of file
diff --git a/test/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
new file mode 100644
index 0000000..2274ba4
--- /dev/null
+++ b/test/510-checker-try-catch/smali/Builder.smali
@@ -0,0 +1,1175 @@
+# 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 LBuilder;
+
+.super Ljava/lang/Object;
+
+# Basic test case with two try blocks and three catch handlers, one of which
+# is shared by the two tries.
+
+## CHECK-START: int Builder.testMultipleTryCatch(int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+## CHECK:  <<Minus2:i\d+>>  IntConstant -2
+## CHECK:  <<Minus3:i\d+>>  IntConstant -3
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BExitTry1:B\d+>>"
+## CHECK:  DivZeroCheck
+
+## CHECK:  name             "<<BAdd:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2:B\d+>>"
+## CHECK:  Add
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BExitTry2:B\d+>>"
+## CHECK:  DivZeroCheck
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>" "<<BCatch3:B\d+>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BCatch1>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BExitTry1>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BCatch2>>"
+## CHECK:  predecessors     "<<BEnterTry2>>" "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus2>>]
+
+## CHECK:  name             "<<BCatch3>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2>>" "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus3>>]
+
+## CHECK:  name             "<<BEnterTry1>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatch1>>" "<<BCatch3>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BAdd>>"
+## CHECK:  xhandlers        "<<BCatch1>>" "<<BCatch3>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BAdd>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch2>>" "<<BCatch3>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch2>>" "<<BCatch3>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testMultipleTryCatch(III)I
+    .registers 3
+
+    :try_start_1
+    div-int/2addr p0, p1
+    :try_end_1
+    .catch Ljava/lang/ArithmeticException; {:try_start_1 .. :try_end_1} :catch_arith
+    .catchall {:try_start_1 .. :try_end_1} :catch_other
+
+    add-int/2addr p0, p0
+
+    :try_start_2
+    div-int/2addr p0, p2
+    :try_end_2
+    .catch Ljava/lang/OutOfMemoryError; {:try_start_2 .. :try_end_2} :catch_mem
+    .catchall {:try_start_2 .. :try_end_2} :catch_other
+
+    :return
+    return p0
+
+    :catch_arith
+    const/4 p0, -0x1
+    goto :return
+
+    :catch_mem
+    const/4 p0, -0x2
+    goto :return
+
+    :catch_other
+    const/4 p0, -0x3
+    goto :return
+.end method
+
+# Test that multiple try-entry blocks are generated if there are multiple entry
+# points into the try block.
+
+## CHECK-START: int Builder.testMultipleEntries(int, int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BIf:B\d+>>"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+
+## CHECK:  name             "<<BIf>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BEnterTry2:B\d+>>" "<<BThen:B\d+>>"
+## CHECK:  If
+
+## CHECK:  name             "<<BThen>>"
+## CHECK:  predecessors     "<<BIf>>"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
+## CHECK:  Div
+
+## 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             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry>>" "<<BCatch:B\d+>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BCatch>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BEnterTry1>>"
+## CHECK:  predecessors     "<<BThen>>"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BIf>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testMultipleEntries(IIII)I
+    .registers 4
+
+    if-eqz p2, :else
+
+    div-int/2addr p0, p1
+
+    :try_start
+    div-int/2addr p0, p2
+
+    :else
+    div-int/2addr p0, p3
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return p0
+
+    :catch_all
+    const/4 p0, -0x1
+    goto :return
+
+.end method
+
+# Test that multiple try-exit blocks are generated if (normal) control flow can
+# jump out of the try block at multiple points.
+
+## CHECK-START: int Builder.testMultipleExits(int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BEnterTry:B\d+>>"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+## CHECK:  <<Minus2:i\d+>>  IntConstant -2
+
+## CHECK:  name             "<<BTry:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry>>"
+## CHECK:  successors       "<<BExitTry1:B\d+>>" "<<BExitTry2:B\d+>>"
+## CHECK:  Div
+## CHECK:  If
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry2>>" "<<BThen:B\d+>>" "<<BCatch:B\d+>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BThen>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BCatch>>"
+## CHECK:  predecessors     "<<BEnterTry>>" "<<BExitTry1>>" "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus2>>]
+
+## CHECK:  name             "<<BEnterTry>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BTry>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BTry>>"
+## CHECK:  successors       "<<BThen>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BTry>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testMultipleExits(II)I
+    .registers 2
+
+    :try_start
+    div-int/2addr p0, p1
+    if-eqz p0, :then
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return p0
+
+    :then
+    const/4 p0, -0x1
+    goto :return
+
+    :catch_all
+    const/4 p0, -0x2
+    goto :return
+.end method
+
+# Test that only one TryBoundary is inserted when an edge connects two different
+# try ranges.
+
+## CHECK-START: int Builder.testSharedBoundary(int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BEnter1:B\d+>>"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+## CHECK:  <<Minus2:i\d+>>  IntConstant -2
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnter1>>"
+## CHECK:  successors       "<<BExit1:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnter2:B\d+>>"
+## CHECK:  successors       "<<BExit2:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExit2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BCatch1>>"
+## CHECK:  predecessors     "<<BEnter1>>" "<<BExit1>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BCatch2>>"
+## CHECK:  predecessors     "<<BEnter2>>" "<<BExit2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus2>>]
+
+## CHECK:  name             "<<BEnter1>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatch1>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BEnter2>>"
+## CHECK:  xhandlers        "<<BCatch1>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnter2>>"
+## CHECK:  predecessors     "<<BExit1>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch2>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch2>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testSharedBoundary(III)I
+    .registers 3
+
+    :try_start_1
+    div-int/2addr p0, p1
+    :try_end_1
+    .catchall {:try_start_1 .. :try_end_1} :catch_all_1
+
+    :try_start_2
+    div-int/2addr p0, p2
+    :try_end_2
+    .catchall {:try_start_2 .. :try_end_2} :catch_all_2
+
+    :return
+    return p0
+
+    :catch_all_1
+    const/4 p0, -0x1
+    goto :return
+
+    :catch_all_2
+    const/4 p0, -0x2
+    goto :return
+.end method
+
+# Same as previous test, only the blocks are processed in the opposite order.
+
+## CHECK-START: int Builder.testSharedBoundary_Reverse(int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BGoto:B\d+>>"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+## CHECK:  <<Minus2:i\d+>>  IntConstant -2
+
+## CHECK:  name             "<<BGoto>>"
+## CHECK:  successors       "<<BEnter2:B\d+>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnter1:B\d+>>"
+## CHECK:  successors       "<<BExit1:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnter2>>"
+## CHECK:  successors       "<<BExit2:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExit1>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BCatch1>>"
+## CHECK:  predecessors     "<<BEnter1>>" "<<BExit1>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BCatch2>>"
+## CHECK:  predecessors     "<<BEnter2>>" "<<BExit2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus2>>]
+
+## CHECK:  name             "<<BEnter1>>"
+## CHECK:  predecessors     "<<BExit2>>"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatch1>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch1>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnter2>>"
+## CHECK:  predecessors     "<<BGoto>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch2>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BEnter1>>"
+## CHECK:  xhandlers        "<<BCatch2>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testSharedBoundary_Reverse(III)I
+    .registers 3
+
+    goto :try_start_2
+
+    :try_start_1
+    div-int/2addr p0, p1
+    goto :return
+    :try_end_1
+    .catchall {:try_start_1 .. :try_end_1} :catch_all_1
+
+    :try_start_2
+    div-int/2addr p0, p2
+    goto :try_start_1
+    :try_end_2
+    .catchall {:try_start_2 .. :try_end_2} :catch_all_2
+
+    :return
+    return p0
+
+    :catch_all_1
+    const/4 p0, -0x1
+    goto :return
+
+    :catch_all_2
+    const/4 p0, -0x2
+    goto :return
+.end method
+
+# Test that nested tries are split into non-overlapping blocks and TryBoundary
+# blocks are correctly created between them.
+
+## CHECK-START: int Builder.testNestedTry(int, int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+## CHECK:  <<Minus2:i\d+>>  IntConstant -2
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnter1:B\d+>>"
+## CHECK:  successors       "<<BExit1:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnter2:B\d+>>"
+## CHECK:  successors       "<<BExit2:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry3:B\d+>>"
+## CHECK:  predecessors     "<<BEnter3:B\d+>>"
+## CHECK:  successors       "<<BExit3:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExit3>>" "<<BCatchArith:B\d+>>" "<<BCatchAll:B\d+>>"
+
+## CHECK:  name             "<<BCatchArith>>"
+## CHECK:  predecessors     "<<BEnter2>>" "<<BExit2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BCatchAll>>"
+## CHECK:  predecessors     "<<BEnter1>>" "<<BExit1>>" "<<BEnter2>>" "<<BExit2>>" "<<BEnter3>>" "<<BExit3>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus2>>]
+
+## CHECK:  name             "<<BEnter1>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatchAll>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BEnter2>>"
+## CHECK:  xhandlers        "<<BCatchAll>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnter2>>"
+## CHECK:  predecessors     "<<BExit1>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatchArith>>" "<<BCatchAll>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BEnter3>>"
+## CHECK:  xhandlers        "<<BCatchArith>>" "<<BCatchAll>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnter3>>"
+## CHECK:  predecessors     "<<BExit2>>"
+## CHECK:  successors       "<<BTry3>>"
+## CHECK:  xhandlers        "<<BCatchAll>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExit3>>"
+## CHECK:  predecessors     "<<BTry3>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatchAll>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testNestedTry(IIII)I
+    .registers 4
+
+    :try_start_1
+    div-int/2addr p0, p1
+
+    :try_start_2
+    div-int/2addr p0, p2
+    :try_end_2
+    .catch Ljava/lang/ArithmeticException; {:try_start_2 .. :try_end_2} :catch_arith
+
+    div-int/2addr p0, p3
+    :try_end_1
+    .catchall {:try_start_1 .. :try_end_1} :catch_all
+
+    :return
+    return p0
+
+    :catch_arith
+    const/4 p0, -0x1
+    goto :return
+
+    :catch_all
+    const/4 p0, -0x2
+    goto :return
+.end method
+
+# Test control flow that enters a try block, leaves it and returns again.
+
+## CHECK-START: int Builder.testIncontinuousTry(int, int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1:B\d+>>"
+## CHECK:  successors       "<<BExitTry1:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2:B\d+>>"
+## CHECK:  successors       "<<BExitTry2:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry2>>" "<<BCatch:B\d+>>"
+
+## CHECK:  name             "<<BOutside:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BCatch>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2>>" "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  flags            "catch_block"
+## CHECK:  StoreLocal       [v0,<<Minus1>>]
+
+## CHECK:  name             "<<BEnterTry1>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BOutside>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testIncontinuousTry(IIII)I
+    .registers 4
+
+    :try_start
+    div-int/2addr p0, p1
+    goto :outside
+
+    :inside
+    div-int/2addr p0, p3
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return p0
+
+    :outside
+    div-int/2addr p0, p2
+    goto :inside
+
+    :catch_all
+    const/4 p0, -0x1
+    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.
+
+## CHECK-START: int Builder.testThrow(java.lang.Exception) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BEnterTry:B\d+>>"
+## CHECK:  <<Minus1:i\d+>>  IntConstant -1
+
+## CHECK:  name             "<<BTry:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry>>"
+## CHECK:  successors       "<<BExitTry:B\d+>>"
+## CHECK:  Throw
+
+## CHECK:  name             "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry>>" "<<BExitTry>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
+## 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>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry>>"
+## CHECK:  predecessors     "<<BTry>>"
+## CHECK:  successors       "<<BExit>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testThrow(Ljava/lang/Exception;)I
+    .registers 2
+
+    :try_start
+    throw p0
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :catch_all
+    const/4 v0, -0x1
+    return v0
+.end method
+
+# Test graph with a throw/catch loop.
+
+## CHECK-START: int Builder.testCatchLoop(int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BCatch:B\d+>>"
+
+## CHECK:  name             "<<BCatch>>"
+## CHECK:  predecessors     "B0" "<<BEnterTry:B\d+>>" "<<BExitTry:B\d+>>"
+## CHECK:  successors       "<<BEnterTry>>"
+## CHECK:  flags            "catch_block"
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
+
+## CHECK:  name             "<<BExit>>"
+
+## CHECK:  name             "<<BTry:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry>>"
+## CHECK:  successors       "<<BExitTry>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BEnterTry>>"
+## CHECK:  predecessors     "<<BCatch>>"
+## CHECK:  successors       "<<BTry>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry>>"
+## CHECK:  predecessors     "<<BTry>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testCatchLoop(III)I
+    .registers 4
+
+    :try_start
+    :catch_all
+    div-int/2addr p0, p2
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :return
+    return p0
+.end method
+
+# Test that handler edges are not split. In this scenario, the catch block is
+# only the handler of the try block.
+
+## CHECK-START: int Builder.testHandlerEdge1(int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BExitTry1:B\d+>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry1>>" "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2:B\d+>>" "<<BExitTry2:B\d+>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  flags            "catch_block"
+
+## 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>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BCatch>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BCatch>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testHandlerEdge1(III)I
+    .registers 4
+
+    :try_start
+    div-int/2addr p0, p1
+
+    :catch_all
+    div-int/2addr p0, p2
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    return p0
+.end method
+
+# Test that handler edges are not split. In this scenario, the catch block is
+# the handler and also the successor of the try block.
+
+## CHECK-START: int Builder.testHandlerEdge2(int, int, int) builder (after)
+
+## CHECK:  name             "B0"
+## CHECK:  successors       "<<BCatch1:B\d+>>"
+
+## CHECK:  name             "<<BCatch1>>"
+## 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     "<<BExitTry1:B\d+>>" "<<BEnterTry1>>" "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  flags            "catch_block"
+
+## CHECK:  name             "<<BReturn:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BExit>>"
+
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BExitTry1>>"
+## CHECK:  Div
+
+## 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             "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BTry1>>"
+## CHECK:  successors       "<<BCatch2>>"
+## CHECK:  xhandlers        "<<BCatch2>>"
+## CHECK:  TryBoundary      kind:exit
+
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BCatch2>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  xhandlers        "<<BCatch1>>"
+## CHECK:  TryBoundary      kind:entry
+
+## CHECK:  name             "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  xhandlers        "<<BCatch1>>"
+## CHECK:  TryBoundary      kind:exit
+
+.method public static testHandlerEdge2(III)I
+    .registers 4
+
+    :try_start_1
+    :catch_all_1
+    div-int/2addr p0, p1
+    :try_end_1
+    .catchall {:try_start_1 .. :try_end_1} :catch_all_2
+
+    :try_start_2
+    :catch_all_2
+    div-int/2addr p0, p2
+    :try_end_2
+    .catchall {:try_start_2 .. :try_end_2} :catch_all_1
+
+    return p0
+.end method
+
+# Test that a MOVE_RESULT instruction is placed into the same block as the
+# INVOKE it follows, even if there is a try boundary between them.
+
+## CHECK-START: int Builder.testMoveResult_Invoke(int, int, int) builder (after)
+
+## CHECK:       <<Res:i\d+>> InvokeStaticOrDirect
+## CHECK-NEXT:  StoreLocal   [v0,<<Res>>]
+
+.method public static testMoveResult_Invoke(III)I
+    .registers 3
+
+    :try_start
+    invoke-static {p0, p1, p2}, LBuilder;->testCatchLoop(III)I
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    move-result p0
+
+    :return
+    return p0
+
+    :catch_all
+    const/4 p0, -0x1
+    goto :return
+.end method
+
+# Test that a MOVE_RESULT instruction is placed into the same block as the
+# FILLED_NEW_ARRAY it follows, even if there is a try boundary between them.
+
+## CHECK-START: int[] Builder.testMoveResult_FilledNewArray(int, int, int) builder (after)
+
+## CHECK:      <<Res:l\d+>>     NewArray
+## CHECK-NEXT:                  Temporary
+## CHECK-NEXT: <<Local1:i\d+>>  LoadLocal  [v0]
+## CHECK-NEXT:                  ArraySet   [<<Res>>,{{i\d+}},<<Local1>>]
+## CHECK-NEXT: <<Local2:i\d+>>  LoadLocal  [v1]
+## CHECK-NEXT:                  ArraySet   [<<Res>>,{{i\d+}},<<Local2>>]
+## CHECK-NEXT: <<Local3:i\d+>>  LoadLocal  [v2]
+## CHECK-NEXT:                  ArraySet   [<<Res>>,{{i\d+}},<<Local3>>]
+## CHECK-NEXT:                  StoreLocal [v0,<<Res>>]
+
+.method public static testMoveResult_FilledNewArray(III)[I
+    .registers 3
+
+    :try_start
+    filled-new-array {p0, p1, p2}, [I
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    move-result-object p0
+
+    :return
+    return-object p0
+
+    :catch_all
+    const/4 p0, 0x0
+    goto :return
+.end method
+
+# Test case for ReturnVoid inside a try block. Builder needs to move it outside
+# the try block so as to not split the ReturnVoid-Exit edge.
+# This invariant is enforced by GraphChecker.
+
+.method public static testReturnVoidInTry(II)V
+    .registers 2
+
+    :catch_all
+    :try_start
+    return-void
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+.end method
+
+# Test case for Return inside a try block. Builder needs to move it outside the
+# try block so as to not split the Return-Exit edge.
+# This invariant is enforced by GraphChecker.
+
+.method public static testReturnInTry(II)I
+    .registers 2
+
+    :try_start
+    div-int/2addr p0, p1
+    return p0
+    :try_end
+    .catchall {:try_start .. :try_end} :catch_all
+
+    :catch_all
+    const/4 v0, 0x0
+    return v0
+.end method
+
+# Test a (dead) try block which flows out of the method. The block will be
+# removed by DCE but needs to pass post-builder GraphChecker.
+
+## CHECK-START: int Builder.testDeadEndTry(int) builder (after)
+## CHECK-NOT:     TryBoundary is_exit:true
+
+.method public static testDeadEndTry(I)I
+    .registers 1
+
+    return p0
+
+    :catch_all
+    nop
+
+    :try_start
+    nop
+    :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/src/Main.java b/test/510-checker-try-catch/src/Main.java
new file mode 100644
index 0000000..ae78ba0
--- /dev/null
+++ b/test/510-checker-try-catch/src/Main.java
@@ -0,0 +1,23 @@
+/*
+ * 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 {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) {}
+}
diff --git a/test/517-checker-builder-fallthrough/expected.txt b/test/517-checker-builder-fallthrough/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/517-checker-builder-fallthrough/expected.txt
diff --git a/test/517-checker-builder-fallthrough/info.txt b/test/517-checker-builder-fallthrough/info.txt
new file mode 100644
index 0000000..5789b56
--- /dev/null
+++ b/test/517-checker-builder-fallthrough/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing's builder which created a block under
+the assumption that Goto can fall through.
diff --git a/test/517-checker-builder-fallthrough/smali/TestCase.smali b/test/517-checker-builder-fallthrough/smali/TestCase.smali
new file mode 100644
index 0000000..bc9502b
--- /dev/null
+++ b/test/517-checker-builder-fallthrough/smali/TestCase.smali
@@ -0,0 +1,67 @@
+# 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 LTestCase;
+
+.super Ljava/lang/Object;
+
+.field public static value:Z
+
+## CHECK-START: int TestCase.testCase(int) builder (after)
+
+## CHECK:  name            "B0"
+## CHECK:  <<Const0:i\d+>> IntConstant 0
+
+## CHECK:  name            "B1"
+## CHECK:  successors      "B5" "B2"
+## CHECK:  StoreLocal      [v0,<<Const0>>]
+## CHECK:  If
+
+## CHECK:  name            "B2"
+## CHECK:  successors      "B4"
+## CHECK:  Goto
+
+## CHECK:  name            "B3"
+## CHECK:  Return
+
+## CHECK:  name            "B4"
+## CHECK:  successors      "B3"
+## CHECK:  Goto
+
+## CHECK:  name            "B5"
+## CHECK:  successors      "B3"
+## CHECK:  Goto
+
+.method public static testCase(I)I
+    .registers 2
+
+    const/4 v0, 0
+    packed-switch v0, :switch_data
+    goto :default
+
+    :switch_data
+    .packed-switch 0x0
+        :case
+    .end packed-switch
+
+    :return
+    return v1
+
+    :default
+    goto :return
+
+    :case
+    goto :return
+
+.end method
diff --git a/test/517-checker-builder-fallthrough/src/Main.java b/test/517-checker-builder-fallthrough/src/Main.java
new file mode 100644
index 0000000..23d94e6
--- /dev/null
+++ b/test/517-checker-builder-fallthrough/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * 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.*;
+
+public class Main {
+
+  public static int runTest(int input) throws Exception {
+    Class<?> c = Class.forName("TestCase");
+    Method m = c.getMethod("testCase", new Class[] { int.class });
+    return (Integer) m.invoke(null, input);
+  }
+
+  public static void main(String[] args) throws Exception {
+    if (runTest(42) != 42) {
+      throw new Error("Expected 42");
+    }
+  }
+}
diff --git a/test/521-checker-array-set-null/expected.txt b/test/521-checker-array-set-null/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/521-checker-array-set-null/expected.txt
diff --git a/test/521-checker-array-set-null/info.txt b/test/521-checker-array-set-null/info.txt
new file mode 100644
index 0000000..ec2ba35
--- /dev/null
+++ b/test/521-checker-array-set-null/info.txt
@@ -0,0 +1,2 @@
+Checker test for optimizing that checks whether our
+optimizations to remove type checks on array set operations work.
diff --git a/test/521-checker-array-set-null/src/Main.java b/test/521-checker-array-set-null/src/Main.java
new file mode 100644
index 0000000..74bb73f
--- /dev/null
+++ b/test/521-checker-array-set-null/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * 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 main(String[] args) {
+    testWithNull(new Object[2]);
+    testWithUnknown(new Object[2], new Object());
+    testWithSame(new Object[2]);
+  }
+
+  /// CHECK-START: void Main.testWithNull(java.lang.Object[]) disassembly (after)
+  /// CHECK-NOT:      pAputObject
+  public static void testWithNull(Object[] o) {
+    o[0] = null;
+  }
+
+  /// CHECK-START: void Main.testWithUnknown(java.lang.Object[], java.lang.Object) disassembly (after)
+  /// CHECK:          pAputObject
+  public static void testWithUnknown(Object[] o, Object obj) {
+    o[0] = obj;
+  }
+
+  /// CHECK-START: void Main.testWithSame(java.lang.Object[]) disassembly (after)
+  /// CHECK-NOT:      pAputObject
+  public static void testWithSame(Object[] o) {
+    o[0] = o[1];
+  }
+}
diff --git a/test/521-regression-integer-field-set/expected.txt b/test/521-regression-integer-field-set/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/521-regression-integer-field-set/expected.txt
diff --git a/test/521-regression-integer-field-set/info.txt b/test/521-regression-integer-field-set/info.txt
new file mode 100644
index 0000000..62f7e3d
--- /dev/null
+++ b/test/521-regression-integer-field-set/info.txt
@@ -0,0 +1,3 @@
+Regression test for Optimizing's x86-64 code generator, where moving a
+32-bit immediate (integer or reference) into a field used to generate
+a `movw` instruction instead of a `movl` instruction.
diff --git a/test/521-regression-integer-field-set/src/Main.java b/test/521-regression-integer-field-set/src/Main.java
new file mode 100644
index 0000000..9924e09
--- /dev/null
+++ b/test/521-regression-integer-field-set/src/Main.java
@@ -0,0 +1,58 @@
+/*
+ * 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 Main {
+  public static void assertIntEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void main(String[] args) {
+    Main m = new Main();
+
+    m.$noinline$SetInstanceField();
+    assertIntEquals(123456, m.i);
+
+    $noinline$SetStaticField();
+    assertIntEquals(456789, s);
+  }
+
+  private static boolean doThrow = false;
+
+  private void $noinline$SetInstanceField() {
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
+
+    // Set a value than does not fit in a 16-bit (signed) integer.
+    i = 123456;
+  }
+
+  private static void $noinline$SetStaticField() {
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
+
+    // Set a value than does not fit in a 16-bit (signed) integer.
+    s = 456789;
+  }
+
+  private int i = 0;
+  private static int s = 0;
+}
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/701-easy-div-rem/build b/test/701-easy-div-rem/build
new file mode 100644
index 0000000..666fe89
--- /dev/null
+++ b/test/701-easy-div-rem/build
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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
+
+# Write out the source file.
+mkdir src
+python ./genMain.py
+
+# Increase the file size limitation for classes.lst as the machine generated
+# source file contains a lot of methods and is quite large.
+
+# 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/701-easy-div-rem/genMain.py b/test/701-easy-div-rem/genMain.py
index 80eac34..75eee17 100644
--- a/test/701-easy-div-rem/genMain.py
+++ b/test/701-easy-div-rem/genMain.py
@@ -12,15 +12,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+upper_bound_int_pow2 = 31
+upper_bound_long_pow2 = 63
+upper_bound_constant = 100
 all_tests = [
     ({'@INT@': 'int', '@SUFFIX@':''},
-     [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(31)]),
-      ('CheckDiv', 'idiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
-      ('CheckRem', 'irem_by_pow2_', [2**i for i in range(31)])]),
+     [('CheckDiv', 'idiv_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckDiv', 'idiv_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckDiv', 'idiv_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckDiv', 'idiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'irem_by_pow2_', [2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckRem', 'irem_by_pow2_neg_', [-2**i for i in range(upper_bound_int_pow2)]),
+      ('CheckRem', 'irem_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'irem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])]),
     ({'@INT@': 'long', '@SUFFIX@': 'l'},
-     [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(63)]),
-      ('CheckDiv', 'ldiv_by_small_', [i for i in range(3, 16) if i not in (4, 8)]),
-      ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(63)])])
+     [('CheckDiv', 'ldiv_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckDiv', 'ldiv_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckDiv', 'ldiv_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckDiv', 'ldiv_by_constant_neg_', [-i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'lrem_by_pow2_', [2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckRem', 'lrem_by_pow2_neg_', [-2**i for i in range(upper_bound_long_pow2)]),
+      ('CheckRem', 'lrem_by_constant_', [i for i in range(1, upper_bound_constant)]),
+      ('CheckRem', 'lrem_by_constant_neg_', [-i for i in range(1, upper_bound_constant)])])
 ]
 
 def subst_vars(variables, text):
diff --git a/test/701-easy-div-rem/src/Main.java b/test/701-easy-div-rem/src/Main.java
deleted file mode 100644
index f995f61..0000000
--- a/test/701-easy-div-rem/src/Main.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2014 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 int num_errors = 0;
-
-    public static void reportError(String message) {
-        if (num_errors == 10) {
-            System.out.println("Omitting other error messages...");
-        } else if (num_errors < 10) {
-            System.out.println(message);
-        }
-        num_errors += 1;
-    }
-
-    public static void intCheckDiv(String desc, int result, int dividend, int divisor) {
-        int correct_result = dividend / divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-    public static void intCheckRem(String desc, int result, int dividend, int divisor) {
-        int correct_result = dividend % divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-    public static void longCheckDiv(String desc, long result, long dividend, long divisor) {
-        long correct_result = dividend / divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-    public static void longCheckRem(String desc, long result, long dividend, long divisor) {
-        long correct_result = dividend % divisor;
-        if (result != correct_result) {
-            reportError(desc + "(" + dividend + ") == " + result +
-                        " should be " + correct_result);
-        }
-    }
-
-    public static int idiv_by_pow2_0(int x) {return x / 1;}
-    public static int idiv_by_pow2_1(int x) {return x / 2;}
-    public static int idiv_by_pow2_2(int x) {return x / 4;}
-    public static int idiv_by_pow2_3(int x) {return x / 8;}
-    public static int idiv_by_pow2_4(int x) {return x / 16;}
-    public static int idiv_by_pow2_5(int x) {return x / 32;}
-    public static int idiv_by_pow2_6(int x) {return x / 64;}
-    public static int idiv_by_pow2_7(int x) {return x / 128;}
-    public static int idiv_by_pow2_8(int x) {return x / 256;}
-    public static int idiv_by_pow2_9(int x) {return x / 512;}
-    public static int idiv_by_pow2_10(int x) {return x / 1024;}
-    public static int idiv_by_pow2_11(int x) {return x / 2048;}
-    public static int idiv_by_pow2_12(int x) {return x / 4096;}
-    public static int idiv_by_pow2_13(int x) {return x / 8192;}
-    public static int idiv_by_pow2_14(int x) {return x / 16384;}
-    public static int idiv_by_pow2_15(int x) {return x / 32768;}
-    public static int idiv_by_pow2_16(int x) {return x / 65536;}
-    public static int idiv_by_pow2_17(int x) {return x / 131072;}
-    public static int idiv_by_pow2_18(int x) {return x / 262144;}
-    public static int idiv_by_pow2_19(int x) {return x / 524288;}
-    public static int idiv_by_pow2_20(int x) {return x / 1048576;}
-    public static int idiv_by_pow2_21(int x) {return x / 2097152;}
-    public static int idiv_by_pow2_22(int x) {return x / 4194304;}
-    public static int idiv_by_pow2_23(int x) {return x / 8388608;}
-    public static int idiv_by_pow2_24(int x) {return x / 16777216;}
-    public static int idiv_by_pow2_25(int x) {return x / 33554432;}
-    public static int idiv_by_pow2_26(int x) {return x / 67108864;}
-    public static int idiv_by_pow2_27(int x) {return x / 134217728;}
-    public static int idiv_by_pow2_28(int x) {return x / 268435456;}
-    public static int idiv_by_pow2_29(int x) {return x / 536870912;}
-    public static int idiv_by_pow2_30(int x) {return x / 1073741824;}
-    public static int idiv_by_small_0(int x) {return x / 3;}
-    public static int idiv_by_small_1(int x) {return x / 5;}
-    public static int idiv_by_small_2(int x) {return x / 6;}
-    public static int idiv_by_small_3(int x) {return x / 7;}
-    public static int idiv_by_small_4(int x) {return x / 9;}
-    public static int idiv_by_small_5(int x) {return x / 10;}
-    public static int idiv_by_small_6(int x) {return x / 11;}
-    public static int idiv_by_small_7(int x) {return x / 12;}
-    public static int idiv_by_small_8(int x) {return x / 13;}
-    public static int idiv_by_small_9(int x) {return x / 14;}
-    public static int idiv_by_small_10(int x) {return x / 15;}
-    public static int irem_by_pow2_0(int x) {return x % 1;}
-    public static int irem_by_pow2_1(int x) {return x % 2;}
-    public static int irem_by_pow2_2(int x) {return x % 4;}
-    public static int irem_by_pow2_3(int x) {return x % 8;}
-    public static int irem_by_pow2_4(int x) {return x % 16;}
-    public static int irem_by_pow2_5(int x) {return x % 32;}
-    public static int irem_by_pow2_6(int x) {return x % 64;}
-    public static int irem_by_pow2_7(int x) {return x % 128;}
-    public static int irem_by_pow2_8(int x) {return x % 256;}
-    public static int irem_by_pow2_9(int x) {return x % 512;}
-    public static int irem_by_pow2_10(int x) {return x % 1024;}
-    public static int irem_by_pow2_11(int x) {return x % 2048;}
-    public static int irem_by_pow2_12(int x) {return x % 4096;}
-    public static int irem_by_pow2_13(int x) {return x % 8192;}
-    public static int irem_by_pow2_14(int x) {return x % 16384;}
-    public static int irem_by_pow2_15(int x) {return x % 32768;}
-    public static int irem_by_pow2_16(int x) {return x % 65536;}
-    public static int irem_by_pow2_17(int x) {return x % 131072;}
-    public static int irem_by_pow2_18(int x) {return x % 262144;}
-    public static int irem_by_pow2_19(int x) {return x % 524288;}
-    public static int irem_by_pow2_20(int x) {return x % 1048576;}
-    public static int irem_by_pow2_21(int x) {return x % 2097152;}
-    public static int irem_by_pow2_22(int x) {return x % 4194304;}
-    public static int irem_by_pow2_23(int x) {return x % 8388608;}
-    public static int irem_by_pow2_24(int x) {return x % 16777216;}
-    public static int irem_by_pow2_25(int x) {return x % 33554432;}
-    public static int irem_by_pow2_26(int x) {return x % 67108864;}
-    public static int irem_by_pow2_27(int x) {return x % 134217728;}
-    public static int irem_by_pow2_28(int x) {return x % 268435456;}
-    public static int irem_by_pow2_29(int x) {return x % 536870912;}
-    public static int irem_by_pow2_30(int x) {return x % 1073741824;}
-    public static long ldiv_by_pow2_0(long x) {return x / 1l;}
-    public static long ldiv_by_pow2_1(long x) {return x / 2l;}
-    public static long ldiv_by_pow2_2(long x) {return x / 4l;}
-    public static long ldiv_by_pow2_3(long x) {return x / 8l;}
-    public static long ldiv_by_pow2_4(long x) {return x / 16l;}
-    public static long ldiv_by_pow2_5(long x) {return x / 32l;}
-    public static long ldiv_by_pow2_6(long x) {return x / 64l;}
-    public static long ldiv_by_pow2_7(long x) {return x / 128l;}
-    public static long ldiv_by_pow2_8(long x) {return x / 256l;}
-    public static long ldiv_by_pow2_9(long x) {return x / 512l;}
-    public static long ldiv_by_pow2_10(long x) {return x / 1024l;}
-    public static long ldiv_by_pow2_11(long x) {return x / 2048l;}
-    public static long ldiv_by_pow2_12(long x) {return x / 4096l;}
-    public static long ldiv_by_pow2_13(long x) {return x / 8192l;}
-    public static long ldiv_by_pow2_14(long x) {return x / 16384l;}
-    public static long ldiv_by_pow2_15(long x) {return x / 32768l;}
-    public static long ldiv_by_pow2_16(long x) {return x / 65536l;}
-    public static long ldiv_by_pow2_17(long x) {return x / 131072l;}
-    public static long ldiv_by_pow2_18(long x) {return x / 262144l;}
-    public static long ldiv_by_pow2_19(long x) {return x / 524288l;}
-    public static long ldiv_by_pow2_20(long x) {return x / 1048576l;}
-    public static long ldiv_by_pow2_21(long x) {return x / 2097152l;}
-    public static long ldiv_by_pow2_22(long x) {return x / 4194304l;}
-    public static long ldiv_by_pow2_23(long x) {return x / 8388608l;}
-    public static long ldiv_by_pow2_24(long x) {return x / 16777216l;}
-    public static long ldiv_by_pow2_25(long x) {return x / 33554432l;}
-    public static long ldiv_by_pow2_26(long x) {return x / 67108864l;}
-    public static long ldiv_by_pow2_27(long x) {return x / 134217728l;}
-    public static long ldiv_by_pow2_28(long x) {return x / 268435456l;}
-    public static long ldiv_by_pow2_29(long x) {return x / 536870912l;}
-    public static long ldiv_by_pow2_30(long x) {return x / 1073741824l;}
-    public static long ldiv_by_pow2_31(long x) {return x / 2147483648l;}
-    public static long ldiv_by_pow2_32(long x) {return x / 4294967296l;}
-    public static long ldiv_by_pow2_33(long x) {return x / 8589934592l;}
-    public static long ldiv_by_pow2_34(long x) {return x / 17179869184l;}
-    public static long ldiv_by_pow2_35(long x) {return x / 34359738368l;}
-    public static long ldiv_by_pow2_36(long x) {return x / 68719476736l;}
-    public static long ldiv_by_pow2_37(long x) {return x / 137438953472l;}
-    public static long ldiv_by_pow2_38(long x) {return x / 274877906944l;}
-    public static long ldiv_by_pow2_39(long x) {return x / 549755813888l;}
-    public static long ldiv_by_pow2_40(long x) {return x / 1099511627776l;}
-    public static long ldiv_by_pow2_41(long x) {return x / 2199023255552l;}
-    public static long ldiv_by_pow2_42(long x) {return x / 4398046511104l;}
-    public static long ldiv_by_pow2_43(long x) {return x / 8796093022208l;}
-    public static long ldiv_by_pow2_44(long x) {return x / 17592186044416l;}
-    public static long ldiv_by_pow2_45(long x) {return x / 35184372088832l;}
-    public static long ldiv_by_pow2_46(long x) {return x / 70368744177664l;}
-    public static long ldiv_by_pow2_47(long x) {return x / 140737488355328l;}
-    public static long ldiv_by_pow2_48(long x) {return x / 281474976710656l;}
-    public static long ldiv_by_pow2_49(long x) {return x / 562949953421312l;}
-    public static long ldiv_by_pow2_50(long x) {return x / 1125899906842624l;}
-    public static long ldiv_by_pow2_51(long x) {return x / 2251799813685248l;}
-    public static long ldiv_by_pow2_52(long x) {return x / 4503599627370496l;}
-    public static long ldiv_by_pow2_53(long x) {return x / 9007199254740992l;}
-    public static long ldiv_by_pow2_54(long x) {return x / 18014398509481984l;}
-    public static long ldiv_by_pow2_55(long x) {return x / 36028797018963968l;}
-    public static long ldiv_by_pow2_56(long x) {return x / 72057594037927936l;}
-    public static long ldiv_by_pow2_57(long x) {return x / 144115188075855872l;}
-    public static long ldiv_by_pow2_58(long x) {return x / 288230376151711744l;}
-    public static long ldiv_by_pow2_59(long x) {return x / 576460752303423488l;}
-    public static long ldiv_by_pow2_60(long x) {return x / 1152921504606846976l;}
-    public static long ldiv_by_pow2_61(long x) {return x / 2305843009213693952l;}
-    public static long ldiv_by_pow2_62(long x) {return x / 4611686018427387904l;}
-    public static long ldiv_by_small_0(long x) {return x / 3l;}
-    public static long ldiv_by_small_1(long x) {return x / 5l;}
-    public static long ldiv_by_small_2(long x) {return x / 6l;}
-    public static long ldiv_by_small_3(long x) {return x / 7l;}
-    public static long ldiv_by_small_4(long x) {return x / 9l;}
-    public static long ldiv_by_small_5(long x) {return x / 10l;}
-    public static long ldiv_by_small_6(long x) {return x / 11l;}
-    public static long ldiv_by_small_7(long x) {return x / 12l;}
-    public static long ldiv_by_small_8(long x) {return x / 13l;}
-    public static long ldiv_by_small_9(long x) {return x / 14l;}
-    public static long ldiv_by_small_10(long x) {return x / 15l;}
-    public static long lrem_by_pow2_0(long x) {return x % 1l;}
-    public static long lrem_by_pow2_1(long x) {return x % 2l;}
-    public static long lrem_by_pow2_2(long x) {return x % 4l;}
-    public static long lrem_by_pow2_3(long x) {return x % 8l;}
-    public static long lrem_by_pow2_4(long x) {return x % 16l;}
-    public static long lrem_by_pow2_5(long x) {return x % 32l;}
-    public static long lrem_by_pow2_6(long x) {return x % 64l;}
-    public static long lrem_by_pow2_7(long x) {return x % 128l;}
-    public static long lrem_by_pow2_8(long x) {return x % 256l;}
-    public static long lrem_by_pow2_9(long x) {return x % 512l;}
-    public static long lrem_by_pow2_10(long x) {return x % 1024l;}
-    public static long lrem_by_pow2_11(long x) {return x % 2048l;}
-    public static long lrem_by_pow2_12(long x) {return x % 4096l;}
-    public static long lrem_by_pow2_13(long x) {return x % 8192l;}
-    public static long lrem_by_pow2_14(long x) {return x % 16384l;}
-    public static long lrem_by_pow2_15(long x) {return x % 32768l;}
-    public static long lrem_by_pow2_16(long x) {return x % 65536l;}
-    public static long lrem_by_pow2_17(long x) {return x % 131072l;}
-    public static long lrem_by_pow2_18(long x) {return x % 262144l;}
-    public static long lrem_by_pow2_19(long x) {return x % 524288l;}
-    public static long lrem_by_pow2_20(long x) {return x % 1048576l;}
-    public static long lrem_by_pow2_21(long x) {return x % 2097152l;}
-    public static long lrem_by_pow2_22(long x) {return x % 4194304l;}
-    public static long lrem_by_pow2_23(long x) {return x % 8388608l;}
-    public static long lrem_by_pow2_24(long x) {return x % 16777216l;}
-    public static long lrem_by_pow2_25(long x) {return x % 33554432l;}
-    public static long lrem_by_pow2_26(long x) {return x % 67108864l;}
-    public static long lrem_by_pow2_27(long x) {return x % 134217728l;}
-    public static long lrem_by_pow2_28(long x) {return x % 268435456l;}
-    public static long lrem_by_pow2_29(long x) {return x % 536870912l;}
-    public static long lrem_by_pow2_30(long x) {return x % 1073741824l;}
-    public static long lrem_by_pow2_31(long x) {return x % 2147483648l;}
-    public static long lrem_by_pow2_32(long x) {return x % 4294967296l;}
-    public static long lrem_by_pow2_33(long x) {return x % 8589934592l;}
-    public static long lrem_by_pow2_34(long x) {return x % 17179869184l;}
-    public static long lrem_by_pow2_35(long x) {return x % 34359738368l;}
-    public static long lrem_by_pow2_36(long x) {return x % 68719476736l;}
-    public static long lrem_by_pow2_37(long x) {return x % 137438953472l;}
-    public static long lrem_by_pow2_38(long x) {return x % 274877906944l;}
-    public static long lrem_by_pow2_39(long x) {return x % 549755813888l;}
-    public static long lrem_by_pow2_40(long x) {return x % 1099511627776l;}
-    public static long lrem_by_pow2_41(long x) {return x % 2199023255552l;}
-    public static long lrem_by_pow2_42(long x) {return x % 4398046511104l;}
-    public static long lrem_by_pow2_43(long x) {return x % 8796093022208l;}
-    public static long lrem_by_pow2_44(long x) {return x % 17592186044416l;}
-    public static long lrem_by_pow2_45(long x) {return x % 35184372088832l;}
-    public static long lrem_by_pow2_46(long x) {return x % 70368744177664l;}
-    public static long lrem_by_pow2_47(long x) {return x % 140737488355328l;}
-    public static long lrem_by_pow2_48(long x) {return x % 281474976710656l;}
-    public static long lrem_by_pow2_49(long x) {return x % 562949953421312l;}
-    public static long lrem_by_pow2_50(long x) {return x % 1125899906842624l;}
-    public static long lrem_by_pow2_51(long x) {return x % 2251799813685248l;}
-    public static long lrem_by_pow2_52(long x) {return x % 4503599627370496l;}
-    public static long lrem_by_pow2_53(long x) {return x % 9007199254740992l;}
-    public static long lrem_by_pow2_54(long x) {return x % 18014398509481984l;}
-    public static long lrem_by_pow2_55(long x) {return x % 36028797018963968l;}
-    public static long lrem_by_pow2_56(long x) {return x % 72057594037927936l;}
-    public static long lrem_by_pow2_57(long x) {return x % 144115188075855872l;}
-    public static long lrem_by_pow2_58(long x) {return x % 288230376151711744l;}
-    public static long lrem_by_pow2_59(long x) {return x % 576460752303423488l;}
-    public static long lrem_by_pow2_60(long x) {return x % 1152921504606846976l;}
-    public static long lrem_by_pow2_61(long x) {return x % 2305843009213693952l;}
-    public static long lrem_by_pow2_62(long x) {return x % 4611686018427387904l;}
-
-    public static void intCheckAll(int x) {
-        intCheckDiv("idiv_by_pow2_0", idiv_by_pow2_0(x), x, 1);
-        intCheckDiv("idiv_by_pow2_1", idiv_by_pow2_1(x), x, 2);
-        intCheckDiv("idiv_by_pow2_2", idiv_by_pow2_2(x), x, 4);
-        intCheckDiv("idiv_by_pow2_3", idiv_by_pow2_3(x), x, 8);
-        intCheckDiv("idiv_by_pow2_4", idiv_by_pow2_4(x), x, 16);
-        intCheckDiv("idiv_by_pow2_5", idiv_by_pow2_5(x), x, 32);
-        intCheckDiv("idiv_by_pow2_6", idiv_by_pow2_6(x), x, 64);
-        intCheckDiv("idiv_by_pow2_7", idiv_by_pow2_7(x), x, 128);
-        intCheckDiv("idiv_by_pow2_8", idiv_by_pow2_8(x), x, 256);
-        intCheckDiv("idiv_by_pow2_9", idiv_by_pow2_9(x), x, 512);
-        intCheckDiv("idiv_by_pow2_10", idiv_by_pow2_10(x), x, 1024);
-        intCheckDiv("idiv_by_pow2_11", idiv_by_pow2_11(x), x, 2048);
-        intCheckDiv("idiv_by_pow2_12", idiv_by_pow2_12(x), x, 4096);
-        intCheckDiv("idiv_by_pow2_13", idiv_by_pow2_13(x), x, 8192);
-        intCheckDiv("idiv_by_pow2_14", idiv_by_pow2_14(x), x, 16384);
-        intCheckDiv("idiv_by_pow2_15", idiv_by_pow2_15(x), x, 32768);
-        intCheckDiv("idiv_by_pow2_16", idiv_by_pow2_16(x), x, 65536);
-        intCheckDiv("idiv_by_pow2_17", idiv_by_pow2_17(x), x, 131072);
-        intCheckDiv("idiv_by_pow2_18", idiv_by_pow2_18(x), x, 262144);
-        intCheckDiv("idiv_by_pow2_19", idiv_by_pow2_19(x), x, 524288);
-        intCheckDiv("idiv_by_pow2_20", idiv_by_pow2_20(x), x, 1048576);
-        intCheckDiv("idiv_by_pow2_21", idiv_by_pow2_21(x), x, 2097152);
-        intCheckDiv("idiv_by_pow2_22", idiv_by_pow2_22(x), x, 4194304);
-        intCheckDiv("idiv_by_pow2_23", idiv_by_pow2_23(x), x, 8388608);
-        intCheckDiv("idiv_by_pow2_24", idiv_by_pow2_24(x), x, 16777216);
-        intCheckDiv("idiv_by_pow2_25", idiv_by_pow2_25(x), x, 33554432);
-        intCheckDiv("idiv_by_pow2_26", idiv_by_pow2_26(x), x, 67108864);
-        intCheckDiv("idiv_by_pow2_27", idiv_by_pow2_27(x), x, 134217728);
-        intCheckDiv("idiv_by_pow2_28", idiv_by_pow2_28(x), x, 268435456);
-        intCheckDiv("idiv_by_pow2_29", idiv_by_pow2_29(x), x, 536870912);
-        intCheckDiv("idiv_by_pow2_30", idiv_by_pow2_30(x), x, 1073741824);
-        intCheckDiv("idiv_by_small_0", idiv_by_small_0(x), x, 3);
-        intCheckDiv("idiv_by_small_1", idiv_by_small_1(x), x, 5);
-        intCheckDiv("idiv_by_small_2", idiv_by_small_2(x), x, 6);
-        intCheckDiv("idiv_by_small_3", idiv_by_small_3(x), x, 7);
-        intCheckDiv("idiv_by_small_4", idiv_by_small_4(x), x, 9);
-        intCheckDiv("idiv_by_small_5", idiv_by_small_5(x), x, 10);
-        intCheckDiv("idiv_by_small_6", idiv_by_small_6(x), x, 11);
-        intCheckDiv("idiv_by_small_7", idiv_by_small_7(x), x, 12);
-        intCheckDiv("idiv_by_small_8", idiv_by_small_8(x), x, 13);
-        intCheckDiv("idiv_by_small_9", idiv_by_small_9(x), x, 14);
-        intCheckDiv("idiv_by_small_10", idiv_by_small_10(x), x, 15);
-        intCheckRem("irem_by_pow2_0", irem_by_pow2_0(x), x, 1);
-        intCheckRem("irem_by_pow2_1", irem_by_pow2_1(x), x, 2);
-        intCheckRem("irem_by_pow2_2", irem_by_pow2_2(x), x, 4);
-        intCheckRem("irem_by_pow2_3", irem_by_pow2_3(x), x, 8);
-        intCheckRem("irem_by_pow2_4", irem_by_pow2_4(x), x, 16);
-        intCheckRem("irem_by_pow2_5", irem_by_pow2_5(x), x, 32);
-        intCheckRem("irem_by_pow2_6", irem_by_pow2_6(x), x, 64);
-        intCheckRem("irem_by_pow2_7", irem_by_pow2_7(x), x, 128);
-        intCheckRem("irem_by_pow2_8", irem_by_pow2_8(x), x, 256);
-        intCheckRem("irem_by_pow2_9", irem_by_pow2_9(x), x, 512);
-        intCheckRem("irem_by_pow2_10", irem_by_pow2_10(x), x, 1024);
-        intCheckRem("irem_by_pow2_11", irem_by_pow2_11(x), x, 2048);
-        intCheckRem("irem_by_pow2_12", irem_by_pow2_12(x), x, 4096);
-        intCheckRem("irem_by_pow2_13", irem_by_pow2_13(x), x, 8192);
-        intCheckRem("irem_by_pow2_14", irem_by_pow2_14(x), x, 16384);
-        intCheckRem("irem_by_pow2_15", irem_by_pow2_15(x), x, 32768);
-        intCheckRem("irem_by_pow2_16", irem_by_pow2_16(x), x, 65536);
-        intCheckRem("irem_by_pow2_17", irem_by_pow2_17(x), x, 131072);
-        intCheckRem("irem_by_pow2_18", irem_by_pow2_18(x), x, 262144);
-        intCheckRem("irem_by_pow2_19", irem_by_pow2_19(x), x, 524288);
-        intCheckRem("irem_by_pow2_20", irem_by_pow2_20(x), x, 1048576);
-        intCheckRem("irem_by_pow2_21", irem_by_pow2_21(x), x, 2097152);
-        intCheckRem("irem_by_pow2_22", irem_by_pow2_22(x), x, 4194304);
-        intCheckRem("irem_by_pow2_23", irem_by_pow2_23(x), x, 8388608);
-        intCheckRem("irem_by_pow2_24", irem_by_pow2_24(x), x, 16777216);
-        intCheckRem("irem_by_pow2_25", irem_by_pow2_25(x), x, 33554432);
-        intCheckRem("irem_by_pow2_26", irem_by_pow2_26(x), x, 67108864);
-        intCheckRem("irem_by_pow2_27", irem_by_pow2_27(x), x, 134217728);
-        intCheckRem("irem_by_pow2_28", irem_by_pow2_28(x), x, 268435456);
-        intCheckRem("irem_by_pow2_29", irem_by_pow2_29(x), x, 536870912);
-        intCheckRem("irem_by_pow2_30", irem_by_pow2_30(x), x, 1073741824);
-    }
-
-    public static void longCheckAll(long x) {
-        longCheckDiv("ldiv_by_pow2_0", ldiv_by_pow2_0(x), x, 1l);
-        longCheckDiv("ldiv_by_pow2_1", ldiv_by_pow2_1(x), x, 2l);
-        longCheckDiv("ldiv_by_pow2_2", ldiv_by_pow2_2(x), x, 4l);
-        longCheckDiv("ldiv_by_pow2_3", ldiv_by_pow2_3(x), x, 8l);
-        longCheckDiv("ldiv_by_pow2_4", ldiv_by_pow2_4(x), x, 16l);
-        longCheckDiv("ldiv_by_pow2_5", ldiv_by_pow2_5(x), x, 32l);
-        longCheckDiv("ldiv_by_pow2_6", ldiv_by_pow2_6(x), x, 64l);
-        longCheckDiv("ldiv_by_pow2_7", ldiv_by_pow2_7(x), x, 128l);
-        longCheckDiv("ldiv_by_pow2_8", ldiv_by_pow2_8(x), x, 256l);
-        longCheckDiv("ldiv_by_pow2_9", ldiv_by_pow2_9(x), x, 512l);
-        longCheckDiv("ldiv_by_pow2_10", ldiv_by_pow2_10(x), x, 1024l);
-        longCheckDiv("ldiv_by_pow2_11", ldiv_by_pow2_11(x), x, 2048l);
-        longCheckDiv("ldiv_by_pow2_12", ldiv_by_pow2_12(x), x, 4096l);
-        longCheckDiv("ldiv_by_pow2_13", ldiv_by_pow2_13(x), x, 8192l);
-        longCheckDiv("ldiv_by_pow2_14", ldiv_by_pow2_14(x), x, 16384l);
-        longCheckDiv("ldiv_by_pow2_15", ldiv_by_pow2_15(x), x, 32768l);
-        longCheckDiv("ldiv_by_pow2_16", ldiv_by_pow2_16(x), x, 65536l);
-        longCheckDiv("ldiv_by_pow2_17", ldiv_by_pow2_17(x), x, 131072l);
-        longCheckDiv("ldiv_by_pow2_18", ldiv_by_pow2_18(x), x, 262144l);
-        longCheckDiv("ldiv_by_pow2_19", ldiv_by_pow2_19(x), x, 524288l);
-        longCheckDiv("ldiv_by_pow2_20", ldiv_by_pow2_20(x), x, 1048576l);
-        longCheckDiv("ldiv_by_pow2_21", ldiv_by_pow2_21(x), x, 2097152l);
-        longCheckDiv("ldiv_by_pow2_22", ldiv_by_pow2_22(x), x, 4194304l);
-        longCheckDiv("ldiv_by_pow2_23", ldiv_by_pow2_23(x), x, 8388608l);
-        longCheckDiv("ldiv_by_pow2_24", ldiv_by_pow2_24(x), x, 16777216l);
-        longCheckDiv("ldiv_by_pow2_25", ldiv_by_pow2_25(x), x, 33554432l);
-        longCheckDiv("ldiv_by_pow2_26", ldiv_by_pow2_26(x), x, 67108864l);
-        longCheckDiv("ldiv_by_pow2_27", ldiv_by_pow2_27(x), x, 134217728l);
-        longCheckDiv("ldiv_by_pow2_28", ldiv_by_pow2_28(x), x, 268435456l);
-        longCheckDiv("ldiv_by_pow2_29", ldiv_by_pow2_29(x), x, 536870912l);
-        longCheckDiv("ldiv_by_pow2_30", ldiv_by_pow2_30(x), x, 1073741824l);
-        longCheckDiv("ldiv_by_pow2_31", ldiv_by_pow2_31(x), x, 2147483648l);
-        longCheckDiv("ldiv_by_pow2_32", ldiv_by_pow2_32(x), x, 4294967296l);
-        longCheckDiv("ldiv_by_pow2_33", ldiv_by_pow2_33(x), x, 8589934592l);
-        longCheckDiv("ldiv_by_pow2_34", ldiv_by_pow2_34(x), x, 17179869184l);
-        longCheckDiv("ldiv_by_pow2_35", ldiv_by_pow2_35(x), x, 34359738368l);
-        longCheckDiv("ldiv_by_pow2_36", ldiv_by_pow2_36(x), x, 68719476736l);
-        longCheckDiv("ldiv_by_pow2_37", ldiv_by_pow2_37(x), x, 137438953472l);
-        longCheckDiv("ldiv_by_pow2_38", ldiv_by_pow2_38(x), x, 274877906944l);
-        longCheckDiv("ldiv_by_pow2_39", ldiv_by_pow2_39(x), x, 549755813888l);
-        longCheckDiv("ldiv_by_pow2_40", ldiv_by_pow2_40(x), x, 1099511627776l);
-        longCheckDiv("ldiv_by_pow2_41", ldiv_by_pow2_41(x), x, 2199023255552l);
-        longCheckDiv("ldiv_by_pow2_42", ldiv_by_pow2_42(x), x, 4398046511104l);
-        longCheckDiv("ldiv_by_pow2_43", ldiv_by_pow2_43(x), x, 8796093022208l);
-        longCheckDiv("ldiv_by_pow2_44", ldiv_by_pow2_44(x), x, 17592186044416l);
-        longCheckDiv("ldiv_by_pow2_45", ldiv_by_pow2_45(x), x, 35184372088832l);
-        longCheckDiv("ldiv_by_pow2_46", ldiv_by_pow2_46(x), x, 70368744177664l);
-        longCheckDiv("ldiv_by_pow2_47", ldiv_by_pow2_47(x), x, 140737488355328l);
-        longCheckDiv("ldiv_by_pow2_48", ldiv_by_pow2_48(x), x, 281474976710656l);
-        longCheckDiv("ldiv_by_pow2_49", ldiv_by_pow2_49(x), x, 562949953421312l);
-        longCheckDiv("ldiv_by_pow2_50", ldiv_by_pow2_50(x), x, 1125899906842624l);
-        longCheckDiv("ldiv_by_pow2_51", ldiv_by_pow2_51(x), x, 2251799813685248l);
-        longCheckDiv("ldiv_by_pow2_52", ldiv_by_pow2_52(x), x, 4503599627370496l);
-        longCheckDiv("ldiv_by_pow2_53", ldiv_by_pow2_53(x), x, 9007199254740992l);
-        longCheckDiv("ldiv_by_pow2_54", ldiv_by_pow2_54(x), x, 18014398509481984l);
-        longCheckDiv("ldiv_by_pow2_55", ldiv_by_pow2_55(x), x, 36028797018963968l);
-        longCheckDiv("ldiv_by_pow2_56", ldiv_by_pow2_56(x), x, 72057594037927936l);
-        longCheckDiv("ldiv_by_pow2_57", ldiv_by_pow2_57(x), x, 144115188075855872l);
-        longCheckDiv("ldiv_by_pow2_58", ldiv_by_pow2_58(x), x, 288230376151711744l);
-        longCheckDiv("ldiv_by_pow2_59", ldiv_by_pow2_59(x), x, 576460752303423488l);
-        longCheckDiv("ldiv_by_pow2_60", ldiv_by_pow2_60(x), x, 1152921504606846976l);
-        longCheckDiv("ldiv_by_pow2_61", ldiv_by_pow2_61(x), x, 2305843009213693952l);
-        longCheckDiv("ldiv_by_pow2_62", ldiv_by_pow2_62(x), x, 4611686018427387904l);
-        longCheckDiv("ldiv_by_small_0", ldiv_by_small_0(x), x, 3l);
-        longCheckDiv("ldiv_by_small_1", ldiv_by_small_1(x), x, 5l);
-        longCheckDiv("ldiv_by_small_2", ldiv_by_small_2(x), x, 6l);
-        longCheckDiv("ldiv_by_small_3", ldiv_by_small_3(x), x, 7l);
-        longCheckDiv("ldiv_by_small_4", ldiv_by_small_4(x), x, 9l);
-        longCheckDiv("ldiv_by_small_5", ldiv_by_small_5(x), x, 10l);
-        longCheckDiv("ldiv_by_small_6", ldiv_by_small_6(x), x, 11l);
-        longCheckDiv("ldiv_by_small_7", ldiv_by_small_7(x), x, 12l);
-        longCheckDiv("ldiv_by_small_8", ldiv_by_small_8(x), x, 13l);
-        longCheckDiv("ldiv_by_small_9", ldiv_by_small_9(x), x, 14l);
-        longCheckDiv("ldiv_by_small_10", ldiv_by_small_10(x), x, 15l);
-        longCheckRem("lrem_by_pow2_0", lrem_by_pow2_0(x), x, 1l);
-        longCheckRem("lrem_by_pow2_1", lrem_by_pow2_1(x), x, 2l);
-        longCheckRem("lrem_by_pow2_2", lrem_by_pow2_2(x), x, 4l);
-        longCheckRem("lrem_by_pow2_3", lrem_by_pow2_3(x), x, 8l);
-        longCheckRem("lrem_by_pow2_4", lrem_by_pow2_4(x), x, 16l);
-        longCheckRem("lrem_by_pow2_5", lrem_by_pow2_5(x), x, 32l);
-        longCheckRem("lrem_by_pow2_6", lrem_by_pow2_6(x), x, 64l);
-        longCheckRem("lrem_by_pow2_7", lrem_by_pow2_7(x), x, 128l);
-        longCheckRem("lrem_by_pow2_8", lrem_by_pow2_8(x), x, 256l);
-        longCheckRem("lrem_by_pow2_9", lrem_by_pow2_9(x), x, 512l);
-        longCheckRem("lrem_by_pow2_10", lrem_by_pow2_10(x), x, 1024l);
-        longCheckRem("lrem_by_pow2_11", lrem_by_pow2_11(x), x, 2048l);
-        longCheckRem("lrem_by_pow2_12", lrem_by_pow2_12(x), x, 4096l);
-        longCheckRem("lrem_by_pow2_13", lrem_by_pow2_13(x), x, 8192l);
-        longCheckRem("lrem_by_pow2_14", lrem_by_pow2_14(x), x, 16384l);
-        longCheckRem("lrem_by_pow2_15", lrem_by_pow2_15(x), x, 32768l);
-        longCheckRem("lrem_by_pow2_16", lrem_by_pow2_16(x), x, 65536l);
-        longCheckRem("lrem_by_pow2_17", lrem_by_pow2_17(x), x, 131072l);
-        longCheckRem("lrem_by_pow2_18", lrem_by_pow2_18(x), x, 262144l);
-        longCheckRem("lrem_by_pow2_19", lrem_by_pow2_19(x), x, 524288l);
-        longCheckRem("lrem_by_pow2_20", lrem_by_pow2_20(x), x, 1048576l);
-        longCheckRem("lrem_by_pow2_21", lrem_by_pow2_21(x), x, 2097152l);
-        longCheckRem("lrem_by_pow2_22", lrem_by_pow2_22(x), x, 4194304l);
-        longCheckRem("lrem_by_pow2_23", lrem_by_pow2_23(x), x, 8388608l);
-        longCheckRem("lrem_by_pow2_24", lrem_by_pow2_24(x), x, 16777216l);
-        longCheckRem("lrem_by_pow2_25", lrem_by_pow2_25(x), x, 33554432l);
-        longCheckRem("lrem_by_pow2_26", lrem_by_pow2_26(x), x, 67108864l);
-        longCheckRem("lrem_by_pow2_27", lrem_by_pow2_27(x), x, 134217728l);
-        longCheckRem("lrem_by_pow2_28", lrem_by_pow2_28(x), x, 268435456l);
-        longCheckRem("lrem_by_pow2_29", lrem_by_pow2_29(x), x, 536870912l);
-        longCheckRem("lrem_by_pow2_30", lrem_by_pow2_30(x), x, 1073741824l);
-        longCheckRem("lrem_by_pow2_31", lrem_by_pow2_31(x), x, 2147483648l);
-        longCheckRem("lrem_by_pow2_32", lrem_by_pow2_32(x), x, 4294967296l);
-        longCheckRem("lrem_by_pow2_33", lrem_by_pow2_33(x), x, 8589934592l);
-        longCheckRem("lrem_by_pow2_34", lrem_by_pow2_34(x), x, 17179869184l);
-        longCheckRem("lrem_by_pow2_35", lrem_by_pow2_35(x), x, 34359738368l);
-        longCheckRem("lrem_by_pow2_36", lrem_by_pow2_36(x), x, 68719476736l);
-        longCheckRem("lrem_by_pow2_37", lrem_by_pow2_37(x), x, 137438953472l);
-        longCheckRem("lrem_by_pow2_38", lrem_by_pow2_38(x), x, 274877906944l);
-        longCheckRem("lrem_by_pow2_39", lrem_by_pow2_39(x), x, 549755813888l);
-        longCheckRem("lrem_by_pow2_40", lrem_by_pow2_40(x), x, 1099511627776l);
-        longCheckRem("lrem_by_pow2_41", lrem_by_pow2_41(x), x, 2199023255552l);
-        longCheckRem("lrem_by_pow2_42", lrem_by_pow2_42(x), x, 4398046511104l);
-        longCheckRem("lrem_by_pow2_43", lrem_by_pow2_43(x), x, 8796093022208l);
-        longCheckRem("lrem_by_pow2_44", lrem_by_pow2_44(x), x, 17592186044416l);
-        longCheckRem("lrem_by_pow2_45", lrem_by_pow2_45(x), x, 35184372088832l);
-        longCheckRem("lrem_by_pow2_46", lrem_by_pow2_46(x), x, 70368744177664l);
-        longCheckRem("lrem_by_pow2_47", lrem_by_pow2_47(x), x, 140737488355328l);
-        longCheckRem("lrem_by_pow2_48", lrem_by_pow2_48(x), x, 281474976710656l);
-        longCheckRem("lrem_by_pow2_49", lrem_by_pow2_49(x), x, 562949953421312l);
-        longCheckRem("lrem_by_pow2_50", lrem_by_pow2_50(x), x, 1125899906842624l);
-        longCheckRem("lrem_by_pow2_51", lrem_by_pow2_51(x), x, 2251799813685248l);
-        longCheckRem("lrem_by_pow2_52", lrem_by_pow2_52(x), x, 4503599627370496l);
-        longCheckRem("lrem_by_pow2_53", lrem_by_pow2_53(x), x, 9007199254740992l);
-        longCheckRem("lrem_by_pow2_54", lrem_by_pow2_54(x), x, 18014398509481984l);
-        longCheckRem("lrem_by_pow2_55", lrem_by_pow2_55(x), x, 36028797018963968l);
-        longCheckRem("lrem_by_pow2_56", lrem_by_pow2_56(x), x, 72057594037927936l);
-        longCheckRem("lrem_by_pow2_57", lrem_by_pow2_57(x), x, 144115188075855872l);
-        longCheckRem("lrem_by_pow2_58", lrem_by_pow2_58(x), x, 288230376151711744l);
-        longCheckRem("lrem_by_pow2_59", lrem_by_pow2_59(x), x, 576460752303423488l);
-        longCheckRem("lrem_by_pow2_60", lrem_by_pow2_60(x), x, 1152921504606846976l);
-        longCheckRem("lrem_by_pow2_61", lrem_by_pow2_61(x), x, 2305843009213693952l);
-        longCheckRem("lrem_by_pow2_62", lrem_by_pow2_62(x), x, 4611686018427387904l);
-    }
-
-    public static void main(String[] args) {
-      int i;
-      long l;
-
-      System.out.println("Begin");
-
-      System.out.println("Int: checking some equally spaced dividends...");
-      for (i = -1000; i < 1000; i += 300) {
-          intCheckAll(i);
-          intCheckAll(-i);
-      }
-
-      System.out.println("Int: checking small dividends...");
-      for (i = 1; i < 100; i += 1) {
-          intCheckAll(i);
-          intCheckAll(-i);
-      }
-
-      System.out.println("Int: checking big dividends...");
-      for (i = 0; i < 100; i += 1) {
-          intCheckAll(Integer.MAX_VALUE - i);
-          intCheckAll(Integer.MIN_VALUE + i);
-      }
-
-      System.out.println("Long: checking some equally spaced dividends...");
-      for (l = 0l; l < 1000000000000l; l += 300000000000l) {
-          longCheckAll(l);
-          longCheckAll(-l);
-      }
-
-      System.out.println("Long: checking small dividends...");
-      for (l = 1l; l < 100l; l += 1l) {
-          longCheckAll(l);
-          longCheckAll(-l);
-      }
-
-      System.out.println("Long: checking big dividends...");
-      for (l = 0l; l < 100l; l += 1l) {
-          longCheckAll(Long.MAX_VALUE - l);
-          longCheckAll(Long.MIN_VALUE + l);
-      }
-
-      System.out.println("End");
-    }
-}
diff --git a/test/702-LargeBranchOffset/build b/test/702-LargeBranchOffset/build
index eacf730..20030fa 100644
--- a/test/702-LargeBranchOffset/build
+++ b/test/702-LargeBranchOffset/build
@@ -17,11 +17,7 @@
 # Stop if something fails.
 set -e
 
-# Write out a bunch of source files.
+# Write out the source file.
 cpp -P src/Main.java.in src/Main.java
 
-mkdir classes
-${JAVAC} -d classes src/*.java
-
-${DX} --debug --dex --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+./default-build
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index aa997a6..6ee7a5b 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -16,10 +16,14 @@
 MoveExceptionOnEntry
 EmptySparseSwitch
 b/20224106
+b/17410612
+b/21863767
 b/21873167
 b/21614284
 b/21902684
-b/21863767
+b/22045582
+b/22045582 (int)
+b/22045582 (wide)
 b/21886894
 b/22080519
 b/21645819
diff --git a/test/800-smali/smali/b_17410612.smali b/test/800-smali/smali/b_17410612.smali
new file mode 100644
index 0000000..17718cb
--- /dev/null
+++ b/test/800-smali/smali/b_17410612.smali
@@ -0,0 +1,14 @@
+.class public LB17410612;
+
+# Test that an invoke with a long parameter has the long parameter in
+# a pair. This should fail in the verifier and not an abort in the compiler.
+
+.super Ljava/lang/Object;
+
+.method public static run()V
+    .registers 4
+    const-wide v0, 0          # Make (v0, v1) a long
+    const-wide v2, 0          # Make (v2, v3) a long
+    invoke-static {v0, v3}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
+    return-void
+.end method
diff --git a/test/800-smali/smali/b_22045582.smali b/test/800-smali/smali/b_22045582.smali
new file mode 100644
index 0000000..3cb661a
--- /dev/null
+++ b/test/800-smali/smali/b_22045582.smali
@@ -0,0 +1,13 @@
+.class public LB22045582;
+
+# Fail verification of a method that returns an undefined register even if the return type
+# is unresolved.
+
+.super Ljava/lang/Object;
+
+.method public static run()La/b/c/d/e/nonexistant;
+    .registers 4
+    # v1 is undefined, and the return type cannot be resolved. The Undefined should take
+    # precedence here.
+    return-object v1
+.end method
diff --git a/test/800-smali/smali/b_22045582_int.smali b/test/800-smali/smali/b_22045582_int.smali
new file mode 100644
index 0000000..c79bb30
--- /dev/null
+++ b/test/800-smali/smali/b_22045582_int.smali
@@ -0,0 +1,11 @@
+.class public LB22045582Int;
+
+# Fail verification of a method that returns an undefined integral register.
+
+.super Ljava/lang/Object;
+
+.method public static run()I
+    .registers 4
+    # v1 is undefined here.
+    return v1
+.end method
diff --git a/test/800-smali/smali/b_22045582_wide.smali b/test/800-smali/smali/b_22045582_wide.smali
new file mode 100644
index 0000000..1485000
--- /dev/null
+++ b/test/800-smali/smali/b_22045582_wide.smali
@@ -0,0 +1,11 @@
+.class public LB22045582Wide;
+
+# Fail verification of a method that returns an undefined wide register.
+
+.super Ljava/lang/Object;
+
+.method public static run()J
+    .registers 4
+    # v0/v1 is undefined here.
+    return-wide v0
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index e0872c3..3dbba8d 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -81,12 +81,20 @@
                 null));
         testCases.add(new TestCase("b/20224106", "B20224106", "run", null, new VerifyError(),
                 0));
+        testCases.add(new TestCase("b/17410612", "B17410612", "run", null, new VerifyError(),
+                0));
+        testCases.add(new TestCase("b/21863767", "B21863767", "run", null, null,
+                null));
         testCases.add(new TestCase("b/21873167", "B21873167", "test", null, null, null));
         testCases.add(new TestCase("b/21614284", "B21614284", "test", new Object[] { null },
                 new NullPointerException(), null));
         testCases.add(new TestCase("b/21902684", "B21902684", "test", null, null, null));
-        testCases.add(new TestCase("b/21863767", "B21863767", "run", null, null,
-                null));
+        testCases.add(new TestCase("b/22045582", "B22045582", "run", null, new VerifyError(),
+                0));
+        testCases.add(new TestCase("b/22045582 (int)", "B22045582Int", "run", null,
+                new VerifyError(), 0));
+        testCases.add(new TestCase("b/22045582 (wide)", "B22045582Wide", "run", null,
+                new VerifyError(), 0));
         testCases.add(new TestCase("b/21886894", "B21886894", "test", null, new VerifyError(),
                 null));
         testCases.add(new TestCase("b/22080519", "B22080519", "run", null,
diff --git a/test/802-deoptimization/src/DeoptimizationController.java b/test/802-deoptimization/src/DeoptimizationController.java
index c926669..d6e662d 100644
--- a/test/802-deoptimization/src/DeoptimizationController.java
+++ b/test/802-deoptimization/src/DeoptimizationController.java
@@ -22,24 +22,27 @@
  * Controls deoptimization using dalvik.system.VMDebug class.
  */
 public class DeoptimizationController {
+  private static final String TEMP_FILE_NAME_PREFIX = "test";
+  private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
+
   private static File createTempFile() throws Exception {
     try {
-      return  File.createTempFile("test", ".trace");
+      return  File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
     } catch (IOException e) {
       System.setProperty("java.io.tmpdir", "/data/local/tmp");
       try {
-        return File.createTempFile("test", ".trace");
+        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
       } catch (IOException e2) {
         System.setProperty("java.io.tmpdir", "/sdcard");
-        return File.createTempFile("test", ".trace");
+        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
       }
     }
   }
 
   public static void startDeoptimization() {
+    File tempFile = null;
     try {
-      File tempFile = createTempFile();
-      tempFile.deleteOnExit();
+      tempFile = createTempFile();
       String tempFileName = tempFile.getPath();
 
       VMDebug.startMethodTracing(tempFileName, 0, 0, false, 1000);
@@ -48,6 +51,10 @@
       }
     } catch (Exception exc) {
       exc.printStackTrace(System.err);
+    } finally {
+      if (tempFile != null) {
+        tempFile.delete();
+      }
     }
   }
 
diff --git a/test/955-lambda-smali/expected.txt b/test/955-lambda-smali/expected.txt
new file mode 100644
index 0000000..0a5b5fd
--- /dev/null
+++ b/test/955-lambda-smali/expected.txt
@@ -0,0 +1,8 @@
+SanityCheck
+Hello world! (0-args, no closure)
+ABCD Hello world! (4-args, no closure)
+Caught NPE
+(BoxUnbox) Hello boxing world! (0-args, no closure)
+(BoxUnbox) Caught NPE for unbox-lambda
+(BoxUnbox) Caught NPE for box-lambda
+(BoxUnbox) Caught ClassCastException for unbox-lambda
diff --git a/test/955-lambda-smali/info.txt b/test/955-lambda-smali/info.txt
new file mode 100644
index 0000000..aed5e84
--- /dev/null
+++ b/test/955-lambda-smali/info.txt
@@ -0,0 +1,3 @@
+Smali-based tests for experimental lambda intructions.
+
+Obviously needs to run under ART.
diff --git a/test/955-lambda-smali/run b/test/955-lambda-smali/run
new file mode 100755
index 0000000..2aeca8c
--- /dev/null
+++ b/test/955-lambda-smali/run
@@ -0,0 +1,18 @@
+#!/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.
+
+# Ensure that the lambda experimental opcodes are turned on for dalvikvm and dex2oat
+${RUN} "$@" --runtime-option -Xexperimental-lambdas -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental-lambdas
diff --git a/test/955-lambda-smali/smali/BoxUnbox.smali b/test/955-lambda-smali/smali/BoxUnbox.smali
new file mode 100644
index 0000000..5e66733
--- /dev/null
+++ b/test/955-lambda-smali/smali/BoxUnbox.smali
@@ -0,0 +1,118 @@
+#
+#  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 LBoxUnbox;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static run()V
+.registers 2
+    # Trivial 0-arg hello world
+    create-lambda v0, LBoxUnbox;->doHelloWorld(Ljava/lang/reflect/ArtMethod;)V
+    # TODO: create-lambda should not write to both v0 and v1
+    invoke-lambda v0, {}
+
+    invoke-static {}, LBoxUnbox;->testFailures()V
+    invoke-static {}, LBoxUnbox;->testFailures2()V
+    invoke-static {}, LBoxUnbox;->testFailures3()V
+
+    return-void
+.end method
+
+#TODO: should use a closure type instead of ArtMethod.
+.method public static doHelloWorld(Ljava/lang/reflect/ArtMethod;)V
+    .registers 3 # 1 parameters, 2 locals
+
+    const-string v0, "(BoxUnbox) Hello boxing world! (0-args, no closure)"
+
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+.end method
+
+# Test exceptions are thrown as expected when used opcodes incorrectly
+.method private static testFailures()V
+    .registers 4 # 0 parameters, 4 locals
+
+    const v0, 0  # v0 = null
+    const v1, 0  # v1 = null
+:start
+    unbox-lambda v2, v0, Ljava/lang/reflect/ArtMethod;
+    # attempting to unbox a null lambda will throw NPE
+:end
+    return-void
+
+:handler
+    const-string v2, "(BoxUnbox) Caught NPE for unbox-lambda"
+    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+
+    .catch Ljava/lang/NullPointerException; {:start .. :end} :handler
+.end method
+
+# Test exceptions are thrown as expected when used opcodes incorrectly
+.method private static testFailures2()V
+    .registers 4 # 0 parameters, 4 locals
+
+    const v0, 0  # v0 = null
+    const v1, 0  # v1 = null
+:start
+    box-lambda v2, v0  # attempting to box a null lambda will throw NPE
+:end
+    return-void
+
+    # TODO: refactor testFailures using a goto
+
+:handler
+    const-string v2, "(BoxUnbox) Caught NPE for box-lambda"
+    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+
+    .catch Ljava/lang/NullPointerException; {:start .. :end} :handler
+.end method
+
+# Test exceptions are thrown as expected when used opcodes incorrectly
+.method private static testFailures3()V
+    .registers 4 # 0 parameters, 4 locals
+
+    const-string v0, "This is not a boxed lambda"
+:start
+    # TODO: use \FunctionalType; here instead
+    unbox-lambda v2, v0, Ljava/lang/reflect/ArtMethod;
+    # can't use a string, expects a lambda object here. throws ClassCastException.
+:end
+    return-void
+
+    # TODO: refactor testFailures using a goto
+
+:handler
+    const-string v2, "(BoxUnbox) Caught ClassCastException for unbox-lambda"
+    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+
+    .catch Ljava/lang/ClassCastException; {:start .. :end} :handler
+.end method
diff --git a/test/955-lambda-smali/smali/Main.smali b/test/955-lambda-smali/smali/Main.smali
new file mode 100644
index 0000000..92afd79
--- /dev/null
+++ b/test/955-lambda-smali/smali/Main.smali
@@ -0,0 +1,30 @@
+#
+#  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 LMain;
+
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+    .registers 2
+
+    invoke-static {}, LSanityCheck;->run()I
+    invoke-static {}, LTrivialHelloWorld;->run()V
+    invoke-static {}, LBoxUnbox;->run()V
+
+# TODO: add tests when verification fails
+
+    return-void
+.end method
diff --git a/test/955-lambda-smali/smali/SanityCheck.smali b/test/955-lambda-smali/smali/SanityCheck.smali
new file mode 100644
index 0000000..4c807d7
--- /dev/null
+++ b/test/955-lambda-smali/smali/SanityCheck.smali
@@ -0,0 +1,36 @@
+#
+#  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 LSanityCheck;
+.super Ljava/lang/Object;
+
+
+.method public constructor <init>()V
+.registers 1
+   invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+   return-void
+.end method
+
+# This test is just here to make sure that we can at least execute basic non-lambda
+# functionality such as printing (when lambdas are enabled in the runtime).
+.method public static run()I
+# Don't use too many registers here to avoid hitting the Stack::SanityCheck frame<2KB assert
+.registers 3
+    const-string v0, "SanityCheck"
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+    const v2, 123456
+    return v2
+.end method
diff --git a/test/955-lambda-smali/smali/TrivialHelloWorld.smali b/test/955-lambda-smali/smali/TrivialHelloWorld.smali
new file mode 100644
index 0000000..38ee95a
--- /dev/null
+++ b/test/955-lambda-smali/smali/TrivialHelloWorld.smali
@@ -0,0 +1,94 @@
+#
+#  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 LTrivialHelloWorld;
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+.registers 1
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
+
+.method public static run()V
+.registers 8
+    # Trivial 0-arg hello world
+    create-lambda v0, LTrivialHelloWorld;->doHelloWorld(Ljava/lang/reflect/ArtMethod;)V
+    # TODO: create-lambda should not write to both v0 and v1
+    invoke-lambda v0, {}
+
+    # Slightly more interesting 4-arg hello world
+    create-lambda v2, doHelloWorldArgs(Ljava/lang/reflect/ArtMethod;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+    # TODO: create-lambda should not write to both v2 and v3
+    const-string v4, "A"
+    const-string v5, "B"
+    const-string v6, "C"
+    const-string v7, "D"
+    invoke-lambda v2, {v4, v5, v6, v7}
+
+    invoke-static {}, LTrivialHelloWorld;->testFailures()V
+
+    return-void
+.end method
+
+#TODO: should use a closure type instead of ArtMethod.
+.method public static doHelloWorld(Ljava/lang/reflect/ArtMethod;)V
+    .registers 3 # 1 parameters, 2 locals
+
+    const-string v0, "Hello world! (0-args, no closure)"
+
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+.end method
+
+#TODO: should use a closure type instead of ArtMethod.
+.method public static doHelloWorldArgs(Ljava/lang/reflect/ArtMethod;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+    .registers 7 # 5 parameters, 2 locals
+
+    const-string v0, " Hello world! (4-args, no closure)"
+    sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream;
+
+    invoke-virtual {v1, p1}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V
+    invoke-virtual {v1, p2}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V
+    invoke-virtual {v1, p3}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V
+    invoke-virtual {v1, p4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V
+
+    invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+.end method
+
+# Test exceptions are thrown as expected when used opcodes incorrectly
+.method private static testFailures()V
+    .registers 4 # 0 parameters, 4 locals
+
+    const v0, 0  # v0 = null
+    const v1, 0  # v1 = null
+:start
+    invoke-lambda v0, {}  # invoking a null lambda shall raise an NPE
+:end
+    return-void
+
+:handler
+    const-string v2, "Caught NPE"
+    sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream;
+    invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+
+    return-void
+
+    .catch Ljava/lang/NullPointerException; {:start .. :end} :handler
+.end method
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 57d06c4..fcb9f8a 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -34,7 +34,8 @@
   455-set-vreg/set_vreg_jni.cc \
   457-regs/regs_jni.cc \
   461-get-reference-vreg/get_reference_vreg_jni.cc \
-  466-get-live-vreg/get_live_vreg_jni.cc
+  466-get-live-vreg/get_live_vreg_jni.cc \
+  497-inlining-and-class-loader/clear_dex_cache.cc
 
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ifdef TARGET_2ND_ARCH
@@ -74,6 +75,7 @@
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+    LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
     LOCAL_IS_HOST_MODULE := true
     LOCAL_MULTILIB := both
diff --git a/test/Android.libnativebridgetest.mk b/test/Android.libnativebridgetest.mk
index 5a5f725..e8cc7e4 100644
--- a/test/Android.libnativebridgetest.mk
+++ b/test/Android.libnativebridgetest.mk
@@ -60,6 +60,7 @@
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
     LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+    LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
     LOCAL_SHARED_LIBRARIES := libcutils
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
     ifeq ($(HOST_OS),linux)
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index b1edc3b..c18bb5c 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -257,12 +257,15 @@
 TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
 
 # Tests that are broken with GC stress.
-TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
+# 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
+# hope the second process got into the expected state. The slowness of gcstress makes this bad.
+TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
+  137-cfi
 
 ifneq (,$(filter gcstress,$(GC_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
       $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),gcstress,$(JNI_TYPES), \
-      $(IMAGE_TYPES), $(PICTEST_TYPES), $(DBEUGGABLE_TYPES), $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(ALL_ADDRESS_SIZES))
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
 TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
@@ -371,6 +374,7 @@
   457-regs \
   461-get-reference-vreg \
   466-get-live-vreg \
+  497-inlining-and-class-loader \
 
 ifneq (,$(filter ndebug,$(RUN_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),ndebug,$(PREBUILD_TYPES), \
@@ -419,29 +423,6 @@
 
 TEST_ART_BROKEN_DEFAULT_RUN_TESTS :=
 
-# Known broken tests for Quick's and Optimizing's ARM back ends.
-TEST_ART_BROKEN_ARM_RUN_TESTS := 477-long-to-float-conversion-precision  # b/20413424
-
-ifeq ($(TARGET_ARCH),arm)
-  ifneq (,$(filter 32,$(ALL_ADDRESS_SIZES)))
-    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
-        $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
-        $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_ARM_RUN_TESTS),32)
-  endif
-endif
-
-ifdef TARGET_2ND_ARCH
-  ifeq ($(TARGET_2ND_ARCH),arm)
-    ifneq (,$(filter 32,$(ALL_ADDRESS_SIZES)))
-      ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
-          $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
-          $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_ARM_RUN_TESTS),32)
-    endif
-  endif
-endif
-
-TEST_ART_BROKEN_ARM_RUN_TESTS :=
-
 # Known broken tests for the arm64 optimizing compiler backend.
 TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS :=
 
@@ -512,11 +493,9 @@
 TEST_ART_BROKEN_OPTIMIZING_DEBUGGABLE_RUN_TESTS :=
 
 # Tests that should fail in the read barrier configuration.
-# 098: b/20720510
 # 137: Read barrier forces interpreter. Cannot run this with the interpreter.
 TEST_ART_BROKEN_READ_BARRIER_RUN_TESTS := \
-  098-ddmc \
-  137-cfi \
+  137-cfi
 
 ifeq ($(ART_USE_READ_BARRIER),true)
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -526,18 +505,45 @@
 
 TEST_ART_BROKEN_READ_BARRIER_RUN_TESTS :=
 
-# Tests that should fail in the heap poisoning configuration.
-# 137: Heap poisoning forces interpreter. Cannot run this with the interpreter.
-TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS := \
+# Tests that should fail in the heap poisoning configuration with the default (Quick) compiler.
+# 137: Quick punts to the interpreter, and this test cannot run this with the interpreter.
+TEST_ART_BROKEN_DEFAULT_HEAP_POISONING_RUN_TESTS := \
+  137-cfi
+# Tests that should fail in the heap poisoning configuration with the Optimizing compiler.
+# 055-enum-performance: Exceeds run time limits due to heap poisoning instrumentation.
+TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS := \
+  055-enum-performance
+# Tests that should fail in the heap poisoning configuration with the interpreter.
+# 137: Cannot run this with the interpreter.
+TEST_ART_BROKEN_INTERPRETER_HEAP_POISONING_RUN_TESTS := \
   137-cfi
 
 ifeq ($(ART_HEAP_POISONING),true)
-  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
-      $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
-      $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),$(TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+  ifneq (,$(filter default,$(COMPILER_TYPES)))
+    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES), \
+        $(PREBUILD_TYPES),default,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+        $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES), \
+        $(TEST_ART_BROKEN_DEFAULT_HEAP_POISONING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+  endif
+
+  ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
+    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES), \
+        $(PREBUILD_TYPES),optimizing,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+        $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES), \
+        $(TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+  endif
+
+  ifneq (,$(filter interpreter,$(COMPILER_TYPES)))
+    ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES), \
+        $(PREBUILD_TYPES),interpreter,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+        $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES), \
+        $(TEST_ART_BROKEN_INTERPRETER_HEAP_POISONING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+  endif
 endif
 
-TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS :=
+TEST_ART_BROKEN_INTERPRETER_HEAP_POISONING_RUN_TESTS :=
+TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS :=
+TEST_ART_BROKEN_DEFAULT_HEAP_POISONING_RUN_TESTS :=
 
 # Clear variables ahead of appending to them when defining tests.
 $(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=))
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 7995bd5..c281bca 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -18,6 +18,7 @@
 set -e
 
 DX_FLAGS=""
+SKIP_DX_MERGER="false"
 
 while true; do
   if [ "x$1" = "x--dx-option" ]; then
@@ -38,6 +39,11 @@
   exit 0
 fi
 
+if ! [ -d src ] && ! [ -d src2 ]; then
+  # No src directory? Then forget about trying to run dx.
+  SKIP_DX_MERGER="true"
+fi
+
 if [ -d src-multidex ]; then
   # Jack does not support this configuration unless we specify how to partition the DEX file
   # with a .jpp file.
@@ -80,7 +86,7 @@
     ${JAVAC} -d classes `find src2 -name '*.java'`
   fi
 
-  if [ ${NEED_DEX} = "true" ]; then
+  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
@@ -88,8 +94,14 @@
 
 if [ -d smali ]; then
   # Compile Smali classes
-  ${SMALI} -JXmx256m --output smali_classes.dex `find smali -name '*.smali'`
-  ${DXMERGER} classes.dex classes.dex smali_classes.dex
+  ${SMALI} -JXmx256m --experimental --api-level 23 --output smali_classes.dex `find smali -name '*.smali'`
+
+  # Don't bother with dexmerger if we provide our own main function in a smali file.
+  if [ ${SKIP_DX_MERGER} = "false" ]; then
+    ${DXMERGER} classes.dex classes.dex smali_classes.dex
+  else
+    mv smali_classes.dex classes.dex
+  fi
 fi
 
 if [ -d src-ex ]; then
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 240ed41..842d87e 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -296,6 +296,10 @@
 else
     FLAGS="$FLAGS -Xnorelocate"
     COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
+    if [ "$HOST" = "y" ]; then
+        # Increase ulimit to 64MB in case we are running hprof test.
+        ulimit -S 64000 || exit 1
+    fi
 fi
 
 if [ "$HOST" = "n" ]; then
@@ -405,6 +409,10 @@
     export DYLD_LIBRARY_PATH="${ANDROID_ROOT}/lib"
     export PATH="$PATH:${ANDROID_ROOT}/bin"
 
+    # Temporarily disable address space layout randomization (ASLR).
+    # This is needed on the host so that the linker loads core.oat at the necessary address.
+    export LD_USE_LOAD_BIAS=1
+
     cmdline="$dalvikvm_cmdline"
 
     if [ "$TIME_OUT" = "y" ]; then
@@ -450,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 8410387..f5fff09a 100755
--- a/test/run-test
+++ b/test/run-test
@@ -39,7 +39,7 @@
 else
   tmp_dir="${TMPDIR}/$USER/${test_dir}"
 fi
-checker="${progdir}/../tools/checker.py"
+checker="${progdir}/../tools/checker/checker.py"
 
 export JAVA="java"
 export JAVAC="javac -g"
@@ -116,7 +116,7 @@
 check_cmd="check"
 output="output.txt"
 build_output="build-output.txt"
-cfg_output="cfg-output.txt"
+cfg_output="graph.cfg"
 lib="libartd.so"
 run_args="--quiet"
 build_args=""
@@ -138,6 +138,7 @@
 gc_verify="false"
 gc_stress="false"
 always_clean="no"
+never_clean="no"
 have_dex2oat="yes"
 have_patchoat="yes"
 have_image="yes"
@@ -322,6 +323,9 @@
     elif [ "x$1" = "x--always-clean" ]; then
         always_clean="yes"
         shift
+    elif [ "x$1" = "x--never-clean" ]; then
+        never_clean="yes"
+        shift
     elif [ "x$1" = "x--dex2oat-swap" ]; then
         run_args="${run_args} --dex2oat-swap"
         shift
@@ -352,7 +356,7 @@
   run_args="${run_args} --runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc"
 fi
 if [ "$gc_stress" = "true" ]; then
-  run_args="${run_args} --runtime-option -Xgc:SS --runtime-option -Xms2m --runtime-option -Xmx2m"
+  run_args="${run_args} --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
 fi
 if [ "$trace" = "true" ]; then
     run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000"
@@ -536,6 +540,7 @@
         echo "    --gcstress            Run with gc stress testing"
         echo "    --gcverify            Run with gc verification"
         echo "    --always-clean        Delete the test files even if the test fails."
+        echo "    --never-clean         Keep the test files even if the test succeeds."
         echo "    --android-root [path] The path on target for the android root. (/system by default)."
         echo "    --dex2oat-swap        Use a dex2oat swap file."
     ) 1>&2
@@ -568,14 +573,20 @@
 
 if [ '!' -r "$build" ]; then
     cp "${progdir}/etc/default-build" build
+else
+    cp "${progdir}/etc/default-build" .
 fi
 
 if [ '!' -r "$run" ]; then
     cp "${progdir}/etc/default-run" run
+else
+    cp "${progdir}/etc/default-run" .
 fi
 
 if [ '!' -r "$check_cmd" ]; then
     cp "${progdir}/etc/default-check" check
+else
+    cp "${progdir}/etc/default-check" .
 fi
 
 chmod 755 "$build"
@@ -745,7 +756,7 @@
 ) 1>&2
 
 # Clean up test files.
-if [ "$always_clean" = "yes" -o "$good" = "yes" ]; then
+if [ "$always_clean" = "yes" -o "$good" = "yes" ] && [ "$never_clean" = "no" ]; then
     cd "$oldwd"
     rm -rf "$tmp_dir"
     if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then
diff --git a/tools/art b/tools/art
index 2ee8940..676d6ae 100644
--- a/tools/art
+++ b/tools/art
@@ -93,6 +93,7 @@
   ANDROID_ROOT=$ANDROID_ROOT \
   LD_LIBRARY_PATH=$LD_LIBRARY_PATH \
   PATH=$ANDROID_ROOT/bin:$PATH \
+  LD_USE_LOAD_BIAS=1 \
   $invoke_with $ANDROID_ROOT/bin/$DALVIKVM $lib \
     -XXlib:$LIBART \
     -Xnorelocate \
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
new file mode 100755
index 0000000..62fd67b
--- /dev/null
+++ b/tools/buildbot-build.sh
@@ -0,0 +1,77 @@
+#!/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.
+
+if [ ! -d art ]; then
+  echo "Script needs to be run at the root of the android tree"
+  exit 1
+fi
+
+common_targets="vogar vogar.jar core-tests apache-harmony-jdwp-tests-hostdex out/host/linux-x86/bin/adb jsr166-tests"
+android_root="/data/local/tmp/system"
+linker="linker"
+mode="target"
+j_arg="-j$(nproc)"
+make_command=
+
+if [[ "$TARGET_PRODUCT" == "armv8" ]]; then
+  linker="linker64"
+fi
+
+if [[ "$ART_TEST_ANDROID_ROOT" != "" ]]; then
+  android_root="$ART_TEST_ANDROID_ROOT"
+fi
+
+while true; do
+  if [[ "$1" == "--host" ]]; then
+    mode="host"
+    shift
+  elif [[ "$1" == "--target" ]]; then
+    mode="target"
+    shift
+  elif [[ "$1" == "--32" ]]; then
+    linker="linker"
+    shift
+  elif [[ "$1" == "--64" ]]; then
+    linker="linker64"
+    shift
+  elif [[ "$1" == "--android-root" ]]; then
+    shift
+    android_root=$1
+    shift
+  elif [[ "$1" == -j* ]]; then
+    j_arg=$1
+    shift
+  elif [[ "$1" == "" ]]; then
+    break
+  fi
+done
+
+if [[ $mode == "host" ]]; then
+  make_command="make $j_arg build-art-host-tests $common_targets out/host/linux-x86/lib/libjavacoretests.so out/host/linux-x86/lib64/libjavacoretests.so"
+  echo "Executing $make_command"
+  $make_command
+elif [[ $mode == "target" ]]; then
+  # We need to provide our own linker in case the linker on the device
+  # is out of date.
+  env="TARGET_GLOBAL_LDFLAGS=-Wl,-dynamic-linker=$android_root/bin/$linker"
+  # Use '-e' to force the override of TARGET_GLOBAL_LDFLAGS.
+  # Also, we build extra tools that will be used by tests, so that
+  # they are compiled with our own linker.
+  make_command="make -e $j_arg build-art-target-tests $common_targets libjavacrypto libjavacoretests linker toybox toolbox sh"
+  echo "Executing env $env $make_command"
+  env $env $make_command
+fi
+
diff --git a/tools/checker.py b/tools/checker.py
deleted file mode 100755
index 0bce236..0000000
--- a/tools/checker.py
+++ /dev/null
@@ -1,777 +0,0 @@
-#!/usr/bin/env python2
-#
-# Copyright (C) 2014 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.
-
-
-# Checker is a testing tool which compiles a given test file and compares the
-# state of the control-flow graph before and after each optimization pass
-# against a set of assertions specified alongside the tests.
-#
-# Tests are written in Java, turned into DEX and compiled with the Optimizing
-# compiler. "Check lines" are assertions formatted as comments of the Java file.
-# They begin with prefix 'CHECK' followed by a pattern that the engine attempts
-# to match in the compiler-generated output.
-#
-# Assertions are tested in groups which correspond to the individual compiler
-# passes. Each group of check lines therefore must start with a 'CHECK-START'
-# header which specifies the output group it should be tested against. The group
-# name must exactly match one of the groups recognized in the output (they can
-# be listed with the '--list-groups' command-line flag).
-#
-# Matching of check lines is carried out in the order of appearance in the
-# source file. There are three types of check lines:
-#  - CHECK:     Must match an output line which appears in the output group
-#               later than lines matched against any preceeding checks. Output
-#               lines must therefore match the check lines in the same order.
-#               These are referred to as "in-order" checks in the code.
-#  - CHECK-DAG: Must match an output line which appears in the output group
-#               later than lines matched against any preceeding in-order checks.
-#               In other words, the order of output lines does not matter
-#               between consecutive DAG checks.
-#  - CHECK-NOT: Must not match any output line which appears in the output group
-#               later than lines matched against any preceeding checks and
-#               earlier than lines matched against any subsequent checks.
-#               Surrounding non-negative checks (or boundaries of the group)
-#               therefore create a scope within which the assertion is verified.
-#
-# Check-line patterns are treated as plain text rather than regular expressions
-# but are whitespace agnostic.
-#
-# Actual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If
-# curly brackets need to be used inside the body of the regex, they need to be
-# enclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse
-# the invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'.
-#
-# Regex patterns can be named and referenced later. A new variable is defined
-# with '[[name:regex]]' and can be referenced with '[[name]]'. Variables are
-# only valid within the scope of the defining group. Within a group they cannot
-# be redefined or used undefined.
-#
-# Example:
-#   The following assertions can be placed in a Java source file:
-#
-#   // CHECK-START: int MyClass.MyMethod() constant_folding (after)
-#   // CHECK:         [[ID:i[0-9]+]] IntConstant {{11|22}}
-#   // CHECK:                        Return [ [[ID]] ]
-#
-#   The engine will attempt to match the check lines against the output of the
-#   group named on the first line. Together they verify that the CFG after
-#   constant folding returns an integer constant with value either 11 or 22.
-#
-
-from __future__ import print_function
-import argparse
-import os
-import re
-import shutil
-import sys
-import tempfile
-
-class Logger(object):
-
-  class Level(object):
-    NoOutput, Error, Info = range(3)
-
-  class Color(object):
-    Default, Blue, Gray, Purple, Red = range(5)
-
-    @staticmethod
-    def terminalCode(color, out=sys.stdout):
-      if not out.isatty():
-        return ''
-      elif color == Logger.Color.Blue:
-        return '\033[94m'
-      elif color == Logger.Color.Gray:
-        return '\033[37m'
-      elif color == Logger.Color.Purple:
-        return '\033[95m'
-      elif color == Logger.Color.Red:
-        return '\033[91m'
-      else:
-        return '\033[0m'
-
-  Verbosity = Level.Info
-
-  @staticmethod
-  def log(text, level=Level.Info, color=Color.Default, newLine=True, out=sys.stdout):
-    if level <= Logger.Verbosity:
-      text = Logger.Color.terminalCode(color, out) + text + \
-             Logger.Color.terminalCode(Logger.Color.Default, out)
-      if newLine:
-        print(text, file=out)
-      else:
-        print(text, end="", file=out)
-      out.flush()
-
-  @staticmethod
-  def fail(msg, file=None, line=-1):
-    location = ""
-    if file:
-      location += file + ":"
-    if line > 0:
-      location += str(line) + ":"
-    if location:
-      location += " "
-
-    Logger.log(location, Logger.Level.Error, color=Logger.Color.Gray, newLine=False, out=sys.stderr)
-    Logger.log("error: ", Logger.Level.Error, color=Logger.Color.Red, newLine=False, out=sys.stderr)
-    Logger.log(msg, Logger.Level.Error, out=sys.stderr)
-    sys.exit(msg)
-
-  @staticmethod
-  def startTest(name):
-    Logger.log("TEST ", color=Logger.Color.Purple, newLine=False)
-    Logger.log(name + "... ", newLine=False)
-
-  @staticmethod
-  def testPassed():
-    Logger.log("PASS", color=Logger.Color.Blue)
-
-  @staticmethod
-  def testFailed(msg, file=None, line=-1):
-    Logger.log("FAIL", color=Logger.Color.Red)
-    Logger.fail(msg, file, line)
-
-class CommonEqualityMixin:
-  """Mixin for class equality as equality of the fields."""
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__)
-           and self.__dict__ == other.__dict__)
-
-  def __ne__(self, other):
-    return not self.__eq__(other)
-
-  def __repr__(self):
-    return "<%s: %s>" % (type(self).__name__, str(self.__dict__))
-
-
-class CheckElement(CommonEqualityMixin):
-  """Single element of the check line."""
-
-  class Variant(object):
-    """Supported language constructs."""
-    Text, Pattern, VarRef, VarDef, Separator = range(5)
-
-  rStartOptional = r"("
-  rEndOptional = r")?"
-
-  rName = r"([a-zA-Z][a-zA-Z0-9]*)"
-  rRegex = r"(.+?)"
-  rPatternStartSym = r"(\{\{)"
-  rPatternEndSym = r"(\}\})"
-  rVariableStartSym = r"(\[\[)"
-  rVariableEndSym = r"(\]\])"
-  rVariableSeparator = r"(:)"
-
-  regexPattern = rPatternStartSym + rRegex + rPatternEndSym
-  regexVariable = rVariableStartSym + \
-                    rName + \
-                    (rStartOptional + rVariableSeparator + rRegex + rEndOptional) + \
-                  rVariableEndSym
-
-  def __init__(self, variant, name, pattern):
-    self.variant = variant
-    self.name = name
-    self.pattern = pattern
-
-  @staticmethod
-  def newSeparator():
-    return CheckElement(CheckElement.Variant.Separator, None, None)
-
-  @staticmethod
-  def parseText(text):
-    return CheckElement(CheckElement.Variant.Text, None, re.escape(text))
-
-  @staticmethod
-  def parsePattern(patternElem):
-    return CheckElement(CheckElement.Variant.Pattern, None, patternElem[2:-2])
-
-  @staticmethod
-  def parseVariable(varElem):
-    colonPos = varElem.find(":")
-    if colonPos == -1:
-      # Variable reference
-      name = varElem[2:-2]
-      return CheckElement(CheckElement.Variant.VarRef, name, None)
-    else:
-      # Variable definition
-      name = varElem[2:colonPos]
-      body = varElem[colonPos+1:-2]
-      return CheckElement(CheckElement.Variant.VarDef, name, body)
-
-class CheckLine(CommonEqualityMixin):
-  """Representation of a single assertion in the check file formed of one or
-     more regex elements. Matching against an output line is successful only
-     if all regex elements can be matched in the given order."""
-
-  class Variant(object):
-    """Supported types of assertions."""
-    InOrder, DAG, Not = range(3)
-
-  def __init__(self, content, variant=Variant.InOrder, fileName=None, lineNo=-1):
-    self.fileName = fileName
-    self.lineNo = lineNo
-    self.content = content.strip()
-
-    self.variant = variant
-    self.lineParts = self.__parse(self.content)
-    if not self.lineParts:
-      Logger.fail("Empty check line", self.fileName, self.lineNo)
-
-    if self.variant == CheckLine.Variant.Not:
-      for elem in self.lineParts:
-        if elem.variant == CheckElement.Variant.VarDef:
-          Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
-
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__) and
-            self.variant == other.variant and
-            self.lineParts == other.lineParts)
-
-  # Returns True if the given Match object was at the beginning of the line.
-  def __isMatchAtStart(self, match):
-    return (match is not None) and (match.start() == 0)
-
-  # Takes in a list of Match objects and returns the minimal start point among
-  # them. If there aren't any successful matches it returns the length of
-  # the searched string.
-  def __firstMatch(self, matches, string):
-    starts = map(lambda m: len(string) if m is None else m.start(), matches)
-    return min(starts)
-
-  # This method parses the content of a check line stripped of the initial
-  # comment symbol and the CHECK keyword.
-  def __parse(self, line):
-    lineParts = []
-    # Loop as long as there is something to parse.
-    while line:
-      # Search for the nearest occurrence of the special markers.
-      matchWhitespace = re.search(r"\s+", line)
-      matchPattern = re.search(CheckElement.regexPattern, line)
-      matchVariable = re.search(CheckElement.regexVariable, line)
-
-      # If one of the above was identified at the current position, extract them
-      # from the line, parse them and add to the list of line parts.
-      if self.__isMatchAtStart(matchWhitespace):
-        # A whitespace in the check line creates a new separator of line parts.
-        # This allows for ignored output between the previous and next parts.
-        line = line[matchWhitespace.end():]
-        lineParts.append(CheckElement.newSeparator())
-      elif self.__isMatchAtStart(matchPattern):
-        pattern = line[0:matchPattern.end()]
-        line = line[matchPattern.end():]
-        lineParts.append(CheckElement.parsePattern(pattern))
-      elif self.__isMatchAtStart(matchVariable):
-        var = line[0:matchVariable.end()]
-        line = line[matchVariable.end():]
-        lineParts.append(CheckElement.parseVariable(var))
-      else:
-        # If we're not currently looking at a special marker, this is a plain
-        # text match all the way until the first special marker (or the end
-        # of the line).
-        firstMatch = self.__firstMatch([ matchWhitespace, matchPattern, matchVariable ], line)
-        text = line[0:firstMatch]
-        line = line[firstMatch:]
-        lineParts.append(CheckElement.parseText(text))
-    return lineParts
-
-  # Returns the regex pattern to be matched in the output line. Variable
-  # references are substituted with their current values provided in the
-  # 'varState' argument.
-  # An exception is raised if a referenced variable is undefined.
-  def __generatePattern(self, linePart, varState):
-    if linePart.variant == CheckElement.Variant.VarRef:
-      try:
-        return re.escape(varState[linePart.name])
-      except KeyError:
-        Logger.testFailed("Use of undefined variable \"" + linePart.name + "\"",
-                          self.fileName, self.lineNo)
-    else:
-      return linePart.pattern
-
-  def __isSeparated(self, outputLine, matchStart):
-    return (matchStart == 0) or (outputLine[matchStart - 1:matchStart].isspace())
-
-  # Attempts to match the check line against a line from the output file with
-  # the given initial variable values. It returns the new variable state if
-  # successful and None otherwise.
-  def match(self, outputLine, initialVarState):
-    # Do the full matching on a shadow copy of the variable state. If the
-    # matching fails half-way, we will not need to revert the state.
-    varState = dict(initialVarState)
-
-    matchStart = 0
-    isAfterSeparator = True
-
-    # Now try to parse all of the parts of the check line in the right order.
-    # Variable values are updated on-the-fly, meaning that a variable can
-    # be referenced immediately after its definition.
-    for part in self.lineParts:
-      if part.variant == CheckElement.Variant.Separator:
-        isAfterSeparator = True
-        continue
-
-      # Find the earliest match for this line part.
-      pattern = self.__generatePattern(part, varState)
-      while True:
-        match = re.search(pattern, outputLine[matchStart:])
-        if (match is None) or (not isAfterSeparator and not self.__isMatchAtStart(match)):
-          return None
-        matchEnd = matchStart + match.end()
-        matchStart += match.start()
-
-        # Check if this is a valid match if we expect a whitespace separator
-        # before the matched text. Otherwise loop and look for another match.
-        if not isAfterSeparator or self.__isSeparated(outputLine, matchStart):
-          break
-        else:
-          matchStart += 1
-
-      if part.variant == CheckElement.Variant.VarDef:
-        if part.name in varState:
-          Logger.testFailed("Multiple definitions of variable \"" + part.name + "\"",
-                            self.fileName, self.lineNo)
-        varState[part.name] = outputLine[matchStart:matchEnd]
-
-      matchStart = matchEnd
-      isAfterSeparator = False
-
-    # All parts were successfully matched. Return the new variable state.
-    return varState
-
-
-class CheckGroup(CommonEqualityMixin):
-  """Represents a named collection of check lines which are to be matched
-     against an output group of the same name."""
-
-  def __init__(self, name, lines, fileName=None, lineNo=-1):
-    self.fileName = fileName
-    self.lineNo = lineNo
-
-    if not name:
-      Logger.fail("Check group does not have a name", self.fileName, self.lineNo)
-    if not lines:
-      Logger.fail("Check group does not have a body", self.fileName, self.lineNo)
-
-    self.name = name
-    self.lines = lines
-
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__) and
-            self.name == other.name and
-            self.lines == other.lines)
-
-  def __headAndTail(self, list):
-    return list[0], list[1:]
-
-  # Splits a list of check lines at index 'i' such that lines[i] is the first
-  # element whose variant is not equal to the given parameter.
-  def __splitByVariant(self, lines, variant):
-    i = 0
-    while i < len(lines) and lines[i].variant == variant:
-      i += 1
-    return lines[:i], lines[i:]
-
-  # Extracts the first sequence of check lines which are independent of each
-  # other's match location, i.e. either consecutive DAG lines or a single
-  # InOrder line. Any Not lines preceeding this sequence are also extracted.
-  def __nextIndependentChecks(self, checkLines):
-    notChecks, checkLines = self.__splitByVariant(checkLines, CheckLine.Variant.Not)
-    if not checkLines:
-      return notChecks, [], []
-
-    head, tail = self.__headAndTail(checkLines)
-    if head.variant == CheckLine.Variant.InOrder:
-      return notChecks, [head], tail
-    else:
-      assert head.variant == CheckLine.Variant.DAG
-      independentChecks, checkLines = self.__splitByVariant(checkLines, CheckLine.Variant.DAG)
-      return notChecks, independentChecks, checkLines
-
-  # If successful, returns the line number of the first output line matching the
-  # check line and the updated variable state. Otherwise returns -1 and None,
-  # respectively. The 'lineFilter' parameter can be used to supply a list of
-  # line numbers (counting from 1) which should be skipped.
-  def __findFirstMatch(self, checkLine, outputLines, startLineNo, lineFilter, varState):
-    matchLineNo = startLineNo
-    for outputLine in outputLines:
-      if matchLineNo not in lineFilter:
-        newVarState = checkLine.match(outputLine, varState)
-        if newVarState is not None:
-          return matchLineNo, newVarState
-      matchLineNo += 1
-    return -1, None
-
-  # Matches the given positive check lines against the output in order of
-  # appearance. Variable state is propagated but the scope of the search remains
-  # the same for all checks. Each output line can only be matched once.
-  # If all check lines are matched, the resulting variable state is returned
-  # together with the remaining output. The function also returns output lines
-  # which appear before either of the matched lines so they can be tested
-  # against Not checks.
-  def __matchIndependentChecks(self, checkLines, outputLines, startLineNo, varState):
-    # If no checks are provided, skip over the entire output.
-    if not checkLines:
-      return outputLines, [], startLineNo + len(outputLines), varState
-
-    # Keep track of which lines have been matched.
-    matchedLines = []
-
-    # Find first unused output line which matches each check line.
-    for checkLine in checkLines:
-      matchLineNo, varState = \
-        self.__findFirstMatch(checkLine, outputLines, startLineNo, matchedLines, varState)
-      if varState is None:
-        Logger.testFailed("Could not match check line \"" + checkLine.content + "\" " +
-                          "starting from output line " + str(startLineNo),
-                          self.fileName, checkLine.lineNo)
-      matchedLines.append(matchLineNo)
-
-    # Return new variable state and the output lines which lie outside the
-    # match locations of this independent group.
-    minMatchLineNo = min(matchedLines)
-    maxMatchLineNo = max(matchedLines)
-    preceedingLines = outputLines[:minMatchLineNo - startLineNo]
-    remainingLines = outputLines[maxMatchLineNo - startLineNo + 1:]
-    return preceedingLines, remainingLines, maxMatchLineNo + 1, varState
-
-  # Makes sure that the given check lines do not match any of the given output
-  # lines. Variable state does not change.
-  def __matchNotLines(self, checkLines, outputLines, startLineNo, varState):
-    for checkLine in checkLines:
-      assert checkLine.variant == CheckLine.Variant.Not
-      matchLineNo, matchVarState = \
-        self.__findFirstMatch(checkLine, outputLines, startLineNo, [], varState)
-      if matchVarState is not None:
-        Logger.testFailed("CHECK-NOT line \"" + checkLine.content + "\" matches output line " + \
-                          str(matchLineNo), self.fileName, checkLine.lineNo)
-
-  # Matches the check lines in this group against an output group. It is
-  # responsible for running the checks in the right order and scope, and
-  # for propagating the variable state between the check lines.
-  def match(self, outputGroup):
-    varState = {}
-    checkLines = self.lines
-    outputLines = outputGroup.body
-    startLineNo = outputGroup.lineNo
-
-    while checkLines:
-      # Extract the next sequence of location-independent checks to be matched.
-      notChecks, independentChecks, checkLines = self.__nextIndependentChecks(checkLines)
-
-      # Match the independent checks.
-      notOutput, outputLines, newStartLineNo, newVarState = \
-        self.__matchIndependentChecks(independentChecks, outputLines, startLineNo, varState)
-
-      # Run the Not checks against the output lines which lie between the last
-      # two independent groups or the bounds of the output.
-      self.__matchNotLines(notChecks, notOutput, startLineNo, varState)
-
-      # Update variable state.
-      startLineNo = newStartLineNo
-      varState = newVarState
-
-class OutputGroup(CommonEqualityMixin):
-  """Represents a named part of the test output against which a check group of
-     the same name is to be matched."""
-
-  def __init__(self, name, body, fileName=None, lineNo=-1):
-    if not name:
-      Logger.fail("Output group does not have a name", fileName, lineNo)
-    if not body:
-      Logger.fail("Output group does not have a body", fileName, lineNo)
-
-    self.name = name
-    self.body = body
-    self.lineNo = lineNo
-
-  def __eq__(self, other):
-    return (isinstance(other, self.__class__) and
-            self.name == other.name and
-            self.body == other.body)
-
-
-class FileSplitMixin(object):
-  """Mixin for representing text files which need to be split into smaller
-     chunks before being parsed."""
-
-  def _parseStream(self, stream):
-    lineNo = 0
-    allGroups = []
-    currentGroup = None
-
-    for line in stream:
-      lineNo += 1
-      line = line.strip()
-      if not line:
-        continue
-
-      # Let the child class process the line and return information about it.
-      # The _processLine method can modify the content of the line (or delete it
-      # entirely) and specify whether it starts a new group.
-      processedLine, newGroupName = self._processLine(line, lineNo)
-      if newGroupName is not None:
-        currentGroup = (newGroupName, [], lineNo)
-        allGroups.append(currentGroup)
-      if processedLine is not None:
-        if currentGroup is not None:
-          currentGroup[1].append(processedLine)
-        else:
-          self._exceptionLineOutsideGroup(line, lineNo)
-
-    # Finally, take the generated line groups and let the child class process
-    # each one before storing the final outcome.
-    return list(map(lambda group: self._processGroup(group[0], group[1], group[2]), allGroups))
-
-
-class CheckFile(FileSplitMixin):
-  """Collection of check groups extracted from the input test file."""
-
-  def __init__(self, prefix, checkStream, fileName=None):
-    self.fileName = fileName
-    self.prefix = prefix
-    self.groups = self._parseStream(checkStream)
-
-  # Attempts to parse a check line. The regex searches for a comment symbol
-  # followed by the CHECK keyword, given attribute and a colon at the very
-  # beginning of the line. Whitespaces are ignored.
-  def _extractLine(self, prefix, line):
-    rIgnoreWhitespace = r"\s*"
-    rCommentSymbols = [r"//", r"#"]
-    regexPrefix = rIgnoreWhitespace + \
-                  r"(" + r"|".join(rCommentSymbols) + r")" + \
-                  rIgnoreWhitespace + \
-                  prefix + r":"
-
-    # The 'match' function succeeds only if the pattern is matched at the
-    # beginning of the line.
-    match = re.match(regexPrefix, line)
-    if match is not None:
-      return line[match.end():].strip()
-    else:
-      return None
-
-  # This function is invoked on each line of the check file and returns a pair
-  # which instructs the parser how the line should be handled. If the line is to
-  # be included in the current check group, it is returned in the first value.
-  # If the line starts a new check group, the name of the group is returned in
-  # the second value.
-  def _processLine(self, line, lineNo):
-    # Lines beginning with 'CHECK-START' start a new check group.
-    startLine = self._extractLine(self.prefix + "-START", line)
-    if startLine is not None:
-      return None, startLine
-
-    # Lines starting only with 'CHECK' are matched in order.
-    plainLine = self._extractLine(self.prefix, line)
-    if plainLine is not None:
-      return (plainLine, CheckLine.Variant.InOrder, lineNo), None
-
-    # 'CHECK-DAG' lines are no-order assertions.
-    dagLine = self._extractLine(self.prefix + "-DAG", line)
-    if dagLine is not None:
-      return (dagLine, CheckLine.Variant.DAG, lineNo), None
-
-    # 'CHECK-NOT' lines are no-order negative assertions.
-    notLine = self._extractLine(self.prefix + "-NOT", line)
-    if notLine is not None:
-      return (notLine, CheckLine.Variant.Not, lineNo), None
-
-    # Other lines are ignored.
-    return None, None
-
-  def _exceptionLineOutsideGroup(self, line, lineNo):
-    Logger.fail("Check line not inside a group", self.fileName, lineNo)
-
-  # Constructs a check group from the parser-collected check lines.
-  def _processGroup(self, name, lines, lineNo):
-    checkLines = list(map(lambda line: CheckLine(line[0], line[1], self.fileName, line[2]), lines))
-    return CheckGroup(name, checkLines, self.fileName, lineNo)
-
-  def match(self, outputFile):
-    for checkGroup in self.groups:
-      # TODO: Currently does not handle multiple occurrences of the same group
-      # name, e.g. when a pass is run multiple times. It will always try to
-      # match a check group against the first output group of the same name.
-      outputGroup = outputFile.findGroup(checkGroup.name)
-      if outputGroup is None:
-        Logger.fail("Group \"" + checkGroup.name + "\" not found in the output",
-                    self.fileName, checkGroup.lineNo)
-      Logger.startTest(checkGroup.name)
-      checkGroup.match(outputGroup)
-      Logger.testPassed()
-
-
-class OutputFile(FileSplitMixin):
-  """Representation of the output generated by the test and split into groups
-     within which the checks are performed.
-
-     C1visualizer format is parsed with a state machine which differentiates
-     between the 'compilation' and 'cfg' blocks. The former marks the beginning
-     of a method. It is parsed for the method's name but otherwise ignored. Each
-     subsequent CFG block represents one stage of the compilation pipeline and
-     is parsed into an output group named "<method name> <pass name>".
-     """
-
-  class ParsingState:
-    OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4)
-
-  def __init__(self, outputStream, fileName=None):
-    self.fileName = fileName
-
-    # Initialize the state machine
-    self.lastMethodName = None
-    self.state = OutputFile.ParsingState.OutsideBlock
-    self.groups = self._parseStream(outputStream)
-
-  # This function is invoked on each line of the output file and returns a pair
-  # which instructs the parser how the line should be handled. If the line is to
-  # be included in the current group, it is returned in the first value. If the
-  # line starts a new output group, the name of the group is returned in the
-  # second value.
-  def _processLine(self, line, lineNo):
-    if self.state == OutputFile.ParsingState.StartingCfgBlock:
-      # Previous line started a new 'cfg' block which means that this one must
-      # contain the name of the pass (this is enforced by C1visualizer).
-      if re.match("name\s+\"[^\"]+\"", line):
-        # Extract the pass name, prepend it with the name of the method and
-        # return as the beginning of a new group.
-        self.state = OutputFile.ParsingState.InsideCfgBlock
-        return (None, self.lastMethodName + " " + line.split("\"")[1])
-      else:
-        Logger.fail("Expected output group name", self.fileName, lineNo)
-
-    elif self.state == OutputFile.ParsingState.InsideCfgBlock:
-      if line == "end_cfg":
-        self.state = OutputFile.ParsingState.OutsideBlock
-        return (None, None)
-      else:
-        return (line, None)
-
-    elif self.state == OutputFile.ParsingState.InsideCompilationBlock:
-      # Search for the method's name. Format: method "<name>"
-      if re.match("method\s+\"[^\"]*\"", line):
-        methodName = line.split("\"")[1].strip()
-        if not methodName:
-          Logger.fail("Empty method name in output", self.fileName, lineNo)
-        self.lastMethodName = methodName
-      elif line == "end_compilation":
-        self.state = OutputFile.ParsingState.OutsideBlock
-      return (None, None)
-
-    else:
-      assert self.state == OutputFile.ParsingState.OutsideBlock
-      if line == "begin_cfg":
-        # The line starts a new group but we'll wait until the next line from
-        # which we can extract the name of the pass.
-        if self.lastMethodName is None:
-          Logger.fail("Expected method header", self.fileName, lineNo)
-        self.state = OutputFile.ParsingState.StartingCfgBlock
-        return (None, None)
-      elif line == "begin_compilation":
-        self.state = OutputFile.ParsingState.InsideCompilationBlock
-        return (None, None)
-      else:
-        Logger.fail("Output line not inside a group", self.fileName, lineNo)
-
-  # Constructs an output group from the parser-collected output lines.
-  def _processGroup(self, name, lines, lineNo):
-    return OutputGroup(name, lines, self.fileName, lineNo + 1)
-
-  def findGroup(self, name):
-    for group in self.groups:
-      if group.name == name:
-        return group
-    return None
-
-
-def ParseArguments():
-  parser = argparse.ArgumentParser()
-  parser.add_argument("tested_file",
-                      help="text file the checks should be verified against")
-  parser.add_argument("source_path", nargs="?",
-                      help="path to file/folder with checking annotations")
-  parser.add_argument("--check-prefix", dest="check_prefix", default="CHECK", metavar="PREFIX",
-                      help="prefix of checks in the test files (default: CHECK)")
-  parser.add_argument("--list-groups", dest="list_groups", action="store_true",
-                      help="print a list of all groups found in the tested file")
-  parser.add_argument("--dump-group", dest="dump_group", metavar="GROUP",
-                      help="print the contents of an output group")
-  parser.add_argument("-q", "--quiet", action="store_true",
-                      help="print only errors")
-  return parser.parse_args()
-
-
-def ListGroups(outputFilename):
-  outputFile = OutputFile(open(outputFilename, "r"))
-  for group in outputFile.groups:
-    Logger.log(group.name)
-
-
-def DumpGroup(outputFilename, groupName):
-  outputFile = OutputFile(open(outputFilename, "r"))
-  group = outputFile.findGroup(groupName)
-  if group:
-    lineNo = group.lineNo
-    maxLineNo = lineNo + len(group.body)
-    lenLineNo = len(str(maxLineNo)) + 2
-    for line in group.body:
-      Logger.log((str(lineNo) + ":").ljust(lenLineNo) + line)
-      lineNo += 1
-  else:
-    Logger.fail("Group \"" + groupName + "\" not found in the output")
-
-
-# Returns a list of files to scan for check annotations in the given path. Path
-# to a file is returned as a single-element list, directories are recursively
-# traversed and all '.java' files returned.
-def FindCheckFiles(path):
-  if not path:
-    Logger.fail("No source path provided")
-  elif os.path.isfile(path):
-    return [ path ]
-  elif os.path.isdir(path):
-    foundFiles = []
-    for root, dirs, files in os.walk(path):
-      for file in files:
-        if os.path.splitext(file)[1] == ".java":
-          foundFiles.append(os.path.join(root, file))
-    return foundFiles
-  else:
-    Logger.fail("Source path \"" + path + "\" not found")
-
-
-def RunChecks(checkPrefix, checkPath, outputFilename):
-  outputBaseName = os.path.basename(outputFilename)
-  outputFile = OutputFile(open(outputFilename, "r"), outputBaseName)
-
-  for checkFilename in FindCheckFiles(checkPath):
-    checkBaseName = os.path.basename(checkFilename)
-    checkFile = CheckFile(checkPrefix, open(checkFilename, "r"), checkBaseName)
-    checkFile.match(outputFile)
-
-
-if __name__ == "__main__":
-  args = ParseArguments()
-
-  if args.quiet:
-    Logger.Verbosity = Logger.Level.Error
-
-  if args.list_groups:
-    ListGroups(args.tested_file)
-  elif args.dump_group:
-    DumpGroup(args.tested_file, args.dump_group)
-  else:
-    RunChecks(args.check_prefix, args.source_path, args.tested_file)
diff --git a/tools/checker/README b/tools/checker/README
new file mode 100644
index 0000000..858a773
--- /dev/null
+++ b/tools/checker/README
@@ -0,0 +1,54 @@
+Checker is a testing tool which compiles a given test file and compares the
+state of the control-flow graph before and after each optimization pass
+against a set of assertions specified alongside the tests.
+
+Tests are written in Java, turned into DEX and compiled with the Optimizing
+compiler. "Check lines" are assertions formatted as comments of the Java file.
+They begin with prefix 'CHECK' followed by a pattern that the engine attempts
+to match in the compiler-generated output.
+
+Assertions are tested in groups which correspond to the individual compiler
+passes. Each group of check lines therefore must start with a 'CHECK-START'
+header which specifies the output group it should be tested against. The group
+name must exactly match one of the groups recognized in the output (they can
+be listed with the '--list-passes' command-line flag).
+
+Matching of check lines is carried out in the order of appearance in the
+source file. There are three types of check lines:
+ - CHECK:     Must match an output line which appears in the output group
+              later than lines matched against any preceeding checks. Output
+              lines must therefore match the check lines in the same order.
+              These are referred to as "in-order" checks in the code.
+ - CHECK-DAG: Must match an output line which appears in the output group
+              later than lines matched against any preceeding in-order checks.
+              In other words, the order of output lines does not matter
+              between consecutive DAG checks.
+ - CHECK-NOT: Must not match any output line which appears in the output group
+              later than lines matched against any preceeding checks and
+              earlier than lines matched against any subsequent checks.
+              Surrounding non-negative checks (or boundaries of the group)
+              therefore create a scope within which the assertion is verified.
+
+Check-line patterns are treated as plain text rather than regular expressions
+but are whitespace agnostic.
+
+Actual regex patterns can be inserted enclosed in '{{' and '}}' brackets. If
+curly brackets need to be used inside the body of the regex, they need to be
+enclosed in round brackets. For example, the pattern '{{foo{2}}}' will parse
+the invalid regex 'foo{2', but '{{(fo{2})}}' will match 'foo'.
+
+Regex patterns can be named and referenced later. A new variable is defined
+with '<<name:regex>>' and can be referenced with '<<name>>'. Variables are
+only valid within the scope of the defining group. Within a group they cannot
+be redefined or used undefined.
+
+Example:
+  The following assertions can be placed in a Java source file:
+
+  // CHECK-START: int MyClass.MyMethod() constant_folding (after)
+  // CHECK:         <<ID:i\d+>>  IntConstant {{11|22}}
+  // CHECK:                      Return [<<ID>>]
+
+  The engine will attempt to match the check lines against the output of the
+  group named on the first line. Together they verify that the CFG after
+  constant folding returns an integer constant with value either 11 or 22.
diff --git a/tools/checker/checker.py b/tools/checker/checker.py
new file mode 100755
index 0000000..ed630e3
--- /dev/null
+++ b/tools/checker/checker.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 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 argparse
+import os
+
+from common.logger                    import Logger
+from file_format.c1visualizer.parser  import ParseC1visualizerStream
+from file_format.checker.parser       import ParseCheckerStream
+from match.file                       import MatchFiles
+
+def ParseArguments():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("tested_file",
+                      help="text file the checks should be verified against")
+  parser.add_argument("source_path", nargs="?",
+                      help="path to file/folder with checking annotations")
+  parser.add_argument("--check-prefix", dest="check_prefix", default="CHECK", metavar="PREFIX",
+                      help="prefix of checks in the test files (default: CHECK)")
+  parser.add_argument("--list-passes", dest="list_passes", action="store_true",
+                      help="print a list of all passes found in the tested file")
+  parser.add_argument("--dump-pass", dest="dump_pass", metavar="PASS",
+                      help="print a compiler pass dump")
+  parser.add_argument("-q", "--quiet", action="store_true",
+                      help="print only errors")
+  return parser.parse_args()
+
+
+def ListPasses(outputFilename):
+  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
+  for compiler_pass in c1File.passes:
+    Logger.log(compiler_pass.name)
+
+
+def DumpPass(outputFilename, passName):
+  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
+  compiler_pass = c1File.findPass(passName)
+  if compiler_pass:
+    maxLineNo = compiler_pass.startLineNo + len(compiler_pass.body)
+    lenLineNo = len(str(maxLineNo)) + 2
+    curLineNo = compiler_pass.startLineNo
+    for line in compiler_pass.body:
+      Logger.log((str(curLineNo) + ":").ljust(lenLineNo) + line)
+      curLineNo += 1
+  else:
+    Logger.fail("Pass \"" + passName + "\" not found in the output")
+
+
+def FindCheckerFiles(path):
+  """ Returns a list of files to scan for check annotations in the given path.
+      Path to a file is returned as a single-element list, directories are
+      recursively traversed and all '.java' files returned.
+  """
+  if not path:
+    Logger.fail("No source path provided")
+  elif os.path.isfile(path):
+    return [ path ]
+  elif os.path.isdir(path):
+    foundFiles = []
+    for root, dirs, files in os.walk(path):
+      for file in files:
+        extension = os.path.splitext(file)[1]
+        if extension in [".java", ".smali"]:
+          foundFiles.append(os.path.join(root, file))
+    return foundFiles
+  else:
+    Logger.fail("Source path \"" + path + "\" not found")
+
+
+def RunTests(checkPrefix, checkPath, outputFilename):
+  c1File = ParseC1visualizerStream(os.path.basename(outputFilename), open(outputFilename, "r"))
+  for checkFilename in FindCheckerFiles(checkPath):
+    checkerFile = ParseCheckerStream(os.path.basename(checkFilename),
+                                     checkPrefix,
+                                     open(checkFilename, "r"))
+    MatchFiles(checkerFile, c1File)
+
+
+if __name__ == "__main__":
+  args = ParseArguments()
+
+  if args.quiet:
+    Logger.Verbosity = Logger.Level.Error
+
+  if args.list_passes:
+    ListPasses(args.tested_file)
+  elif args.dump_pass:
+    DumpPass(args.tested_file, args.dump_pass)
+  else:
+    RunTests(args.check_prefix, args.source_path, args.tested_file)
diff --git a/tools/checker/common/__init__.py b/tools/checker/common/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/common/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 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.
diff --git a/tools/checker/common/immutables.py b/tools/checker/common/immutables.py
new file mode 100644
index 0000000..e016867
--- /dev/null
+++ b/tools/checker/common/immutables.py
@@ -0,0 +1,25 @@
+# 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 ImmutableDict(dict):
+  def __setitem__(self, key, value):
+    raise RuntimeError("Cannot modify ImmutableDict")
+
+  def __delitem__(self, key):
+    raise RuntimeError("Cannot modify ImmutableDict")
+
+  def copyWith(self, key, value):
+    newDict = ImmutableDict(self)
+    dict.__setitem__(newDict, key, value)
+    return newDict
diff --git a/tools/checker/common/logger.py b/tools/checker/common/logger.py
new file mode 100644
index 0000000..28bb458
--- /dev/null
+++ b/tools/checker/common/logger.py
@@ -0,0 +1,81 @@
+# Copyright (C) 2014 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.
+
+from __future__ import print_function
+import sys
+
+class Logger(object):
+
+  class Level(object):
+    NoOutput, Error, Info = range(3)
+
+  class Color(object):
+    Default, Blue, Gray, Purple, Red = range(5)
+
+    @staticmethod
+    def terminalCode(color, out=sys.stdout):
+      if not out.isatty():
+        return ''
+      elif color == Logger.Color.Blue:
+        return '\033[94m'
+      elif color == Logger.Color.Gray:
+        return '\033[37m'
+      elif color == Logger.Color.Purple:
+        return '\033[95m'
+      elif color == Logger.Color.Red:
+        return '\033[91m'
+      else:
+        return '\033[0m'
+
+  Verbosity = Level.Info
+
+  @staticmethod
+  def log(text, level=Level.Info, color=Color.Default, newLine=True, out=sys.stdout):
+    if level <= Logger.Verbosity:
+      text = Logger.Color.terminalCode(color, out) + text + \
+             Logger.Color.terminalCode(Logger.Color.Default, out)
+      if newLine:
+        print(text, file=out)
+      else:
+        print(text, end="", file=out)
+      out.flush()
+
+  @staticmethod
+  def fail(msg, file=None, line=-1):
+    location = ""
+    if file:
+      location += file + ":"
+    if line > 0:
+      location += str(line) + ":"
+    if location:
+      location += " "
+
+    Logger.log(location, Logger.Level.Error, color=Logger.Color.Gray, newLine=False, out=sys.stderr)
+    Logger.log("error: ", Logger.Level.Error, color=Logger.Color.Red, newLine=False, out=sys.stderr)
+    Logger.log(msg, Logger.Level.Error, out=sys.stderr)
+    sys.exit(msg)
+
+  @staticmethod
+  def startTest(name):
+    Logger.log("TEST ", color=Logger.Color.Purple, newLine=False)
+    Logger.log(name + "... ", newLine=False)
+
+  @staticmethod
+  def testPassed():
+    Logger.log("PASS", color=Logger.Color.Blue)
+
+  @staticmethod
+  def testFailed(msg, file=None, line=-1):
+    Logger.log("FAIL", color=Logger.Color.Red)
+    Logger.fail(msg, file, line)
diff --git a/tools/checker/common/mixins.py b/tools/checker/common/mixins.py
new file mode 100644
index 0000000..819de24
--- /dev/null
+++ b/tools/checker/common/mixins.py
@@ -0,0 +1,26 @@
+# Copyright (C) 2014 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 EqualityMixin:
+  """ Object equality via equality of dictionaries. """
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.__dict__ == other.__dict__
+
+class PrintableMixin:
+  """ Prints object as name-dictionary pair. """
+
+  def __repr__(self):
+    return "<%s: %s>" % (type(self).__name__, str(self.__dict__))
diff --git a/tools/checker/common/testing.py b/tools/checker/common/testing.py
new file mode 100644
index 0000000..1299c07
--- /dev/null
+++ b/tools/checker/common/testing.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2014 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.
+
+def ToUnicode(string):
+  """ Converts a string into Unicode.
+
+  This is a delegate function for the built-in `unicode`. It checks if the input
+  is not `None`, because `unicode` turns it into an actual "None" string.
+  """
+  assert string is not None
+  return unicode(string)
diff --git a/tools/checker/file_format/__init__.py b/tools/checker/file_format/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/file_format/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 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.
diff --git a/tools/checker/file_format/c1visualizer/__init__.py b/tools/checker/file_format/c1visualizer/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 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.
diff --git a/tools/checker/file_format/c1visualizer/parser.py b/tools/checker/file_format/c1visualizer/parser.py
new file mode 100644
index 0000000..335a195
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/parser.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2014 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.
+
+from common.logger                   import Logger
+from file_format.common              import SplitStream
+from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
+
+import re
+
+class C1ParserState:
+  OutsideBlock, InsideCompilationBlock, StartingCfgBlock, InsideCfgBlock = range(4)
+
+  def __init__(self):
+    self.currentState = C1ParserState.OutsideBlock
+    self.lastMethodName = None
+
+def __parseC1Line(line, lineNo, state, fileName):
+  """ This function is invoked on each line of the output file and returns
+      a pair which instructs the parser how the line should be handled. If the
+      line is to be included in the current group, it is returned in the first
+      value. If the line starts a new output group, the name of the group is
+      returned in the second value.
+  """
+  if state.currentState == C1ParserState.StartingCfgBlock:
+    # Previous line started a new 'cfg' block which means that this one must
+    # contain the name of the pass (this is enforced by C1visualizer).
+    if re.match("name\s+\"[^\"]+\"", line):
+      # Extract the pass name, prepend it with the name of the method and
+      # return as the beginning of a new group.
+      state.currentState = C1ParserState.InsideCfgBlock
+      return (None, state.lastMethodName + " " + line.split("\"")[1])
+    else:
+      Logger.fail("Expected output group name", fileName, lineNo)
+
+  elif state.currentState == C1ParserState.InsideCfgBlock:
+    if line == "end_cfg":
+      state.currentState = C1ParserState.OutsideBlock
+      return (None, None)
+    else:
+      return (line, None)
+
+  elif state.currentState == C1ParserState.InsideCompilationBlock:
+    # Search for the method's name. Format: method "<name>"
+    if re.match("method\s+\"[^\"]*\"", line):
+      methodName = line.split("\"")[1].strip()
+      if not methodName:
+        Logger.fail("Empty method name in output", fileName, lineNo)
+      state.lastMethodName = methodName
+    elif line == "end_compilation":
+      state.currentState = C1ParserState.OutsideBlock
+    return (None, None)
+
+  else:
+    assert state.currentState == C1ParserState.OutsideBlock
+    if line == "begin_cfg":
+      # The line starts a new group but we'll wait until the next line from
+      # which we can extract the name of the pass.
+      if state.lastMethodName is None:
+        Logger.fail("Expected method header", fileName, lineNo)
+      state.currentState = C1ParserState.StartingCfgBlock
+      return (None, None)
+    elif line == "begin_compilation":
+      state.currentState = C1ParserState.InsideCompilationBlock
+      return (None, None)
+    else:
+      Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
+
+def ParseC1visualizerStream(fileName, stream):
+  c1File = C1visualizerFile(fileName)
+  state = C1ParserState()
+  fnProcessLine = lambda line, lineNo: __parseC1Line(line, lineNo, state, fileName)
+  fnLineOutsideChunk = lambda line, lineNo: \
+      Logger.fail("C1visualizer line not inside a group", fileName, lineNo)
+  for passName, passLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+    C1visualizerPass(c1File, passName, passLines, startLineNo + 1)
+  return c1File
diff --git a/tools/checker/file_format/c1visualizer/struct.py b/tools/checker/file_format/c1visualizer/struct.py
new file mode 100644
index 0000000..991564e
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/struct.py
@@ -0,0 +1,60 @@
+# Copyright (C) 2014 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.
+
+from common.logger import Logger
+from common.mixins import PrintableMixin
+
+class C1visualizerFile(PrintableMixin):
+
+  def __init__(self, fileName):
+    self.fileName = fileName
+    self.passes = []
+
+  def addPass(self, new_pass):
+    self.passes.append(new_pass)
+
+  def findPass(self, name):
+    for entry in self.passes:
+      if entry.name == name:
+        return entry
+    return None
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.passes == other.passes
+
+
+class C1visualizerPass(PrintableMixin):
+
+  def __init__(self, parent, name, body, startLineNo):
+    self.parent = parent
+    self.name = name
+    self.body = body
+    self.startLineNo = startLineNo
+
+    if not self.name:
+      Logger.fail("C1visualizer pass does not have a name", self.fileName, self.startLineNo)
+    if not self.body:
+      Logger.fail("C1visualizer pass does not have a body", self.fileName, self.startLineNo)
+
+    self.parent.addPass(self)
+
+  @property
+  def fileName(self):
+    return self.parent.fileName
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.name == other.name \
+       and self.body == other.body
diff --git a/tools/checker/file_format/c1visualizer/test.py b/tools/checker/file_format/c1visualizer/test.py
new file mode 100644
index 0000000..812a4cf
--- /dev/null
+++ b/tools/checker/file_format/c1visualizer/test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 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.
+
+from common.testing                  import ToUnicode
+from file_format.c1visualizer.parser import ParseC1visualizerStream
+from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
+
+import io
+import unittest
+
+class C1visualizerParser_Test(unittest.TestCase):
+
+  def createFile(self, passList):
+    """ Creates an instance of CheckerFile from provided info.
+
+    Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
+    """
+    c1File = C1visualizerFile("<c1_file>")
+    for passEntry in passList:
+      passName = passEntry[0]
+      passBody = passEntry[1]
+      c1Pass = C1visualizerPass(c1File, passName, passBody, 0)
+    return c1File
+
+  def assertParsesTo(self, c1Text, expectedData):
+    expectedFile = self.createFile(expectedData)
+    actualFile = ParseC1visualizerStream("<c1_file>", io.StringIO(ToUnicode(c1Text)))
+    return self.assertEqual(expectedFile, actualFile)
+
+  def test_EmptyFile(self):
+    self.assertParsesTo("", [])
+
+  def test_SingleGroup(self):
+    self.assertParsesTo(
+      """
+        begin_compilation
+          method "MyMethod"
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+      """,
+      [ ( "MyMethod pass1", [ "foo", "bar" ] ) ])
+
+  def test_MultipleGroups(self):
+    self.assertParsesTo(
+      """
+        begin_compilation
+          name "xyz1"
+          method "MyMethod1"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+        begin_cfg
+          name "pass2"
+          abc
+          def
+        end_cfg
+      """,
+      [ ( "MyMethod1 pass1", [ "foo", "bar" ] ),
+        ( "MyMethod1 pass2", [ "abc", "def" ] ) ])
+    self.assertParsesTo(
+      """
+        begin_compilation
+          name "xyz1"
+          method "MyMethod1"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "pass1"
+          foo
+          bar
+        end_cfg
+        begin_compilation
+          name "xyz2"
+          method "MyMethod2"
+          date 5678
+        end_compilation
+        begin_cfg
+          name "pass2"
+          abc
+          def
+        end_cfg
+      """,
+      [ ( "MyMethod1 pass1", [ "foo", "bar" ] ),
+        ( "MyMethod2 pass2", [ "abc", "def" ] ) ])
diff --git a/tools/checker/file_format/checker/__init__.py b/tools/checker/file_format/checker/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/file_format/checker/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 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.
diff --git a/tools/checker/file_format/checker/parser.py b/tools/checker/file_format/checker/parser.py
new file mode 100644
index 0000000..33735cb
--- /dev/null
+++ b/tools/checker/file_format/checker/parser.py
@@ -0,0 +1,153 @@
+# Copyright (C) 2014 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.
+
+from common.logger              import Logger
+from file_format.common         import SplitStream
+from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
+
+import re
+
+def __isCheckerLine(line):
+  return line.startswith("///") or line.startswith("##")
+
+def __extractLine(prefix, line):
+  """ Attempts to parse a check line. The regex searches for a comment symbol
+      followed by the CHECK keyword, given attribute and a colon at the very
+      beginning of the line. Whitespaces are ignored.
+  """
+  rIgnoreWhitespace = r"\s*"
+  rCommentSymbols = [r"///", r"##"]
+  regexPrefix = rIgnoreWhitespace + \
+                r"(" + r"|".join(rCommentSymbols) + r")" + \
+                rIgnoreWhitespace + \
+                prefix + r":"
+
+  # The 'match' function succeeds only if the pattern is matched at the
+  # beginning of the line.
+  match = re.match(regexPrefix, line)
+  if match is not None:
+    return line[match.end():].strip()
+  else:
+    return None
+
+def __processLine(line, lineNo, prefix, fileName):
+  """ This function is invoked on each line of the check file and returns a pair
+      which instructs the parser how the line should be handled. If the line is
+      to be included in the current check group, it is returned in the first
+      value. If the line starts a new check group, the name of the group is
+      returned in the second value.
+  """
+  if not __isCheckerLine(line):
+    return None, None
+
+  # Lines beginning with 'CHECK-START' start a new test case.
+  startLine = __extractLine(prefix + "-START", line)
+  if startLine is not None:
+    return None, startLine
+
+  # Lines starting only with 'CHECK' are matched in order.
+  plainLine = __extractLine(prefix, line)
+  if plainLine is not None:
+    return (plainLine, TestAssertion.Variant.InOrder, lineNo), None
+
+  # 'CHECK-NEXT' lines are in-order but must match the very next line.
+  nextLine = __extractLine(prefix + "-NEXT", line)
+  if nextLine is not None:
+    return (nextLine, TestAssertion.Variant.NextLine, lineNo), None
+
+  # 'CHECK-DAG' lines are no-order assertions.
+  dagLine = __extractLine(prefix + "-DAG", line)
+  if dagLine is not None:
+    return (dagLine, TestAssertion.Variant.DAG, lineNo), None
+
+  # 'CHECK-NOT' lines are no-order negative assertions.
+  notLine = __extractLine(prefix + "-NOT", line)
+  if notLine is not None:
+    return (notLine, TestAssertion.Variant.Not, lineNo), None
+
+  Logger.fail("Checker assertion could not be parsed", fileName, lineNo)
+
+def __isMatchAtStart(match):
+  """ Tests if the given Match occurred at the beginning of the line. """
+  return (match is not None) and (match.start() == 0)
+
+def __firstMatch(matches, string):
+  """ Takes in a list of Match objects and returns the minimal start point among
+      them. If there aren't any successful matches it returns the length of
+      the searched string.
+  """
+  starts = map(lambda m: len(string) if m is None else m.start(), matches)
+  return min(starts)
+
+def ParseCheckerAssertion(parent, line, variant, lineNo):
+  """ This method parses the content of a check line stripped of the initial
+      comment symbol and the CHECK keyword.
+  """
+  assertion = TestAssertion(parent, variant, line, lineNo)
+  # Loop as long as there is something to parse.
+  while line:
+    # Search for the nearest occurrence of the special markers.
+    matchWhitespace = re.search(r"\s+", line)
+    matchPattern = re.search(RegexExpression.Regex.regexPattern, line)
+    matchVariableReference = re.search(RegexExpression.Regex.regexVariableReference, line)
+    matchVariableDefinition = re.search(RegexExpression.Regex.regexVariableDefinition, line)
+
+    # If one of the above was identified at the current position, extract them
+    # from the line, parse them and add to the list of line parts.
+    if __isMatchAtStart(matchWhitespace):
+      # A whitespace in the check line creates a new separator of line parts.
+      # This allows for ignored output between the previous and next parts.
+      line = line[matchWhitespace.end():]
+      assertion.addExpression(RegexExpression.createSeparator())
+    elif __isMatchAtStart(matchPattern):
+      pattern = line[0:matchPattern.end()]
+      pattern = pattern[2:-2]
+      line = line[matchPattern.end():]
+      assertion.addExpression(RegexExpression.createPattern(pattern))
+    elif __isMatchAtStart(matchVariableReference):
+      var = line[0:matchVariableReference.end()]
+      line = line[matchVariableReference.end():]
+      name = var[2:-2]
+      assertion.addExpression(RegexExpression.createVariableReference(name))
+    elif __isMatchAtStart(matchVariableDefinition):
+      var = line[0:matchVariableDefinition.end()]
+      line = line[matchVariableDefinition.end():]
+      colonPos = var.find(":")
+      name = var[2:colonPos]
+      body = var[colonPos+1:-2]
+      assertion.addExpression(RegexExpression.createVariableDefinition(name, body))
+    else:
+      # If we're not currently looking at a special marker, this is a plain
+      # text match all the way until the first special marker (or the end
+      # of the line).
+      firstMatch = __firstMatch([ matchWhitespace,
+                                  matchPattern,
+                                  matchVariableReference,
+                                  matchVariableDefinition ],
+                                line)
+      text = line[0:firstMatch]
+      line = line[firstMatch:]
+      assertion.addExpression(RegexExpression.createText(text))
+  return assertion
+
+def ParseCheckerStream(fileName, prefix, stream):
+  checkerFile = CheckerFile(fileName)
+  fnProcessLine = lambda line, lineNo: __processLine(line, lineNo, prefix, fileName)
+  fnLineOutsideChunk = lambda line, lineNo: \
+      Logger.fail("Checker line not inside a group", fileName, lineNo)
+  for caseName, caseLines, startLineNo in SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+    testCase = TestCase(checkerFile, caseName, startLineNo)
+    for caseLine in caseLines:
+      ParseCheckerAssertion(testCase, caseLine[0], caseLine[1], caseLine[2])
+  return checkerFile
diff --git a/tools/checker/file_format/checker/struct.py b/tools/checker/file_format/checker/struct.py
new file mode 100644
index 0000000..6a54142
--- /dev/null
+++ b/tools/checker/file_format/checker/struct.py
@@ -0,0 +1,163 @@
+# Copyright (C) 2014 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.
+
+from common.logger import Logger
+from common.mixins import EqualityMixin, PrintableMixin
+
+import re
+
+class CheckerFile(PrintableMixin):
+
+  def __init__(self, fileName):
+    self.fileName = fileName
+    self.testCases = []
+
+  def addTestCase(self, new_test_case):
+    self.testCases.append(new_test_case)
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.testCases == other.testCases
+
+
+class TestCase(PrintableMixin):
+
+  def __init__(self, parent, name, startLineNo):
+    assert isinstance(parent, CheckerFile)
+
+    self.parent = parent
+    self.name = name
+    self.assertions = []
+    self.startLineNo = startLineNo
+
+    if not self.name:
+      Logger.fail("Test case does not have a name", self.fileName, self.startLineNo)
+
+    self.parent.addTestCase(self)
+
+  @property
+  def fileName(self):
+    return self.parent.fileName
+
+  def addAssertion(self, new_assertion):
+    if new_assertion.variant == TestAssertion.Variant.NextLine:
+      if not self.assertions or \
+         (self.assertions[-1].variant != TestAssertion.Variant.InOrder and \
+          self.assertions[-1].variant != TestAssertion.Variant.NextLine):
+        Logger.fail("A next-line assertion can only be placed after an "
+                    "in-order assertion or another next-line assertion.",
+                    new_assertion.fileName, new_assertion.lineNo)
+    self.assertions.append(new_assertion)
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.name == other.name \
+       and self.assertions == other.assertions
+
+
+class TestAssertion(PrintableMixin):
+
+  class Variant(object):
+    """Supported types of assertions."""
+    InOrder, NextLine, DAG, Not = range(4)
+
+  def __init__(self, parent, variant, originalText, lineNo):
+    assert isinstance(parent, TestCase)
+
+    self.parent = parent
+    self.variant = variant
+    self.expressions = []
+    self.lineNo = lineNo
+    self.originalText = originalText
+
+    self.parent.addAssertion(self)
+
+  @property
+  def fileName(self):
+    return self.parent.fileName
+
+  def addExpression(self, new_expression):
+    assert isinstance(new_expression, RegexExpression)
+    if self.variant == TestAssertion.Variant.Not:
+      if new_expression.variant == RegexExpression.Variant.VarDef:
+        Logger.fail("CHECK-NOT lines cannot define variables", self.fileName, self.lineNo)
+    self.expressions.append(new_expression)
+
+  def toRegex(self):
+    """ Returns a regex pattern for this entire assertion. Only used in tests. """
+    regex = ""
+    for expression in self.expressions:
+      if expression.variant == RegexExpression.Variant.Separator:
+        regex = regex + ", "
+      else:
+        regex = regex + "(" + expression.pattern + ")"
+    return regex
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.variant == other.variant \
+       and self.expressions == other.expressions
+
+
+class RegexExpression(EqualityMixin, PrintableMixin):
+
+  class Variant(object):
+    """Supported language constructs."""
+    Text, Pattern, VarRef, VarDef, Separator = range(5)
+
+  class Regex(object):
+    rName = r"([a-zA-Z][a-zA-Z0-9]*)"
+    rRegex = r"(.+?)"
+    rPatternStartSym = r"(\{\{)"
+    rPatternEndSym = r"(\}\})"
+    rVariableStartSym = r"(<<)"
+    rVariableEndSym = r"(>>)"
+    rVariableSeparator = r"(:)"
+
+    regexPattern = rPatternStartSym + rRegex + rPatternEndSym
+    regexVariableReference = rVariableStartSym + rName + rVariableEndSym
+    regexVariableDefinition = rVariableStartSym + rName + rVariableSeparator + rRegex + rVariableEndSym
+
+  def __init__(self, variant, name, pattern):
+    self.variant = variant
+    self.name = name
+    self.pattern = pattern
+
+  def __eq__(self, other):
+    return isinstance(other, self.__class__) \
+       and self.variant == other.variant \
+       and self.name == other.name \
+       and self.pattern == other.pattern
+
+  @staticmethod
+  def createSeparator():
+    return RegexExpression(RegexExpression.Variant.Separator, None, None)
+
+  @staticmethod
+  def createText(text):
+    return RegexExpression(RegexExpression.Variant.Text, None, re.escape(text))
+
+  @staticmethod
+  def createPattern(pattern):
+    return RegexExpression(RegexExpression.Variant.Pattern, None, pattern)
+
+  @staticmethod
+  def createVariableReference(name):
+    assert re.match(RegexExpression.Regex.rName, name)
+    return RegexExpression(RegexExpression.Variant.VarRef, name, None)
+
+  @staticmethod
+  def createVariableDefinition(name, pattern):
+    assert re.match(RegexExpression.Regex.rName, name)
+    return RegexExpression(RegexExpression.Variant.VarDef, name, pattern)
diff --git a/tools/checker/file_format/checker/test.py b/tools/checker/file_format/checker/test.py
new file mode 100644
index 0000000..ff24cc1
--- /dev/null
+++ b/tools/checker/file_format/checker/test.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 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.
+
+from common.testing             import ToUnicode
+from file_format.checker.parser import ParseCheckerStream
+from file_format.checker.struct import CheckerFile, TestCase, TestAssertion, RegexExpression
+
+import io
+import unittest
+
+CheckerException = SystemExit
+
+class CheckerParser_PrefixTest(unittest.TestCase):
+
+  def tryParse(self, string):
+    checkerText = u"/// CHECK-START: pass\n" + ToUnicode(string)
+    return ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
+
+  def assertParses(self, string):
+    checkFile = self.tryParse(string)
+    self.assertEqual(len(checkFile.testCases), 1)
+    self.assertNotEqual(len(checkFile.testCases[0].assertions), 0)
+
+  def assertIgnored(self, string):
+    checkFile = self.tryParse(string)
+    self.assertEqual(len(checkFile.testCases), 1)
+    self.assertEqual(len(checkFile.testCases[0].assertions), 0)
+
+  def assertInvalid(self, string):
+    with self.assertRaises(CheckerException):
+      self.tryParse(string)
+
+  def test_ValidFormat(self):
+    self.assertParses("///CHECK:foo")
+    self.assertParses("##CHECK:bar")
+
+  def test_InvalidFormat(self):
+    self.assertIgnored("CHECK")
+    self.assertIgnored(":CHECK")
+    self.assertIgnored("CHECK:")
+    self.assertIgnored("//CHECK")
+    self.assertIgnored("#CHECK")
+    self.assertInvalid("///CHECK")
+    self.assertInvalid("##CHECK")
+
+  def test_InvalidPrefix(self):
+    self.assertInvalid("///ACHECK:foo")
+    self.assertInvalid("##ACHECK:foo")
+
+  def test_NotFirstOnTheLine(self):
+    self.assertIgnored("A/// CHECK: foo")
+    self.assertIgnored("A # CHECK: foo")
+    self.assertInvalid("/// /// CHECK: foo")
+    self.assertInvalid("## ## CHECK: foo")
+
+  def test_WhitespaceAgnostic(self):
+    self.assertParses("  ///CHECK: foo")
+    self.assertParses("///  CHECK: foo")
+    self.assertParses("    ///CHECK: foo")
+    self.assertParses("///    CHECK: foo")
+
+class CheckerParser_RegexExpressionTest(unittest.TestCase):
+
+  def parseAssertion(self, string, variant=""):
+    checkerText = u"/// CHECK-START: pass\n/// CHECK" + ToUnicode(variant) + u": " + ToUnicode(string)
+    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(checkerText))
+    self.assertEqual(len(checkerFile.testCases), 1)
+    testCase = checkerFile.testCases[0]
+    self.assertEqual(len(testCase.assertions), 1)
+    return testCase.assertions[0]
+
+  def parseExpression(self, string):
+    line = self.parseAssertion(string)
+    self.assertEqual(1, len(line.expressions))
+    return line.expressions[0]
+
+  def assertEqualsRegex(self, string, expected):
+    self.assertEqual(expected, self.parseAssertion(string).toRegex())
+
+  def assertEqualsText(self, string, text):
+    self.assertEqual(self.parseExpression(string), RegexExpression.createText(text))
+
+  def assertEqualsPattern(self, string, pattern):
+    self.assertEqual(self.parseExpression(string), RegexExpression.createPattern(pattern))
+
+  def assertEqualsVarRef(self, string, name):
+    self.assertEqual(self.parseExpression(string), RegexExpression.createVariableReference(name))
+
+  def assertEqualsVarDef(self, string, name, pattern):
+    self.assertEqual(self.parseExpression(string),
+                     RegexExpression.createVariableDefinition(name, pattern))
+
+  def assertVariantNotEqual(self, string, variant):
+    self.assertNotEqual(variant, self.parseExpression(string).variant)
+
+  # Test that individual parts of the line are recognized
+
+  def test_TextOnly(self):
+    self.assertEqualsText("foo", "foo")
+    self.assertEqualsText("  foo  ", "foo")
+    self.assertEqualsRegex("f$o^o", "(f\$o\^o)")
+
+  def test_PatternOnly(self):
+    self.assertEqualsPattern("{{a?b.c}}", "a?b.c")
+
+  def test_VarRefOnly(self):
+    self.assertEqualsVarRef("<<ABC>>", "ABC")
+
+  def test_VarDefOnly(self):
+    self.assertEqualsVarDef("<<ABC:a?b.c>>", "ABC", "a?b.c")
+
+  def test_TextWithWhitespace(self):
+    self.assertEqualsRegex("foo bar", "(foo), (bar)")
+    self.assertEqualsRegex("foo   bar", "(foo), (bar)")
+
+  def test_TextWithRegex(self):
+    self.assertEqualsRegex("foo{{abc}}bar", "(foo)(abc)(bar)")
+
+  def test_TextWithVar(self):
+    self.assertEqualsRegex("foo<<ABC:abc>>bar", "(foo)(abc)(bar)")
+
+  def test_PlainWithRegexAndWhitespaces(self):
+    self.assertEqualsRegex("foo {{abc}}bar", "(foo), (abc)(bar)")
+    self.assertEqualsRegex("foo{{abc}} bar", "(foo)(abc), (bar)")
+    self.assertEqualsRegex("foo {{abc}} bar", "(foo), (abc), (bar)")
+
+  def test_PlainWithVarAndWhitespaces(self):
+    self.assertEqualsRegex("foo <<ABC:abc>>bar", "(foo), (abc)(bar)")
+    self.assertEqualsRegex("foo<<ABC:abc>> bar", "(foo)(abc), (bar)")
+    self.assertEqualsRegex("foo <<ABC:abc>> bar", "(foo), (abc), (bar)")
+
+  def test_AllKinds(self):
+    self.assertEqualsRegex("foo <<ABC:abc>>{{def}}bar", "(foo), (abc)(def)(bar)")
+    self.assertEqualsRegex("foo<<ABC:abc>> {{def}}bar", "(foo)(abc), (def)(bar)")
+    self.assertEqualsRegex("foo <<ABC:abc>> {{def}} bar", "(foo), (abc), (def), (bar)")
+
+  # # Test that variables and patterns are parsed correctly
+
+  def test_ValidPattern(self):
+    self.assertEqualsPattern("{{abc}}", "abc")
+    self.assertEqualsPattern("{{a[b]c}}", "a[b]c")
+    self.assertEqualsPattern("{{(a{bc})}}", "(a{bc})")
+
+  def test_ValidRef(self):
+    self.assertEqualsVarRef("<<ABC>>", "ABC")
+    self.assertEqualsVarRef("<<A1BC2>>", "A1BC2")
+
+  def test_ValidDef(self):
+    self.assertEqualsVarDef("<<ABC:abc>>", "ABC", "abc")
+    self.assertEqualsVarDef("<<ABC:ab:c>>", "ABC", "ab:c")
+    self.assertEqualsVarDef("<<ABC:a[b]c>>", "ABC", "a[b]c")
+    self.assertEqualsVarDef("<<ABC:(a[bc])>>", "ABC", "(a[bc])")
+
+  def test_Empty(self):
+    self.assertVariantNotEqual("{{}}", RegexExpression.Variant.Pattern)
+    self.assertVariantNotEqual("<<>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<:>>", RegexExpression.Variant.VarDef)
+
+  def test_InvalidVarName(self):
+    self.assertVariantNotEqual("<<0ABC>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<AB=C>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<ABC=>>", RegexExpression.Variant.VarRef)
+    self.assertVariantNotEqual("<<0ABC:abc>>", RegexExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<AB=C:abc>>", RegexExpression.Variant.VarDef)
+    self.assertVariantNotEqual("<<ABC=:abc>>", RegexExpression.Variant.VarDef)
+
+  def test_BodyMatchNotGreedy(self):
+    self.assertEqualsRegex("{{abc}}{{def}}", "(abc)(def)")
+    self.assertEqualsRegex("<<ABC:abc>><<DEF:def>>", "(abc)(def)")
+
+  def test_NoVarDefsInNotChecks(self):
+    with self.assertRaises(CheckerException):
+      self.parseAssertion("<<ABC:abc>>", "-NOT")
+
+
+class CheckerParser_FileLayoutTest(unittest.TestCase):
+
+  # Creates an instance of CheckerFile from provided info.
+  # Data format: [ ( <case-name>, [ ( <text>, <assert-variant> ), ... ] ), ... ]
+  def createFile(self, caseList):
+    testFile = CheckerFile("<test_file>")
+    for caseEntry in caseList:
+      caseName = caseEntry[0]
+      testCase = TestCase(testFile, caseName, 0)
+      assertionList = caseEntry[1]
+      for assertionEntry in assertionList:
+        content = assertionEntry[0]
+        variant = assertionEntry[1]
+        assertion = TestAssertion(testCase, variant, content, 0)
+        assertion.addExpression(RegexExpression.createText(content))
+    return testFile
+
+  def assertParsesTo(self, checkerText, expectedData):
+    expectedFile = self.createFile(expectedData)
+    actualFile = self.parse(checkerText)
+    return self.assertEqual(expectedFile, actualFile)
+
+  def parse(self, checkerText):
+    return ParseCheckerStream("<test_file>", "CHECK", io.StringIO(ToUnicode(checkerText)))
+
+  def test_EmptyFile(self):
+    self.assertParsesTo("", [])
+
+  def test_SingleGroup(self):
+    self.assertParsesTo(
+      """
+        /// CHECK-START: Example Group
+        /// CHECK:  foo
+        /// CHECK:    bar
+      """,
+      [ ( "Example Group", [ ("foo", TestAssertion.Variant.InOrder),
+                             ("bar", TestAssertion.Variant.InOrder) ] ) ])
+
+  def test_MultipleGroups(self):
+    self.assertParsesTo(
+      """
+        /// CHECK-START: Example Group1
+        /// CHECK: foo
+        /// CHECK: bar
+        /// CHECK-START: Example Group2
+        /// CHECK: abc
+        /// CHECK: def
+      """,
+      [ ( "Example Group1", [ ("foo", TestAssertion.Variant.InOrder),
+                              ("bar", TestAssertion.Variant.InOrder) ] ),
+        ( "Example Group2", [ ("abc", TestAssertion.Variant.InOrder),
+                              ("def", TestAssertion.Variant.InOrder) ] ) ])
+
+  def test_AssertionVariants(self):
+    self.assertParsesTo(
+      """
+        /// CHECK-START: Example Group
+        /// CHECK:      foo1
+        /// CHECK:      foo2
+        /// CHECK-NEXT: foo3
+        /// CHECK-NEXT: foo4
+        /// CHECK-NOT:  bar
+        /// CHECK-DAG:  abc
+        /// CHECK-DAG:  def
+      """,
+      [ ( "Example Group", [ ("foo1", TestAssertion.Variant.InOrder),
+                             ("foo2", TestAssertion.Variant.InOrder),
+                             ("foo3", TestAssertion.Variant.NextLine),
+                             ("foo4", TestAssertion.Variant.NextLine),
+                             ("bar", TestAssertion.Variant.Not),
+                             ("abc", TestAssertion.Variant.DAG),
+                             ("def", TestAssertion.Variant.DAG) ] ) ])
+
+  def test_MisplacedNext(self):
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          /// CHECK-START: Example Group
+          /// CHECK-DAG:  foo
+          /// CHECK-NEXT: bar
+        """)
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          /// CHECK-START: Example Group
+          /// CHECK-NOT:  foo
+          /// CHECK-NEXT: bar
+        """)
+    with self.assertRaises(CheckerException):
+      self.parse(
+        """
+          /// CHECK-START: Example Group
+          /// CHECK-NEXT: bar
+        """)
diff --git a/tools/checker/file_format/common.py b/tools/checker/file_format/common.py
new file mode 100644
index 0000000..f91fdeb
--- /dev/null
+++ b/tools/checker/file_format/common.py
@@ -0,0 +1,48 @@
+# Copyright (C) 2014 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.
+
+def SplitStream(stream, fnProcessLine, fnLineOutsideChunk):
+  """ Reads the given input stream and splits it into chunks based on
+      information extracted from individual lines.
+
+  Arguments:
+   - fnProcessLine: Called on each line with the text and line number. Must
+     return a pair, name of the chunk started on this line and data extracted
+     from this line (or None in both cases).
+   - fnLineOutsideChunk: Called on attempt to attach data prior to creating
+     a chunk.
+  """
+  lineNo = 0
+  allChunks = []
+  currentChunk = None
+
+  for line in stream:
+    lineNo += 1
+    line = line.strip()
+    if not line:
+      continue
+
+    # Let the child class process the line and return information about it.
+    # The _processLine method can modify the content of the line (or delete it
+    # entirely) and specify whether it starts a new group.
+    processedLine, newChunkName = fnProcessLine(line, lineNo)
+    if newChunkName is not None:
+      currentChunk = (newChunkName, [], lineNo)
+      allChunks.append(currentChunk)
+    if processedLine is not None:
+      if currentChunk is not None:
+        currentChunk[1].append(processedLine)
+      else:
+        fnLineOutsideChunk(line, lineNo)
+  return allChunks
diff --git a/tools/checker/match/__init__.py b/tools/checker/match/__init__.py
new file mode 100644
index 0000000..d0a140b
--- /dev/null
+++ b/tools/checker/match/__init__.py
@@ -0,0 +1,13 @@
+# Copyright (C) 2014 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.
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
new file mode 100644
index 0000000..b22211a
--- /dev/null
+++ b/tools/checker/match/file.py
@@ -0,0 +1,174 @@
+# Copyright (C) 2014 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.
+
+from collections                      import namedtuple
+from common.immutables                import ImmutableDict
+from common.logger                    import Logger
+from file_format.c1visualizer.struct  import C1visualizerFile, C1visualizerPass
+from file_format.checker.struct       import CheckerFile, TestCase, TestAssertion
+from match.line                       import MatchLines
+
+MatchScope = namedtuple("MatchScope", ["start", "end"])
+MatchInfo = namedtuple("MatchInfo", ["scope", "variables"])
+
+class MatchFailedException(Exception):
+  def __init__(self, assertion, lineNo):
+    self.assertion = assertion
+    self.lineNo = lineNo
+
+def splitIntoGroups(assertions):
+  """ Breaks up a list of assertions, grouping instructions which should be
+      tested in the same scope (consecutive DAG and NOT instructions).
+   """
+  splitAssertions = []
+  lastVariant = None
+  for assertion in assertions:
+    if (assertion.variant == lastVariant and
+        assertion.variant in [TestAssertion.Variant.DAG, TestAssertion.Variant.Not]):
+      splitAssertions[-1].append(assertion)
+    else:
+      splitAssertions.append([assertion])
+      lastVariant = assertion.variant
+  return splitAssertions
+
+def findMatchingLine(assertion, c1Pass, scope, variables, excludeLines=[]):
+  """ Finds the first line in `c1Pass` which matches `assertion`.
+
+  Scan only lines numbered between `scope.start` and `scope.end` and not on the
+  `excludeLines` list.
+
+  Returns the index of the `c1Pass` line matching the assertion and variables
+  values after the match.
+
+  Raises MatchFailedException if no such `c1Pass` line can be found.
+  """
+  for i in range(scope.start, scope.end):
+    if i in excludeLines: continue
+    newVariables = MatchLines(assertion, c1Pass.body[i], variables)
+    if newVariables is not None:
+      return MatchInfo(MatchScope(i, i), newVariables)
+  raise MatchFailedException(assertion, scope.start)
+
+def matchDagGroup(assertions, c1Pass, scope, variables):
+  """ Attempts to find matching `c1Pass` lines for a group of DAG assertions.
+
+  Assertions are matched in the list order and variable values propagated. Only
+  lines in `scope` are scanned and each line can only match one assertion.
+
+  Returns the range of `c1Pass` lines covered by this group (min/max of matching
+  line numbers) and the variable values after the match of the last assertion.
+
+  Raises MatchFailedException when an assertion cannot be satisfied.
+  """
+  matchedLines = []
+  for assertion in assertions:
+    assert assertion.variant == TestAssertion.Variant.DAG
+    match = findMatchingLine(assertion, c1Pass, scope, variables, matchedLines)
+    variables = match.variables
+    assert match.scope.start == match.scope.end
+    assert match.scope.start not in matchedLines
+    matchedLines.append(match.scope.start)
+  return MatchInfo(MatchScope(min(matchedLines), max(matchedLines)), variables)
+
+def testNotGroup(assertions, c1Pass, scope, variables):
+  """ Verifies that none of the given NOT assertions matches a line inside
+      the given `scope` of `c1Pass` lines.
+
+  Raises MatchFailedException if an assertion matches a line in the scope.
+  """
+  for i in range(scope.start, scope.end):
+    line = c1Pass.body[i]
+    for assertion in assertions:
+      assert assertion.variant == TestAssertion.Variant.Not
+      if MatchLines(assertion, line, variables) is not None:
+        raise MatchFailedException(assertion, i)
+
+def MatchTestCase(testCase, c1Pass):
+  """ Runs a test case against a C1visualizer graph dump.
+
+  Raises MatchFailedException when an assertion cannot be satisfied.
+  """
+  assert testCase.name == c1Pass.name
+
+  matchFrom = 0
+  variables = ImmutableDict()
+  c1Length = len(c1Pass.body)
+
+  # NOT assertions are verified retrospectively, once the scope is known.
+  pendingNotAssertions = None
+
+  # Prepare assertions by grouping those that are verified in the same scope.
+  # We also add None as an EOF assertion that will set scope for NOTs.
+  assertionGroups = splitIntoGroups(testCase.assertions)
+  assertionGroups.append(None)
+
+  for assertionGroup in assertionGroups:
+    if assertionGroup is None:
+      # EOF marker always matches the last+1 line of c1Pass.
+      match = MatchInfo(MatchScope(c1Length, c1Length), None)
+    elif assertionGroup[0].variant == TestAssertion.Variant.Not:
+      # NOT assertions will be tested together with the next group.
+      assert not pendingNotAssertions
+      pendingNotAssertions = assertionGroup
+      continue
+    elif assertionGroup[0].variant == TestAssertion.Variant.InOrder:
+      # Single in-order assertion. Find the first line that matches.
+      assert len(assertionGroup) == 1
+      scope = MatchScope(matchFrom, c1Length)
+      match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
+    elif assertionGroup[0].variant == TestAssertion.Variant.NextLine:
+      # Single next-line assertion. Test if the current line matches.
+      assert len(assertionGroup) == 1
+      scope = MatchScope(matchFrom, matchFrom + 1)
+      match = findMatchingLine(assertionGroup[0], c1Pass, scope, variables)
+    else:
+      # A group of DAG assertions. Match them all starting from the same point.
+      assert assertionGroup[0].variant == TestAssertion.Variant.DAG
+      scope = MatchScope(matchFrom, c1Length)
+      match = matchDagGroup(assertionGroup, c1Pass, scope, variables)
+
+    if pendingNotAssertions:
+      # Previous group were NOT assertions. Make sure they don't match any lines
+      # in the [matchFrom, match.start) scope.
+      scope = MatchScope(matchFrom, match.scope.start)
+      testNotGroup(pendingNotAssertions, c1Pass, scope, variables)
+      pendingNotAssertions = None
+
+    # Update state.
+    assert matchFrom <= match.scope.end
+    matchFrom = match.scope.end + 1
+    variables = match.variables
+
+def MatchFiles(checkerFile, c1File):
+  for testCase in checkerFile.testCases:
+    # TODO: Currently does not handle multiple occurrences of the same group
+    # name, e.g. when a pass is run multiple times. It will always try to
+    # match a check group against the first output group of the same name.
+    c1Pass = c1File.findPass(testCase.name)
+    if c1Pass is None:
+      Logger.fail("Test case \"{}\" not found in the CFG file".format(testCase.name),
+                  testCase.fileName, testCase.startLineNo)
+
+    Logger.startTest(testCase.name)
+    try:
+      MatchTestCase(testCase, c1Pass)
+      Logger.testPassed()
+    except MatchFailedException as e:
+      lineNo = c1Pass.startLineNo + e.lineNo
+      if e.assertion.variant == TestAssertion.Variant.Not:
+        Logger.testFailed("NOT assertion matched line {}".format(lineNo),
+                          e.assertion.fileName, e.assertion.lineNo)
+      else:
+        Logger.testFailed("Assertion could not be matched starting from line {}".format(lineNo),
+                          e.assertion.fileName, e.assertion.lineNo)
diff --git a/tools/checker/match/line.py b/tools/checker/match/line.py
new file mode 100644
index 0000000..ce11e2a
--- /dev/null
+++ b/tools/checker/match/line.py
@@ -0,0 +1,96 @@
+# Copyright (C) 2014 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.
+
+from common.logger              import Logger
+from file_format.checker.struct import RegexExpression
+
+import re
+
+def headAndTail(list):
+  return list[0], list[1:]
+
+def splitAtSeparators(expressions):
+  """ Splits a list of RegexExpressions at separators. """
+  splitExpressions = []
+  wordStart = 0
+  for index, expression in enumerate(expressions):
+    if expression.variant == RegexExpression.Variant.Separator:
+      splitExpressions.append(expressions[wordStart:index])
+      wordStart = index + 1
+  splitExpressions.append(expressions[wordStart:])
+  return splitExpressions
+
+def matchWords(checkerWord, stringWord, variables, pos):
+  """ Attempts to match a list of RegexExpressions against a string.
+      Returns updated variable dictionary if successful and None otherwise.
+  """
+  for expression in checkerWord:
+    # If `expression` is a variable reference, replace it with the value.
+    if expression.variant == RegexExpression.Variant.VarRef:
+      if expression.name in variables:
+        pattern = re.escape(variables[expression.name])
+      else:
+        Logger.testFailed("Missing definition of variable \"{}\"".format(expression.name),
+                          pos.fileName, pos.lineNo)
+    else:
+      pattern = expression.pattern
+
+    # Match the expression's regex pattern against the remainder of the word.
+    # Note: re.match will succeed only if matched from the beginning.
+    match = re.match(pattern, stringWord)
+    if not match:
+      return None
+
+    # If `expression` was a variable definition, set the variable's value.
+    if expression.variant == RegexExpression.Variant.VarDef:
+      if expression.name not in variables:
+        variables = variables.copyWith(expression.name, stringWord[:match.end()])
+      else:
+        Logger.testFailed("Multiple definitions of variable \"{}\"".format(expression.name),
+                          pos.fileName, pos.lineNo)
+
+    # Move cursor by deleting the matched characters.
+    stringWord = stringWord[match.end():]
+
+  # Make sure the entire word matched, i.e. `stringWord` is empty.
+  if stringWord:
+    return None
+
+  return variables
+
+def MatchLines(checkerLine, stringLine, variables):
+  """ Attempts to match a CHECK line against a string. Returns variable state
+      after the match if successful and None otherwise.
+  """
+  checkerWords = splitAtSeparators(checkerLine.expressions)
+  stringWords = stringLine.split()
+
+  while checkerWords:
+    # Get the next run of RegexExpressions which must match one string word.
+    checkerWord, checkerWords = headAndTail(checkerWords)
+
+    # Keep reading words until a match is found.
+    wordMatched = False
+    while stringWords:
+      stringWord, stringWords = headAndTail(stringWords)
+      newVariables = matchWords(checkerWord, stringWord, variables, checkerLine)
+      if newVariables is not None:
+        wordMatched = True
+        variables = newVariables
+        break
+    if not wordMatched:
+      return None
+
+  # All RegexExpressions matched. Return new variable state.
+  return variables
diff --git a/tools/checker/match/test.py b/tools/checker/match/test.py
new file mode 100644
index 0000000..ca748c7
--- /dev/null
+++ b/tools/checker/match/test.py
@@ -0,0 +1,388 @@
+# Copyright (C) 2014 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.
+
+from common.immutables               import ImmutableDict
+from common.testing                  import ToUnicode
+from file_format.c1visualizer.parser import ParseC1visualizerStream
+from file_format.c1visualizer.struct import C1visualizerFile, C1visualizerPass
+from file_format.checker.parser      import ParseCheckerStream, ParseCheckerAssertion
+from file_format.checker.struct      import CheckerFile, TestCase, TestAssertion, RegexExpression
+from match.file                      import MatchTestCase, MatchFailedException
+from match.line                      import MatchLines
+
+import io
+import unittest
+
+CheckerException = SystemExit
+
+class MatchLines_Test(unittest.TestCase):
+
+  def createTestAssertion(self, checkerString):
+    checkerFile = CheckerFile("<checker-file>")
+    testCase = TestCase(checkerFile, "TestMethod TestPass", 0)
+    return ParseCheckerAssertion(testCase, checkerString, TestAssertion.Variant.InOrder, 0)
+
+  def tryMatch(self, checkerString, c1String, varState={}):
+    return MatchLines(self.createTestAssertion(checkerString),
+                      ToUnicode(c1String),
+                      ImmutableDict(varState))
+
+  def assertMatches(self, checkerString, c1String, varState={}):
+    self.assertIsNotNone(self.tryMatch(checkerString, c1String, varState))
+
+  def assertDoesNotMatch(self, checkerString, c1String, varState={}):
+    self.assertIsNone(self.tryMatch(checkerString, c1String, varState))
+
+  def test_TextAndWhitespace(self):
+    self.assertMatches("foo", "foo")
+    self.assertMatches("foo", "  foo  ")
+    self.assertMatches("foo", "foo bar")
+    self.assertDoesNotMatch("foo", "XfooX")
+    self.assertDoesNotMatch("foo", "zoo")
+
+    self.assertMatches("foo bar", "foo   bar")
+    self.assertMatches("foo bar", "abc foo bar def")
+    self.assertMatches("foo bar", "foo foo bar bar")
+
+    self.assertMatches("foo bar", "foo X bar")
+    self.assertDoesNotMatch("foo bar", "foo Xbar")
+
+  def test_Pattern(self):
+    self.assertMatches("foo{{A|B}}bar", "fooAbar")
+    self.assertMatches("foo{{A|B}}bar", "fooBbar")
+    self.assertDoesNotMatch("foo{{A|B}}bar", "fooCbar")
+
+  def test_VariableReference(self):
+    self.assertMatches("foo<<X>>bar", "foobar", {"X": ""})
+    self.assertMatches("foo<<X>>bar", "fooAbar", {"X": "A"})
+    self.assertMatches("foo<<X>>bar", "fooBbar", {"X": "B"})
+    self.assertDoesNotMatch("foo<<X>>bar", "foobar", {"X": "A"})
+    self.assertDoesNotMatch("foo<<X>>bar", "foo bar", {"X": "A"})
+    with self.assertRaises(CheckerException):
+      self.tryMatch("foo<<X>>bar", "foobar", {})
+
+  def test_VariableDefinition(self):
+    self.assertMatches("foo<<X:A|B>>bar", "fooAbar")
+    self.assertMatches("foo<<X:A|B>>bar", "fooBbar")
+    self.assertDoesNotMatch("foo<<X:A|B>>bar", "fooCbar")
+
+    env = self.tryMatch("foo<<X:A.*B>>bar", "fooABbar", {})
+    self.assertEqual(env, {"X": "AB"})
+    env = self.tryMatch("foo<<X:A.*B>>bar", "fooAxxBbar", {})
+    self.assertEqual(env, {"X": "AxxB"})
+
+    self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooAbarAbaz")
+    self.assertMatches("foo<<X:A|B>>bar<<X>>baz", "fooBbarBbaz")
+    self.assertDoesNotMatch("foo<<X:A|B>>bar<<X>>baz", "fooAbarBbaz")
+
+  def test_NoVariableRedefinition(self):
+    with self.assertRaises(CheckerException):
+      self.tryMatch("<<X:...>><<X>><<X:...>><<X>>", "foofoobarbar")
+
+  def test_EnvNotChangedOnPartialMatch(self):
+    env = {"Y": "foo"}
+    self.assertDoesNotMatch("<<X:A>>bar", "Abaz", env)
+    self.assertFalse("X" in env.keys())
+
+  def test_VariableContentEscaped(self):
+    self.assertMatches("<<X:..>>foo<<X>>", ".*foo.*")
+    self.assertDoesNotMatch("<<X:..>>foo<<X>>", ".*fooAAAA")
+
+
+class MatchFiles_Test(unittest.TestCase):
+
+  def assertMatches(self, checkerString, c1String):
+    checkerString = \
+      """
+        /// CHECK-START: MyMethod MyPass
+      """ + checkerString
+    c1String = \
+      """
+        begin_compilation
+          name "MyMethod"
+          method "MyMethod"
+          date 1234
+        end_compilation
+        begin_cfg
+          name "MyPass"
+      """ + c1String + \
+      """
+        end_cfg
+      """
+    checkerFile = ParseCheckerStream("<test-file>", "CHECK", io.StringIO(ToUnicode(checkerString)))
+    c1File = ParseC1visualizerStream("<c1-file>", io.StringIO(ToUnicode(c1String)))
+    assert len(checkerFile.testCases) == 1
+    assert len(c1File.passes) == 1
+    MatchTestCase(checkerFile.testCases[0], c1File.passes[0])
+
+  def assertDoesNotMatch(self, checkerString, c1String):
+    with self.assertRaises(MatchFailedException):
+      self.assertMatches(checkerString, c1String)
+
+  def test_Text(self):
+    self.assertMatches("/// CHECK: foo bar", "foo bar")
+    self.assertDoesNotMatch("/// CHECK: foo bar", "abc def")
+
+  def test_Pattern(self):
+    self.assertMatches("/// CHECK: abc {{de.}}", "abc de#")
+    self.assertDoesNotMatch("/// CHECK: abc {{de.}}", "abc d#f")
+
+  def test_Variables(self):
+    self.assertMatches(
+    """
+      /// CHECK: foo<<X:.>>bar
+      /// CHECK: abc<<X>>def
+    """,
+    """
+      foo0bar
+      abc0def
+    """)
+    self.assertMatches(
+    """
+      /// CHECK: foo<<X:([0-9]+)>>bar
+      /// CHECK: abc<<X>>def
+      /// CHECK: ### <<X>> ###
+    """,
+    """
+      foo1234bar
+      abc1234def
+      ### 1234 ###
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK: foo<<X:([0-9]+)>>bar
+      /// CHECK: abc<<X>>def
+    """,
+    """
+      foo1234bar
+      abc1235def
+    """)
+
+  def test_WholeWordMustMatch(self):
+    self.assertMatches("/// CHECK: b{{.}}r", "abc bar def")
+    self.assertDoesNotMatch("/// CHECK: b{{.}}r", "abc Xbar def")
+    self.assertDoesNotMatch("/// CHECK: b{{.}}r", "abc barX def")
+    self.assertDoesNotMatch("/// CHECK: b{{.}}r", "abc b r def")
+
+  def test_InOrderAssertions(self):
+    self.assertMatches(
+    """
+      /// CHECK: foo
+      /// CHECK: bar
+    """,
+    """
+      foo
+      bar
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK: foo
+      /// CHECK: bar
+    """,
+    """
+      bar
+      foo
+    """)
+
+  def test_NextLineAssertions(self):
+    self.assertMatches(
+    """
+      /// CHECK:      foo
+      /// CHECK-NEXT: bar
+      /// CHECK-NEXT: abc
+      /// CHECK:      def
+    """,
+    """
+      foo
+      bar
+      abc
+      def
+    """)
+    self.assertMatches(
+    """
+      /// CHECK:      foo
+      /// CHECK-NEXT: bar
+      /// CHECK:      def
+    """,
+    """
+      foo
+      bar
+      abc
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK:      foo
+      /// CHECK-NEXT: bar
+    """,
+    """
+      foo
+      abc
+      bar
+    """)
+
+    self.assertDoesNotMatch(
+    """
+      /// CHECK:      foo
+      /// CHECK-NEXT: bar
+    """,
+    """
+      bar
+      foo
+      abc
+    """)
+
+  def test_DagAssertions(self):
+    self.assertMatches(
+    """
+      /// CHECK-DAG: foo
+      /// CHECK-DAG: bar
+    """,
+    """
+      foo
+      bar
+    """)
+    self.assertMatches(
+    """
+      /// CHECK-DAG: foo
+      /// CHECK-DAG: bar
+    """,
+    """
+      bar
+      foo
+    """)
+
+  def test_DagAssertionsScope(self):
+    self.assertMatches(
+    """
+      /// CHECK:     foo
+      /// CHECK-DAG: abc
+      /// CHECK-DAG: def
+      /// CHECK:     bar
+    """,
+    """
+      foo
+      def
+      abc
+      bar
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK:     foo
+      /// CHECK-DAG: abc
+      /// CHECK-DAG: def
+      /// CHECK:     bar
+    """,
+    """
+      foo
+      abc
+      bar
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK:     foo
+      /// CHECK-DAG: abc
+      /// CHECK-DAG: def
+      /// CHECK:     bar
+    """,
+    """
+      foo
+      def
+      bar
+      abc
+    """)
+
+  def test_NotAssertions(self):
+    self.assertMatches(
+    """
+      /// CHECK-NOT: foo
+    """,
+    """
+      abc
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK-NOT: foo
+    """,
+    """
+      abc foo
+      def
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK-NOT: foo
+      /// CHECK-NOT: bar
+    """,
+    """
+      abc
+      def bar
+    """)
+
+  def test_NotAssertionsScope(self):
+    self.assertMatches(
+    """
+      /// CHECK:     abc
+      /// CHECK-NOT: foo
+      /// CHECK:     def
+    """,
+    """
+      abc
+      def
+    """)
+    self.assertMatches(
+    """
+      /// CHECK:     abc
+      /// CHECK-NOT: foo
+      /// CHECK:     def
+    """,
+    """
+      abc
+      def
+      foo
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK:     abc
+      /// CHECK-NOT: foo
+      /// CHECK:     def
+    """,
+    """
+      abc
+      foo
+      def
+    """)
+
+  def test_LineOnlyMatchesOnce(self):
+    self.assertMatches(
+    """
+      /// CHECK-DAG: foo
+      /// CHECK-DAG: foo
+    """,
+    """
+      foo
+      abc
+      foo
+    """)
+    self.assertDoesNotMatch(
+    """
+      /// CHECK-DAG: foo
+      /// CHECK-DAG: foo
+    """,
+    """
+      foo
+      abc
+      bar
+    """)
diff --git a/tools/checker/run_unit_tests.py b/tools/checker/run_unit_tests.py
new file mode 100755
index 0000000..01708db
--- /dev/null
+++ b/tools/checker/run_unit_tests.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python2
+#
+# Copyright (C) 2014 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.
+
+from common.logger                 import Logger
+from file_format.c1visualizer.test import C1visualizerParser_Test
+from file_format.checker.test      import CheckerParser_PrefixTest, \
+                                          CheckerParser_RegexExpressionTest, \
+                                          CheckerParser_FileLayoutTest
+from match.test                    import MatchLines_Test, \
+                                          MatchFiles_Test
+
+import unittest
+
+if __name__ == '__main__':
+  Logger.Verbosity = Logger.Level.NoOutput
+  unittest.main(verbosity=2)
diff --git a/tools/checker_test.py b/tools/checker_test.py
deleted file mode 100755
index 667ca90..0000000
--- a/tools/checker_test.py
+++ /dev/null
@@ -1,474 +0,0 @@
-#!/usr/bin/env python2
-#
-# Copyright (C) 2014 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.
-
-# This is a test file which exercises all feautres supported by the domain-
-# specific markup language implemented by Checker.
-
-import checker
-import io
-import unittest
-
-# The parent type of exception expected to be thrown by Checker during tests.
-# It must be specific enough to not cover exceptions thrown due to actual flaws
-# in Checker.
-CheckerException = SystemExit
-
-
-class TestCheckFile_PrefixExtraction(unittest.TestCase):
-  def __tryParse(self, string):
-    checkFile = checker.CheckFile(None, [])
-    return checkFile._extractLine("CHECK", string)
-
-  def test_InvalidFormat(self):
-    self.assertIsNone(self.__tryParse("CHECK"))
-    self.assertIsNone(self.__tryParse(":CHECK"))
-    self.assertIsNone(self.__tryParse("CHECK:"))
-    self.assertIsNone(self.__tryParse("//CHECK"))
-    self.assertIsNone(self.__tryParse("#CHECK"))
-
-    self.assertIsNotNone(self.__tryParse("//CHECK:foo"))
-    self.assertIsNotNone(self.__tryParse("#CHECK:bar"))
-
-  def test_InvalidLabel(self):
-    self.assertIsNone(self.__tryParse("//ACHECK:foo"))
-    self.assertIsNone(self.__tryParse("#ACHECK:foo"))
-
-  def test_NotFirstOnTheLine(self):
-    self.assertIsNone(self.__tryParse("A// CHECK: foo"))
-    self.assertIsNone(self.__tryParse("A # CHECK: foo"))
-    self.assertIsNone(self.__tryParse("// // CHECK: foo"))
-    self.assertIsNone(self.__tryParse("# # CHECK: foo"))
-
-  def test_WhitespaceAgnostic(self):
-    self.assertIsNotNone(self.__tryParse("  //CHECK: foo"))
-    self.assertIsNotNone(self.__tryParse("//  CHECK: foo"))
-    self.assertIsNotNone(self.__tryParse("    //CHECK: foo"))
-    self.assertIsNotNone(self.__tryParse("//    CHECK: foo"))
-
-
-class TestCheckLine_Parse(unittest.TestCase):
-  def __getPartPattern(self, linePart):
-    if linePart.variant == checker.CheckElement.Variant.Separator:
-      return "\s+"
-    else:
-      return linePart.pattern
-
-  def __getRegex(self, checkLine):
-    return "".join(map(lambda x: "(" + self.__getPartPattern(x) + ")", checkLine.lineParts))
-
-  def __tryParse(self, string):
-    return checker.CheckLine(string)
-
-  def __parsesTo(self, string, expected):
-    self.assertEqual(expected, self.__getRegex(self.__tryParse(string)))
-
-  def __tryParseNot(self, string):
-    return checker.CheckLine(string, checker.CheckLine.Variant.Not)
-
-  def __parsesPattern(self, string, pattern):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertEqual(checker.CheckElement.Variant.Pattern, line.lineParts[0].variant)
-    self.assertEqual(pattern, line.lineParts[0].pattern)
-
-  def __parsesVarRef(self, string, name):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertEqual(checker.CheckElement.Variant.VarRef, line.lineParts[0].variant)
-    self.assertEqual(name, line.lineParts[0].name)
-
-  def __parsesVarDef(self, string, name, body):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertEqual(checker.CheckElement.Variant.VarDef, line.lineParts[0].variant)
-    self.assertEqual(name, line.lineParts[0].name)
-    self.assertEqual(body, line.lineParts[0].pattern)
-
-  def __doesNotParse(self, string, partType):
-    line = self.__tryParse(string)
-    self.assertEqual(1, len(line.lineParts))
-    self.assertNotEqual(partType, line.lineParts[0].variant)
-
-  # Test that individual parts of the line are recognized
-
-  def test_TextOnly(self):
-    self.__parsesTo("foo", "(foo)")
-    self.__parsesTo("  foo  ", "(foo)")
-    self.__parsesTo("f$o^o", "(f\$o\^o)")
-
-  def test_TextWithWhitespace(self):
-    self.__parsesTo("foo bar", "(foo)(\s+)(bar)")
-    self.__parsesTo("foo   bar", "(foo)(\s+)(bar)")
-
-  def test_RegexOnly(self):
-    self.__parsesPattern("{{a?b.c}}", "a?b.c")
-
-  def test_VarRefOnly(self):
-    self.__parsesVarRef("[[ABC]]", "ABC")
-
-  def test_VarDefOnly(self):
-    self.__parsesVarDef("[[ABC:a?b.c]]", "ABC", "a?b.c")
-
-  def test_TextWithRegex(self):
-    self.__parsesTo("foo{{abc}}bar", "(foo)(abc)(bar)")
-
-  def test_TextWithVar(self):
-    self.__parsesTo("foo[[ABC:abc]]bar", "(foo)(abc)(bar)")
-
-  def test_PlainWithRegexAndWhitespaces(self):
-    self.__parsesTo("foo {{abc}}bar", "(foo)(\s+)(abc)(bar)")
-    self.__parsesTo("foo{{abc}} bar", "(foo)(abc)(\s+)(bar)")
-    self.__parsesTo("foo {{abc}} bar", "(foo)(\s+)(abc)(\s+)(bar)")
-
-  def test_PlainWithVarAndWhitespaces(self):
-    self.__parsesTo("foo [[ABC:abc]]bar", "(foo)(\s+)(abc)(bar)")
-    self.__parsesTo("foo[[ABC:abc]] bar", "(foo)(abc)(\s+)(bar)")
-    self.__parsesTo("foo [[ABC:abc]] bar", "(foo)(\s+)(abc)(\s+)(bar)")
-
-  def test_AllKinds(self):
-    self.__parsesTo("foo [[ABC:abc]]{{def}}bar", "(foo)(\s+)(abc)(def)(bar)")
-    self.__parsesTo("foo[[ABC:abc]] {{def}}bar", "(foo)(abc)(\s+)(def)(bar)")
-    self.__parsesTo("foo [[ABC:abc]] {{def}} bar", "(foo)(\s+)(abc)(\s+)(def)(\s+)(bar)")
-
-  # Test that variables and patterns are parsed correctly
-
-  def test_ValidPattern(self):
-    self.__parsesPattern("{{abc}}", "abc")
-    self.__parsesPattern("{{a[b]c}}", "a[b]c")
-    self.__parsesPattern("{{(a{bc})}}", "(a{bc})")
-
-  def test_ValidRef(self):
-    self.__parsesVarRef("[[ABC]]", "ABC")
-    self.__parsesVarRef("[[A1BC2]]", "A1BC2")
-
-  def test_ValidDef(self):
-    self.__parsesVarDef("[[ABC:abc]]", "ABC", "abc")
-    self.__parsesVarDef("[[ABC:ab:c]]", "ABC", "ab:c")
-    self.__parsesVarDef("[[ABC:a[b]c]]", "ABC", "a[b]c")
-    self.__parsesVarDef("[[ABC:(a[bc])]]", "ABC", "(a[bc])")
-
-  def test_Empty(self):
-    self.__doesNotParse("{{}}", checker.CheckElement.Variant.Pattern)
-    self.__doesNotParse("[[]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[:]]", checker.CheckElement.Variant.VarDef)
-
-  def test_InvalidVarName(self):
-    self.__doesNotParse("[[0ABC]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[AB=C]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[ABC=]]", checker.CheckElement.Variant.VarRef)
-    self.__doesNotParse("[[0ABC:abc]]", checker.CheckElement.Variant.VarDef)
-    self.__doesNotParse("[[AB=C:abc]]", checker.CheckElement.Variant.VarDef)
-    self.__doesNotParse("[[ABC=:abc]]", checker.CheckElement.Variant.VarDef)
-
-  def test_BodyMatchNotGreedy(self):
-    self.__parsesTo("{{abc}}{{def}}", "(abc)(def)")
-    self.__parsesTo("[[ABC:abc]][[DEF:def]]", "(abc)(def)")
-
-  def test_NoVarDefsInNotChecks(self):
-    with self.assertRaises(CheckerException):
-      self.__tryParseNot("[[ABC:abc]]")
-
-class TestCheckLine_Match(unittest.TestCase):
-  def __matchSingle(self, checkString, outputString, varState={}):
-    checkLine = checker.CheckLine(checkString)
-    newVarState = checkLine.match(outputString, varState)
-    self.assertIsNotNone(newVarState)
-    return newVarState
-
-  def __notMatchSingle(self, checkString, outputString, varState={}):
-    checkLine = checker.CheckLine(checkString)
-    self.assertIsNone(checkLine.match(outputString, varState))
-
-  def test_TextAndWhitespace(self):
-    self.__matchSingle("foo", "foo")
-    self.__matchSingle("foo", "  foo  ")
-    self.__matchSingle("foo", "foo bar")
-    self.__notMatchSingle("foo", "XfooX")
-    self.__notMatchSingle("foo", "zoo")
-
-    self.__matchSingle("foo bar", "foo   bar")
-    self.__matchSingle("foo bar", "abc foo bar def")
-    self.__matchSingle("foo bar", "foo foo bar bar")
-
-    self.__matchSingle("foo bar", "foo X bar")
-    self.__notMatchSingle("foo bar", "foo Xbar")
-
-  def test_Pattern(self):
-    self.__matchSingle("foo{{A|B}}bar", "fooAbar")
-    self.__matchSingle("foo{{A|B}}bar", "fooBbar")
-    self.__notMatchSingle("foo{{A|B}}bar", "fooCbar")
-
-  def test_VariableReference(self):
-    self.__matchSingle("foo[[X]]bar", "foobar", {"X": ""})
-    self.__matchSingle("foo[[X]]bar", "fooAbar", {"X": "A"})
-    self.__matchSingle("foo[[X]]bar", "fooBbar", {"X": "B"})
-    self.__notMatchSingle("foo[[X]]bar", "foobar", {"X": "A"})
-    self.__notMatchSingle("foo[[X]]bar", "foo bar", {"X": "A"})
-    with self.assertRaises(CheckerException):
-      self.__matchSingle("foo[[X]]bar", "foobar", {})
-
-  def test_VariableDefinition(self):
-    self.__matchSingle("foo[[X:A|B]]bar", "fooAbar")
-    self.__matchSingle("foo[[X:A|B]]bar", "fooBbar")
-    self.__notMatchSingle("foo[[X:A|B]]bar", "fooCbar")
-
-    env = self.__matchSingle("foo[[X:A.*B]]bar", "fooABbar", {})
-    self.assertEqual(env, {"X": "AB"})
-    env = self.__matchSingle("foo[[X:A.*B]]bar", "fooAxxBbar", {})
-    self.assertEqual(env, {"X": "AxxB"})
-
-    self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarAbaz")
-    self.__matchSingle("foo[[X:A|B]]bar[[X]]baz", "fooBbarBbaz")
-    self.__notMatchSingle("foo[[X:A|B]]bar[[X]]baz", "fooAbarBbaz")
-
-  def test_NoVariableRedefinition(self):
-    with self.assertRaises(CheckerException):
-      self.__matchSingle("[[X:...]][[X]][[X:...]][[X]]", "foofoobarbar")
-
-  def test_EnvNotChangedOnPartialMatch(self):
-    env = {"Y": "foo"}
-    self.__notMatchSingle("[[X:A]]bar", "Abaz", env)
-    self.assertFalse("X" in env.keys())
-
-  def test_VariableContentEscaped(self):
-    self.__matchSingle("[[X:..]]foo[[X]]", ".*foo.*")
-    self.__notMatchSingle("[[X:..]]foo[[X]]", ".*fooAAAA")
-
-
-CheckVariant = checker.CheckLine.Variant
-
-def prepareSingleCheck(line):
-  if isinstance(line, str):
-    return checker.CheckLine(line)
-  else:
-    return checker.CheckLine(line[0], line[1])
-
-def prepareChecks(lines):
-  if isinstance(lines, str):
-    lines = lines.splitlines()
-  return list(map(lambda line: prepareSingleCheck(line), lines))
-
-
-class TestCheckGroup_Match(unittest.TestCase):
-  def __matchMulti(self, checkLines, outputString):
-    checkGroup = checker.CheckGroup("MyGroup", prepareChecks(checkLines))
-    outputGroup = checker.OutputGroup("MyGroup", outputString.splitlines())
-    return checkGroup.match(outputGroup)
-
-  def __notMatchMulti(self, checkString, outputString):
-    with self.assertRaises(CheckerException):
-      self.__matchMulti(checkString, outputString)
-
-  def test_TextAndPattern(self):
-    self.__matchMulti("""foo bar
-                         abc {{def}}""",
-                      """foo bar
-                         abc def""");
-    self.__matchMulti("""foo bar
-                         abc {{de.}}""",
-                      """=======
-                         foo bar
-                         =======
-                         abc de#
-                         =======""");
-    self.__notMatchMulti("""//XYZ: foo bar
-                            //XYZ: abc {{def}}""",
-                         """=======
-                            foo bar
-                            =======
-                            abc de#
-                            =======""");
-
-  def test_Variables(self):
-    self.__matchMulti("""foo[[X:.]]bar
-                         abc[[X]]def""",
-                      """foo bar
-                         abc def""");
-    self.__matchMulti("""foo[[X:([0-9]+)]]bar
-                         abc[[X]]def
-                         ### [[X]] ###""",
-                      """foo1234bar
-                         abc1234def
-                         ### 1234 ###""");
-
-  def test_Ordering(self):
-    self.__matchMulti([("foo", CheckVariant.InOrder),
-                       ("bar", CheckVariant.InOrder)],
-                      """foo
-                         bar""")
-    self.__notMatchMulti([("foo", CheckVariant.InOrder),
-                          ("bar", CheckVariant.InOrder)],
-                         """bar
-                            foo""")
-    self.__matchMulti([("abc", CheckVariant.DAG),
-                       ("def", CheckVariant.DAG)],
-                      """abc
-                         def""")
-    self.__matchMulti([("abc", CheckVariant.DAG),
-                       ("def", CheckVariant.DAG)],
-                      """def
-                         abc""")
-    self.__matchMulti([("foo", CheckVariant.InOrder),
-                       ("abc", CheckVariant.DAG),
-                       ("def", CheckVariant.DAG),
-                       ("bar", CheckVariant.InOrder)],
-                      """foo
-                         def
-                         abc
-                         bar""")
-    self.__notMatchMulti([("foo", CheckVariant.InOrder),
-                          ("abc", CheckVariant.DAG),
-                          ("def", CheckVariant.DAG),
-                          ("bar", CheckVariant.InOrder)],
-                         """foo
-                            abc
-                            bar""")
-    self.__notMatchMulti([("foo", CheckVariant.InOrder),
-                          ("abc", CheckVariant.DAG),
-                          ("def", CheckVariant.DAG),
-                          ("bar", CheckVariant.InOrder)],
-                         """foo
-                            def
-                            bar""")
-
-  def test_NotAssertions(self):
-    self.__matchMulti([("foo", CheckVariant.Not)],
-                      """abc
-                         def""")
-    self.__notMatchMulti([("foo", CheckVariant.Not)],
-                         """abc foo
-                            def""")
-    self.__notMatchMulti([("foo", CheckVariant.Not),
-                          ("bar", CheckVariant.Not)],
-                         """abc
-                            def bar""")
-
-  def test_LineOnlyMatchesOnce(self):
-    self.__matchMulti([("foo", CheckVariant.DAG),
-                       ("foo", CheckVariant.DAG)],
-                       """foo
-                          foo""")
-    self.__notMatchMulti([("foo", CheckVariant.DAG),
-                          ("foo", CheckVariant.DAG)],
-                          """foo
-                             bar""")
-
-class TestOutputFile_Parse(unittest.TestCase):
-  def __parsesTo(self, string, expected):
-    if isinstance(string, str):
-      string = unicode(string)
-    outputStream = io.StringIO(string)
-    return self.assertEqual(checker.OutputFile(outputStream).groups, expected)
-
-  def test_NoInput(self):
-    self.__parsesTo(None, [])
-    self.__parsesTo("", [])
-
-  def test_SingleGroup(self):
-    self.__parsesTo("""begin_compilation
-                         method "MyMethod"
-                       end_compilation
-                       begin_cfg
-                         name "pass1"
-                         foo
-                         bar
-                       end_cfg""",
-                    [ checker.OutputGroup("MyMethod pass1", [ "foo", "bar" ]) ])
-
-  def test_MultipleGroups(self):
-    self.__parsesTo("""begin_compilation
-                         name "xyz1"
-                         method "MyMethod1"
-                         date 1234
-                       end_compilation
-                       begin_cfg
-                         name "pass1"
-                         foo
-                         bar
-                       end_cfg
-                       begin_cfg
-                         name "pass2"
-                         abc
-                         def
-                       end_cfg""",
-                    [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
-                      checker.OutputGroup("MyMethod1 pass2", [ "abc", "def" ]) ])
-
-    self.__parsesTo("""begin_compilation
-                         name "xyz1"
-                         method "MyMethod1"
-                         date 1234
-                       end_compilation
-                       begin_cfg
-                         name "pass1"
-                         foo
-                         bar
-                       end_cfg
-                       begin_compilation
-                         name "xyz2"
-                         method "MyMethod2"
-                         date 5678
-                       end_compilation
-                       begin_cfg
-                         name "pass2"
-                         abc
-                         def
-                       end_cfg""",
-                    [ checker.OutputGroup("MyMethod1 pass1", [ "foo", "bar" ]),
-                      checker.OutputGroup("MyMethod2 pass2", [ "abc", "def" ]) ])
-
-class TestCheckFile_Parse(unittest.TestCase):
-  def __parsesTo(self, string, expected):
-    if isinstance(string, str):
-      string = unicode(string)
-    checkStream = io.StringIO(string)
-    return self.assertEqual(checker.CheckFile("CHECK", checkStream).groups, expected)
-
-  def test_NoInput(self):
-    self.__parsesTo(None, [])
-    self.__parsesTo("", [])
-
-  def test_SingleGroup(self):
-    self.__parsesTo("""// CHECK-START: Example Group
-                       // CHECK:  foo
-                       // CHECK:    bar""",
-                    [ checker.CheckGroup("Example Group", prepareChecks([ "foo", "bar" ])) ])
-
-  def test_MultipleGroups(self):
-    self.__parsesTo("""// CHECK-START: Example Group1
-                       // CHECK: foo
-                       // CHECK: bar
-                       // CHECK-START: Example Group2
-                       // CHECK: abc
-                       // CHECK: def""",
-                    [ checker.CheckGroup("Example Group1", prepareChecks([ "foo", "bar" ])),
-                      checker.CheckGroup("Example Group2", prepareChecks([ "abc", "def" ])) ])
-
-  def test_CheckVariants(self):
-    self.__parsesTo("""// CHECK-START: Example Group
-                       // CHECK:     foo
-                       // CHECK-NOT: bar
-                       // CHECK-DAG: abc
-                       // CHECK-DAG: def""",
-                    [ checker.CheckGroup("Example Group",
-                                         prepareChecks([ ("foo", CheckVariant.InOrder),
-                                                         ("bar", CheckVariant.Not),
-                                                         ("abc", CheckVariant.DAG),
-                                                         ("def", CheckVariant.DAG) ])) ])
-
-if __name__ == '__main__':
-  checker.Logger.Verbosity = checker.Logger.Level.NoOutput
-  unittest.main()
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index a387036..65c3fed 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -21,28 +21,35 @@
   name: "libcore.java.lang.SystemTest#testSystemProperties_mutable"
 },
 {
-  description: "Differences between vogar and cts",
+  description: "Differences between vogar and cts. Passes with --mode activity",
   result: EXEC_FAILED,
   modes: [device],
-  names: ["libcore.java.lang.OldSystemTest#test_getProperties",
-          "org.apache.harmony.tests.java.lang.Process2Test#test_getErrorStream",
-          "org.apache.harmony.tests.java.lang.ProcessTest#test_exitValue"]
+  names: ["libcore.java.lang.OldSystemTest#test_getProperties"]
 },
 {
-  description: "Failures needing investigation",
+  description: "Differences between vogar and cts. EACCESS when run with vogar.
+                Passes on host, passes with cts. Passes with vogar with su
+                (--invoke-with \"su root\"). Does not pass after setting chmod
+                777 all directories on path to socket (on device without su).",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.io.OsTest#testUnixDomainSockets_in_file_system"]
+},
+{
+  description: "Issue with incorrect device time (1970)",
   result: EXEC_FAILED,
   modes: [device],
   names: ["libcore.java.util.TimeZoneTest#testDisplayNames",
           "libcore.java.util.TimeZoneTest#test_useDaylightTime_Taiwan",
-          "libcore.java.util.TimeZoneTest#testAllDisplayNames",
-          "libcore.io.OsTest#testUnixDomainSockets_in_file_system",
-          "org.apache.harmony.luni.tests.java.net.URLConnectionTest#test_setReadTimeoutI",
-          "org.apache.harmony.tests.java.util.DateTest#test_Constructor",
-          "org.apache.harmony.tests.java.util.ScannerTest#test_Constructor_LReadableByteChannel",
-          "org.apache.harmony.tests.java.util.TimeZoneTest#test_hasSameRules_Ljava_util_TimeZone",
-          "org.apache.harmony.tests.java.text.ChoiceFormatTest#testEscapedPatternWithConsecutiveQuotes",
-          "org.apache.harmony.tests.java.text.ChoiceFormatTest#testToPatternWithInfinities",
-          "org.apache.harmony.tests.java.text.MessageFormatTest#test19011159"]
+          "org.apache.harmony.tests.java.util.TimeZoneTest#test_hasSameRules_Ljava_util_TimeZone"],
+  bug: 20879084
+},
+{
+  description: "Issue with incorrect device time (1970). Test assumes that DateTime.now()
+                is greater then a date in 1998.",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["org.apache.harmony.tests.java.util.DateTest#test_Constructor"]
 },
 {
   description: "Failing due to a locale problem on hammerhead.",
@@ -74,7 +81,8 @@
           "libcore.net.NetworkSecurityPolicyTest#testCleartextTrafficPolicyWithJarHttpURLConnection",
           "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest",
           "org.apache.harmony.luni.tests.internal.net.www.protocol.https.HttpsURLConnectionTest",
-          "org.apache.harmony.luni.tests.java.net.URLConnectionTest"
+          "org.apache.harmony.luni.tests.java.net.URLConnectionTest",
+          "org.apache.harmony.tests.java.util.ScannerTest#test_Constructor_LReadableByteChannel"
          ]
 },
 {
@@ -102,25 +110,12 @@
   bug: 18869265
 },
 {
-  description: "Test sometimes timeouts on volantis",
+  description: "Test sometimes timeouts on volantis, and on most modes in debug mode",
   result: EXEC_TIMEOUT,
-  modes_variants: [[device,X64]],
   names: ["libcore.java.lang.SystemTest#testArrayCopyConcurrentModification"],
   bug: 19165288
 },
 {
-  description: "Bug in libcore",
-  result: EXEC_FAILED,
-  names: ["libcore.javax.crypto.ECDHKeyAgreementTest#testInit_withUnsupportedPrivateKeyType"],
-  bug: 19730263
-},
-{
-  description: "Needs to be run as root",
-  result: EXEC_FAILED,
-  modes: [host],
-  names: ["libcore.io.OsTest#test_PacketSocketAddress"]
-},
-{
   description: "Needs kernel updates on host/device",
   result: EXEC_FAILED,
   names: ["libcore.io.OsTest#test_socketPing"]
@@ -130,5 +125,24 @@
   modes: [device],
   result: EXEC_FAILED,
   names: ["org.apache.harmony.tests.java.lang.ProcessManagerTest#testEnvironment"]
+},
+{
+  description: "Crypto failures",
+  result: EXEC_FAILED,
+  names: ["libcore.javax.crypto.CipherTest#testCipher_ShortBlock_Failure",
+          "libcore.javax.crypto.CipherTest#testCipher_Success"]
+},
+{
+  description: "Flake when running with libartd.so or interpreter",
+  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
 }
 ]
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 1dd443b..7135dba 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -21,11 +21,10 @@
 
 # Jar containing all the tests.
 test_jar=out/host/linux-x86/framework/apache-harmony-jdwp-tests-hostdex.jar
-junit_jar=out/host/linux-x86/framework/junit.jar
 
-if [ ! -f $test_jar -o ! -f $junit_jar ]; then
+if [ ! -f $test_jar ]; then
   echo "Before running, you must build jdwp tests and vogar:" \
-       "make junit apache-harmony-jdwp-tests-hostdex vogar vogar.jar"
+       "make apache-harmony-jdwp-tests-hostdex vogar vogar.jar"
   exit 1
 fi
 
@@ -40,6 +39,7 @@
 # image.
 vm_command="--vm-command=$art"
 image_compiler_option=""
+debug="no"
 
 while true; do
   if [[ "$1" == "--mode=host" ]]; then
@@ -54,12 +54,17 @@
     # Vogar knows which VM to use on host.
     vm_command=""
     # We only compile the image on the host. Note that not providing this option
-    # puts us below the adb command limit for vogar.
+    # for target testing puts us below the adb command limit for vogar.
     image_compiler_option="--vm-arg -Ximage-compiler-option --vm-arg --debuggable"
     shift
   elif [[ $1 == -Ximage:* ]]; then
     image="$1"
     shift
+  elif [[ $1 == "--debug" ]]; then
+    debug="yes"
+    # Remove the --debug from the arguments.
+    args=${args/$1}
+    shift
   elif [[ "$1" == "" ]]; then
     break
   else
@@ -67,9 +72,16 @@
   fi
 done
 
+vm_args="--vm-arg $image"
+if [[ $debug == "yes" ]]; then
+  art="$art -d"
+  art_debugee="$art_debugee -d"
+  vm_args="$vm_args --vm-arg -XXlib:libartd.so"
+fi
+
 # Run the tests using vogar.
 vogar $vm_command \
-      --vm-arg $image \
+      $vm_args \
       --verbose \
       $args \
       $device_dir \
@@ -80,7 +92,6 @@
       --vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \
       --vm-arg -Djpda.settings.debuggeeJavaPath="\"$art_debugee $image $debuggee_args\"" \
       --classpath $test_jar \
-      --classpath $junit_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/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index a19fd15..e28de09 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -19,16 +19,22 @@
   exit 1
 fi
 
-# Jar containing all the tests.
+# Jar containing jsr166 tests.
+jsr166_test_jar=out/target/common/obj/JAVA_LIBRARIES/jsr166-tests_intermediates/javalib.jar
+
+# Jar containing all the other tests.
 test_jar=out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/javalib.jar
 
+
 if [ ! -f $test_jar ]; then
-  echo "Before running, you must build core-tests and vogar: make core-tests vogar vogar.jar"
+  echo "Before running, you must build core-tests, jsr166-tests and vogar: \
+        make core-tests jsr166-tests vogar vogar.jar"
   exit 1
 fi
 
 # Packages that currently work correctly with the expectation files.
-working_packages=("libcore.icu"
+working_packages=("dalvik.system"
+                  "libcore.icu"
                   "libcore.io"
                   "libcore.java.lang"
                   "libcore.java.math"
@@ -54,9 +60,40 @@
                   "org.apache.harmony.tests.java.util"
                   "org.apache.harmony.tests.java.text"
                   "org.apache.harmony.tests.javax.security"
-                  "tests.java.lang.String")
+                  "tests.java.lang.String"
+                  "jsr166")
+
+vogar_args=$@
+while true; do
+  if [[ "$1" == "--mode=device" ]]; then
+    vogar_args="$vogar_args --device-dir=/data/local/tmp"
+    vogar_args="$vogar_args --vm-command=/data/local/tmp/system/bin/art"
+    vogar_args="$vogar_args --vm-arg -Ximage:/data/art-test/core-optimizing.art"
+    shift
+  elif [[ "$1" == "--mode=host" ]]; then
+    # We explicitly give a wrong path for the image, to ensure vogar
+    # will create a boot image with the default compiler. Note that
+    # giving an existing image on host does not work because of
+    # classpath/resources differences when compiling the boot image.
+    vogar_args="$vogar_args --vm-arg -Ximage:/non/existent"
+    shift
+  elif [[ "$1" == "--debug" ]]; then
+    # Remove the --debug from the arguments.
+    vogar_args=${vogar_args/$1}
+    vogar_args="$vogar_args --vm-arg -XXlib:libartd.so"
+    # Increase the timeout, as vogar cannot set individual test
+    # timeout when being asked to run packages, and some tests go above
+    # the default timeout.
+    vogar_args="$vogar_args --timeout 240"
+    shift
+  elif [[ "$1" == "" ]]; then
+    break
+  else
+    shift
+  fi
+done
 
 # Run the tests using vogar.
 echo "Running tests for the following test packages:"
 echo ${working_packages[@]} | tr " " "\n"
-vogar $@ --expectations art/tools/libcore_failures.txt --classpath $test_jar ${working_packages[@]}
+vogar $vogar_args --expectations art/tools/libcore_failures.txt --classpath $jsr166_test_jar --classpath $test_jar ${working_packages[@]}